WifiStateMachine.java revision e6574ec7b6b2e7a678da7f77bdaaf31463852b2f
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.wifi; 18 19import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; 20import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; 21import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; 22import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; 23import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; 24 25/** 26 * TODO: 27 * Deprecate WIFI_STATE_UNKNOWN 28 */ 29import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; 30import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; 31import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; 32import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; 33import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; 34 35import android.app.AlarmManager; 36import android.app.PendingIntent; 37import android.app.backup.IBackupManager; 38import android.bluetooth.BluetoothAdapter; 39import android.content.BroadcastReceiver; 40import android.content.Context; 41import android.content.Intent; 42import android.content.IntentFilter; 43import android.content.pm.PackageManager; 44import android.database.ContentObserver; 45import android.net.ConnectivityManager; 46import android.net.DhcpResults; 47import android.net.DhcpStateMachine; 48import android.net.InterfaceConfiguration; 49import android.net.LinkAddress; 50import android.net.LinkProperties; 51import android.net.NetworkAgent; 52import android.net.NetworkCapabilities; 53import android.net.NetworkFactory; 54import android.net.NetworkInfo; 55import android.net.NetworkInfo.DetailedState; 56import android.net.NetworkUtils; 57import android.net.RouteInfo; 58import android.net.TrafficStats; 59import android.net.wifi.*; 60import android.net.wifi.WpsResult.Status; 61import android.net.wifi.p2p.IWifiP2pManager; 62import android.net.wifi.passpoint.IWifiPasspointManager; 63import android.os.BatteryStats; 64import android.os.Bundle; 65import android.os.IBinder; 66import android.os.INetworkManagementService; 67import android.os.Looper; 68import android.os.Message; 69import android.os.Messenger; 70import android.os.PowerManager; 71import android.os.Process; 72import android.os.RemoteException; 73import android.os.ServiceManager; 74import android.os.SystemClock; 75import android.os.SystemProperties; 76import android.os.UserHandle; 77import android.os.WorkSource; 78import android.provider.Settings; 79import android.telephony.TelephonyManager; 80import android.util.LruCache; 81import android.text.TextUtils; 82import android.util.Log; 83 84import com.android.internal.R; 85import com.android.internal.app.IBatteryStats; 86import com.android.internal.util.AsyncChannel; 87import com.android.internal.util.Protocol; 88import com.android.internal.util.State; 89import com.android.internal.util.StateMachine; 90import com.android.server.net.BaseNetworkObserver; 91import com.android.server.net.NetlinkTracker; 92 93import com.android.server.wifi.p2p.WifiP2pServiceImpl; 94import com.android.server.wifi.passpoint.WifiPasspointServiceImpl; 95 96import java.io.FileDescriptor; 97import java.io.PrintWriter; 98import java.net.InetAddress; 99import java.util.*; 100import java.util.concurrent.atomic.AtomicInteger; 101import java.util.concurrent.atomic.AtomicBoolean; 102import java.util.regex.Pattern; 103import java.io.FileReader; 104import java.io.BufferedReader; 105import java.io.FileNotFoundException; 106import java.io.IOException; 107import java.net.Inet4Address; 108 109/** 110 * Track the state of Wifi connectivity. All event handling is done here, 111 * and all changes in connectivity state are initiated here. 112 * 113 * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p 114 * In the current implementation, we support concurrent wifi p2p and wifi operation. 115 * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService 116 * handles p2p operation. 117 * 118 * @hide 119 */ 120public class WifiStateMachine extends StateMachine { 121 122 private static final String NETWORKTYPE = "WIFI"; 123 private static boolean DBG = false; 124 private static boolean VDBG = false; 125 private static boolean mLogMessages = false; 126 127 private static final int ONE_HOUR_MILLI = 1000 * 60 * 60; 128 129 /* temporary debug flag - best network selection development */ 130 private static boolean PDBG = false; 131 132 /* debug flag, indicating if handling of ASSOCIATION_REJECT ended up blacklisting 133 * the corresponding BSSID. 134 */ 135 private boolean didBlackListBSSID = false; 136 137 /** 138 * Log with error attribute 139 * 140 * @param s is string log 141 */ 142 protected void loge(String s) { 143 Log.e(getName(), s); 144 } 145 protected void log(String s) {; 146 Log.e(getName(), s); 147 } 148 149 private WifiMonitor mWifiMonitor; 150 private WifiNative mWifiNative; 151 private WifiConfigStore mWifiConfigStore; 152 private WifiAutoJoinController mWifiAutoJoinController; 153 private INetworkManagementService mNwService; 154 private ConnectivityManager mCm; 155 156 private final boolean mP2pSupported; 157 private final AtomicBoolean mP2pConnected = new AtomicBoolean(false); 158 private boolean mTemporarilyDisconnectWifi = false; 159 private final String mPrimaryDeviceType; 160 161 /* Scan results handling */ 162 private List<ScanResult> mScanResults = new ArrayList<ScanResult>(); 163 private static final Pattern scanResultPattern = Pattern.compile("\t+"); 164 private static final int SCAN_RESULT_CACHE_SIZE = 80; 165 private final LruCache<String, ScanResult> mScanResultCache; 166 167 /* Batch scan results */ 168 private final List<BatchedScanResult> mBatchedScanResults = 169 new ArrayList<BatchedScanResult>(); 170 private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE; 171 private int mExpectedBatchedScans = 0; 172 private long mBatchedScanMinPollTime = 0; 173 174 private boolean mScreenOn = false; 175 176 /* Chipset supports background scan */ 177 private final boolean mBackgroundScanSupported; 178 179 private String mInterfaceName; 180 /* Tethering interface could be separate from wlan interface */ 181 private String mTetherInterfaceName; 182 183 private int mLastSignalLevel = -1; 184 private String mLastBssid; 185 private int mLastNetworkId; // The network Id we successfully joined 186 private boolean linkDebouncing = false; 187 188 // Testing various network disconnect cases by sending lots of spurious 189 // disconnect to supplicant 190 private boolean testNetworkDisconnect = false; 191 192 private boolean mEnableRssiPolling = false; 193 private boolean mEnableBackgroundScan = false; 194 private int mRssiPollToken = 0; 195 /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE 196 * In CONNECT_MODE, the STA can scan and connect to an access point 197 * In SCAN_ONLY_MODE, the STA can only scan for access points 198 * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off 199 */ 200 private int mOperationalMode = CONNECT_MODE; 201 private boolean mIsScanOngoing = false; 202 private boolean mIsFullScanOngoing = false; 203 private final Queue<Message> mBufferedScanMsg = new LinkedList<Message>(); 204 private WorkSource mScanWorkSource = null; 205 private static final int UNKNOWN_SCAN_SOURCE = -1; 206 private static final int SCAN_ALARM_SOURCE = -2; 207 208 private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10; 209 private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings"; 210 private static final String CUSTOMIZED_SCAN_WORKSOURCE = "customized_scan_worksource"; 211 private static final String BATCHED_SETTING = "batched_settings"; 212 private static final String BATCHED_WORKSOURCE = "batched_worksource"; 213 214 /* Tracks if state machine has received any screen state change broadcast yet. 215 * We can miss one of these at boot. 216 */ 217 private AtomicBoolean mScreenBroadcastReceived = new AtomicBoolean(false); 218 219 private boolean mBluetoothConnectionActive = false; 220 221 private PowerManager.WakeLock mSuspendWakeLock; 222 223 /** 224 * Interval in milliseconds between polling for RSSI 225 * and linkspeed information 226 */ 227 private static final int POLL_RSSI_INTERVAL_MSECS = 3000; 228 229 /** 230 * Interval in milliseconds between receiving a disconnect event 231 * while connected to a good AP, and handling the disconnect proper 232 */ 233 private static final int LINK_FLAPPING_DEBOUNCE_MSEC = 7000; 234 235 /** 236 * Delay between supplicant restarts upon failure to establish connection 237 */ 238 private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000; 239 240 /** 241 * Number of times we attempt to restart supplicant 242 */ 243 private static final int SUPPLICANT_RESTART_TRIES = 5; 244 245 private int mSupplicantRestartCount = 0; 246 /* Tracks sequence number on stop failure message */ 247 private int mSupplicantStopFailureToken = 0; 248 249 /** 250 * Tether state change notification time out 251 */ 252 private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000; 253 254 /* Tracks sequence number on a tether notification time out */ 255 private int mTetherToken = 0; 256 257 /** 258 * Driver start time out. 259 */ 260 private static final int DRIVER_START_TIME_OUT_MSECS = 10000; 261 262 /* Tracks sequence number on a driver time out */ 263 private int mDriverStartToken = 0; 264 265 /** 266 * The link properties of the wifi interface. 267 * Do not modify this directly; use updateLinkProperties instead. 268 */ 269 private LinkProperties mLinkProperties; 270 271 /* Tracks sequence number on a periodic scan message */ 272 private int mPeriodicScanToken = 0; 273 274 // Wakelock held during wifi start/stop and driver load/unload 275 private PowerManager.WakeLock mWakeLock; 276 277 private Context mContext; 278 279 private final Object mDhcpResultsLock = new Object(); 280 private DhcpResults mDhcpResults; 281 private WifiInfo mWifiInfo; 282 private NetworkInfo mNetworkInfo; 283 private NetworkCapabilities mNetworkCapabilities; 284 private SupplicantStateTracker mSupplicantStateTracker; 285 private DhcpStateMachine mDhcpStateMachine; 286 private boolean mDhcpActive = false; 287 288 private int mWifiLinkLayerStatsSupported = 4; 289 290 private final AtomicInteger mCountryCodeSequence = new AtomicInteger(); 291 292 //whether the state machine goes thru the Disconnecting->Disconnected->ObtainingIpAddress 293 private int mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 294 295 private String mTargetRoamBSSID = "any"; 296 297 private WifiConfiguration targetWificonfiguration = null; 298 299 boolean isRoaming() { 300 return mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_ROAMING 301 || mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_EXTENDED_ROAMING; 302 } 303 304 public void autoRoamSetBSSID(int netId, String bssid) { 305 autoRoamSetBSSID(mWifiConfigStore.getWifiConfiguration(netId), bssid); 306 } 307 308 public void autoRoamSetBSSID(WifiConfiguration config, String bssid) { 309 mTargetRoamBSSID = "any"; 310 if (config == null || bssid == null) 311 return; 312 if (config.bssidOwnerUid == 0 || config.bssidOwnerUid == Process.WIFI_UID) { 313 if (VDBG) { 314 loge("autoRoamSetBSSID uid=" + Long.toString(config.bssidOwnerUid) 315 + " bssid=" + bssid 316 + " key=" + config.configKey()); 317 } 318 config.bssidOwnerUid = Process.WIFI_UID; 319 config.BSSID = bssid; 320 mTargetRoamBSSID = bssid; 321 } 322 } 323 324 /** 325 * Subset of link properties coming from netlink. 326 * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers 327 * and domains obtained from router advertisements (RFC 6106). 328 */ 329 private NetlinkTracker mNetlinkTracker; 330 331 private AlarmManager mAlarmManager; 332 private PendingIntent mScanIntent; 333 private PendingIntent mDriverStopIntent; 334 private PendingIntent mBatchedScanIntervalIntent; 335 336 /* Tracks current frequency mode */ 337 private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO); 338 339 /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */ 340 private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true); 341 342 // Channel for sending replies. 343 private AsyncChannel mReplyChannel = new AsyncChannel(); 344 345 private WifiP2pServiceImpl mWifiP2pServiceImpl; 346 private WifiPasspointServiceImpl mPasspointServiceImpl; 347 348 // Used to initiate a connection with WifiP2pService 349 private AsyncChannel mWifiP2pChannel; 350 private AsyncChannel mWifiApConfigChannel; 351 352 private WifiNetworkFactory mNetworkFactory; 353 private WifiNetworkAgent mNetworkAgent; 354 355 // Keep track of various statistics, for retrieval by System Apps, i.e. under @SystemApi 356 // We should really persist that into the networkHistory.txt file, and read it back when 357 // WifiStateMachine starts up 358 private WifiConnectionStatistics mWifiConnectionStatistics = new WifiConnectionStatistics(); 359 360 // Used to filter out requests we couldn't possibly satisfy. 361 private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities(); 362 363 /* The base for wifi message types */ 364 static final int BASE = Protocol.BASE_WIFI; 365 /* Start the supplicant */ 366 static final int CMD_START_SUPPLICANT = BASE + 11; 367 /* Stop the supplicant */ 368 static final int CMD_STOP_SUPPLICANT = BASE + 12; 369 /* Start the driver */ 370 static final int CMD_START_DRIVER = BASE + 13; 371 /* Stop the driver */ 372 static final int CMD_STOP_DRIVER = BASE + 14; 373 /* Indicates Static IP succeeded */ 374 static final int CMD_STATIC_IP_SUCCESS = BASE + 15; 375 /* Indicates Static IP failed */ 376 static final int CMD_STATIC_IP_FAILURE = BASE + 16; 377 /* Indicates supplicant stop failed */ 378 static final int CMD_STOP_SUPPLICANT_FAILED = BASE + 17; 379 /* Delayed stop to avoid shutting down driver too quick*/ 380 static final int CMD_DELAYED_STOP_DRIVER = BASE + 18; 381 /* A delayed message sent to start driver when it fail to come up */ 382 static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19; 383 384 /* Start the soft access point */ 385 static final int CMD_START_AP = BASE + 21; 386 /* Indicates soft ap start succeeded */ 387 static final int CMD_START_AP_SUCCESS = BASE + 22; 388 /* Indicates soft ap start failed */ 389 static final int CMD_START_AP_FAILURE = BASE + 23; 390 /* Stop the soft access point */ 391 static final int CMD_STOP_AP = BASE + 24; 392 /* Set the soft access point configuration */ 393 static final int CMD_SET_AP_CONFIG = BASE + 25; 394 /* Soft access point configuration set completed */ 395 static final int CMD_SET_AP_CONFIG_COMPLETED = BASE + 26; 396 /* Request the soft access point configuration */ 397 static final int CMD_REQUEST_AP_CONFIG = BASE + 27; 398 /* Response to access point configuration request */ 399 static final int CMD_RESPONSE_AP_CONFIG = BASE + 28; 400 /* Invoked when getting a tether state change notification */ 401 static final int CMD_TETHER_STATE_CHANGE = BASE + 29; 402 /* A delayed message sent to indicate tether state change failed to arrive */ 403 static final int CMD_TETHER_NOTIFICATION_TIMED_OUT = BASE + 30; 404 405 static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31; 406 407 /* Supplicant commands */ 408 /* Is supplicant alive ? */ 409 static final int CMD_PING_SUPPLICANT = BASE + 51; 410 /* Add/update a network configuration */ 411 static final int CMD_ADD_OR_UPDATE_NETWORK = BASE + 52; 412 /* Delete a network */ 413 static final int CMD_REMOVE_NETWORK = BASE + 53; 414 /* Enable a network. The device will attempt a connection to the given network. */ 415 static final int CMD_ENABLE_NETWORK = BASE + 54; 416 /* Enable all networks */ 417 static final int CMD_ENABLE_ALL_NETWORKS = BASE + 55; 418 /* Blacklist network. De-prioritizes the given BSSID for connection. */ 419 static final int CMD_BLACKLIST_NETWORK = BASE + 56; 420 /* Clear the blacklist network list */ 421 static final int CMD_CLEAR_BLACKLIST = BASE + 57; 422 /* Save configuration */ 423 static final int CMD_SAVE_CONFIG = BASE + 58; 424 /* Get configured networks */ 425 static final int CMD_GET_CONFIGURED_NETWORKS = BASE + 59; 426 /* Get available frequencies */ 427 static final int CMD_GET_CAPABILITY_FREQ = BASE + 60; 428 /* Get adaptors */ 429 static final int CMD_GET_ADAPTORS = BASE + 61; 430 /* Get configured networks with real preSharedKey */ 431 static final int CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS = BASE + 62; 432 433 /* Supplicant commands after driver start*/ 434 /* Initiate a scan */ 435 static final int CMD_START_SCAN = BASE + 71; 436 /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */ 437 static final int CMD_SET_OPERATIONAL_MODE = BASE + 72; 438 /* Disconnect from a network */ 439 static final int CMD_DISCONNECT = BASE + 73; 440 /* Reconnect to a network */ 441 static final int CMD_RECONNECT = BASE + 74; 442 /* Reassociate to a network */ 443 static final int CMD_REASSOCIATE = BASE + 75; 444 /* Get Connection Statistis */ 445 static final int CMD_GET_CONNECTION_STATISTICS = BASE + 76; 446 447 /* Controls suspend mode optimizations 448 * 449 * When high perf mode is enabled, suspend mode optimizations are disabled 450 * 451 * When high perf mode is disabled, suspend mode optimizations are enabled 452 * 453 * Suspend mode optimizations include: 454 * - packet filtering 455 * - turn off roaming 456 * - DTIM wake up settings 457 */ 458 static final int CMD_SET_HIGH_PERF_MODE = BASE + 77; 459 /* Set the country code */ 460 static final int CMD_SET_COUNTRY_CODE = BASE + 80; 461 /* Enables RSSI poll */ 462 static final int CMD_ENABLE_RSSI_POLL = BASE + 82; 463 /* RSSI poll */ 464 static final int CMD_RSSI_POLL = BASE + 83; 465 /* Set up packet filtering */ 466 static final int CMD_START_PACKET_FILTERING = BASE + 84; 467 /* Clear packet filter */ 468 static final int CMD_STOP_PACKET_FILTERING = BASE + 85; 469 /* Enable suspend mode optimizations in the driver */ 470 static final int CMD_SET_SUSPEND_OPT_ENABLED = BASE + 86; 471 /* Delayed NETWORK_DISCONNECT */ 472 static final int CMD_DELAYED_NETWORK_DISCONNECT = BASE + 87; 473 /* When there are no saved networks, we do a periodic scan to notify user of 474 * an open network */ 475 static final int CMD_NO_NETWORKS_PERIODIC_SCAN = BASE + 88; 476 /* Test network Disconnection NETWORK_DISCONNECT */ 477 static final int CMD_TEST_NETWORK_DISCONNECT = BASE + 89; 478 private int testNetworkDisconnectCounter = 0; 479 480 /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */ 481 static final int MULTICAST_V6 = 1; 482 static final int MULTICAST_V4 = 0; 483 484 /* Set the frequency band */ 485 static final int CMD_SET_FREQUENCY_BAND = BASE + 90; 486 /* Enable background scan for configured networks */ 487 static final int CMD_ENABLE_BACKGROUND_SCAN = BASE + 91; 488 /* Enable TDLS on a specific MAC address */ 489 static final int CMD_ENABLE_TDLS = BASE + 92; 490 /* Enable TDLS on a specific MAC address */ 491 static final int CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER = BASE + 93; 492 493 /** 494 * Make this timer 32 seconds, which is about the normal DHCP timeout. 495 * In no valid case, the WiFiStateMachine should remain stuck in ObtainingIpAddress 496 * for more than 30 seconds. 497 */ 498 static final int OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC = 32000; 499 500 int obtainingIpWatchdogCount = 0; 501 /* Commands from/to the SupplicantStateTracker */ 502 /* Reset the supplicant state tracker */ 503 static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111; 504 505 /* P2p commands */ 506 /* We are ok with no response here since we wont do much with it anyway */ 507 public static final int CMD_ENABLE_P2P = BASE + 131; 508 /* In order to shut down supplicant cleanly, we wait till p2p has 509 * been disabled */ 510 public static final int CMD_DISABLE_P2P_REQ = BASE + 132; 511 public static final int CMD_DISABLE_P2P_RSP = BASE + 133; 512 513 public static final int CMD_BOOT_COMPLETED = BASE + 134; 514 515 /* change the batch scan settings. 516 * arg1 = responsible UID 517 * arg2 = csph (channel scans per hour) 518 * obj = bundle with the new settings and the optional worksource 519 */ 520 public static final int CMD_SET_BATCHED_SCAN = BASE + 135; 521 public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136; 522 public static final int CMD_POLL_BATCHED_SCAN = BASE + 137; 523 524 /* We now have a valid IP configuration. */ 525 static final int CMD_IP_CONFIGURATION_SUCCESSFUL = BASE + 138; 526 /* We no longer have a valid IP configuration. */ 527 static final int CMD_IP_CONFIGURATION_LOST = BASE + 139; 528 /* Link configuration (IP address, DNS, ...) changes notified via netlink */ 529 static final int CMD_UPDATE_LINKPROPERTIES = BASE + 140; 530 531 /* Supplicant is trying to associate to a given BSSID */ 532 static final int CMD_TARGET_BSSID = BASE + 141; 533 534 /* Reload all networks and reconnect */ 535 static final int CMD_RELOAD_TLS_AND_RECONNECT = BASE + 142; 536 537 static final int CMD_AUTO_CONNECT = BASE + 143; 538 539 static final int CMD_UNWANTED_NETWORK = BASE + 144; 540 541 static final int CMD_AUTO_ROAM = BASE + 145; 542 543 544 /* Wifi state machine modes of operation */ 545 /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ 546 public static final int CONNECT_MODE = 1; 547 /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */ 548 public static final int SCAN_ONLY_MODE = 2; 549 /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */ 550 public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3; 551 552 private static final int SUCCESS = 1; 553 private static final int FAILURE = -1; 554 555 /* Tracks if suspend optimizations need to be disabled by DHCP, 556 * screen or due to high perf mode. 557 * When any of them needs to disable it, we keep the suspend optimizations 558 * disabled 559 */ 560 private int mSuspendOptNeedsDisabled = 0; 561 562 private static final int SUSPEND_DUE_TO_DHCP = 1; 563 private static final int SUSPEND_DUE_TO_HIGH_PERF = 1<<1; 564 private static final int SUSPEND_DUE_TO_SCREEN = 1<<2; 565 566 /* Tracks if user has enabled suspend optimizations through settings */ 567 private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true); 568 569 /** 570 * Default framework scan interval in milliseconds. This is used in the scenario in which 571 * wifi chipset does not support background scanning to set up a 572 * periodic wake up scan so that the device can connect to a new access 573 * point on the move. {@link Settings.Global#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can 574 * override this. 575 */ 576 private final int mDefaultFrameworkScanIntervalMs; 577 578 /** 579 * Connected state framework scan interval in milliseconds. 580 * This is used for extended roaming, when screen is lit. 581 */ 582 private int mConnectedScanPeriodMs = 10000; 583 private int mDisconnectedScanPeriodMs = 10000; 584 585 /** 586 * Supplicant scan interval in milliseconds. 587 * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or 588 * from the default config if the setting is not set 589 */ 590 private long mSupplicantScanIntervalMs; 591 592 /** 593 * timeStamp of last full band scan we perfoemed for autojoin while connected with screen lit 594 */ 595 private long lastFullBandConnectedTimeMilli; 596 597 /** 598 * time interval to the next full band scan we will perform for 599 * autojoin while connected with screen lit 600 */ 601 private long fullBandConnectedTimeIntervalMilli; 602 603 /** 604 * max time interval to the next full band scan we will perform for 605 * autojoin while connected with screen lit 606 * Max time is 5 minutes 607 */ 608 private static final long maxFullBandConnectedTimeIntervalMilli = 1000 * 60 * 5; 609 610 /** 611 * Minimum time interval between enabling all networks. 612 * A device can end up repeatedly connecting to a bad network on screen on/off toggle 613 * due to enabling every time. We add a threshold to avoid this. 614 */ 615 private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */ 616 private long mLastEnableAllNetworksTime; 617 618 /** 619 * Starting and shutting down driver too quick causes problems leading to driver 620 * being in a bad state. Delay driver stop. 621 */ 622 private final int mDriverStopDelayMs; 623 private int mDelayedStopCounter; 624 private boolean mInDelayedStop = false; 625 626 // sometimes telephony gives us this data before boot is complete and we can't store it 627 // until after, so the write is deferred 628 private volatile String mPersistedCountryCode; 629 630 // Supplicant doesn't like setting the same country code multiple times (it may drop 631 // currently connected network), so we save the country code here to avoid redundency 632 private String mLastSetCountryCode; 633 634 /* Default parent state */ 635 private State mDefaultState = new DefaultState(); 636 /* Temporary initial state */ 637 private State mInitialState = new InitialState(); 638 /* Driver loaded, waiting for supplicant to start */ 639 private State mSupplicantStartingState = new SupplicantStartingState(); 640 /* Driver loaded and supplicant ready */ 641 private State mSupplicantStartedState = new SupplicantStartedState(); 642 /* Waiting for supplicant to stop and monitor to exit */ 643 private State mSupplicantStoppingState = new SupplicantStoppingState(); 644 /* Driver start issued, waiting for completed event */ 645 private State mDriverStartingState = new DriverStartingState(); 646 /* Driver started */ 647 private State mDriverStartedState = new DriverStartedState(); 648 /* Wait until p2p is disabled 649 * This is a special state which is entered right after we exit out of DriverStartedState 650 * before transitioning to another state. 651 */ 652 private State mWaitForP2pDisableState = new WaitForP2pDisableState(); 653 /* Driver stopping */ 654 private State mDriverStoppingState = new DriverStoppingState(); 655 /* Driver stopped */ 656 private State mDriverStoppedState = new DriverStoppedState(); 657 /* Scan for networks, no connection will be established */ 658 private State mScanModeState = new ScanModeState(); 659 /* Connecting to an access point */ 660 private State mConnectModeState = new ConnectModeState(); 661 /* Connected at 802.11 (L2) level */ 662 private State mL2ConnectedState = new L2ConnectedState(); 663 /* fetching IP after connection to access point (assoc+auth complete) */ 664 private State mObtainingIpState = new ObtainingIpState(); 665 /* Waiting for link quality verification to be complete */ 666 private State mVerifyingLinkState = new VerifyingLinkState(); 667 /* Connected with IP addr */ 668 private State mConnectedState = new ConnectedState(); 669 /* Roaming */ 670 private State mRoamingState = new RoamingState(); 671 /* disconnect issued, waiting for network disconnect confirmation */ 672 private State mDisconnectingState = new DisconnectingState(); 673 /* Network is not connected, supplicant assoc+auth is not complete */ 674 private State mDisconnectedState = new DisconnectedState(); 675 /* Waiting for WPS to be completed*/ 676 private State mWpsRunningState = new WpsRunningState(); 677 678 /* Soft ap is starting up */ 679 private State mSoftApStartingState = new SoftApStartingState(); 680 /* Soft ap is running */ 681 private State mSoftApStartedState = new SoftApStartedState(); 682 /* Soft ap is running and we are waiting for tether notification */ 683 private State mTetheringState = new TetheringState(); 684 /* Soft ap is running and we are tethered through connectivity service */ 685 private State mTetheredState = new TetheredState(); 686 /* Waiting for untether confirmation before stopping soft Ap */ 687 private State mUntetheringState = new UntetheringState(); 688 689 private class TetherStateChange { 690 ArrayList<String> available; 691 ArrayList<String> active; 692 TetherStateChange(ArrayList<String> av, ArrayList<String> ac) { 693 available = av; 694 active = ac; 695 } 696 } 697 698 public static class SimAuthRequestData { 699 int networkId; 700 int protocol; 701 String ssid; 702 String[] challenges; 703 } 704 705 public static class SimAuthResponseData { 706 int id; 707 String Kc1; 708 String SRES1; 709 String Kc2; 710 String SRES2; 711 String Kc3; 712 String SRES3; 713 } 714 715 /** 716 * One of {@link WifiManager#WIFI_STATE_DISABLED}, 717 * {@link WifiManager#WIFI_STATE_DISABLING}, 718 * {@link WifiManager#WIFI_STATE_ENABLED}, 719 * {@link WifiManager#WIFI_STATE_ENABLING}, 720 * {@link WifiManager#WIFI_STATE_UNKNOWN} 721 * 722 */ 723 private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED); 724 725 /** 726 * One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 727 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 728 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 729 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 730 * {@link WifiManager#WIFI_AP_STATE_FAILED} 731 * 732 */ 733 private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED); 734 735 private static final int SCAN_REQUEST = 0; 736 private static final String ACTION_START_SCAN = 737 "com.android.server.WifiManager.action.START_SCAN"; 738 739 private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter"; 740 private static final int DRIVER_STOP_REQUEST = 0; 741 private static final String ACTION_DELAYED_DRIVER_STOP = 742 "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP"; 743 744 private static final String ACTION_REFRESH_BATCHED_SCAN = 745 "com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN"; 746 /** 747 * Keep track of whether WIFI is running. 748 */ 749 private boolean mIsRunning = false; 750 751 /** 752 * Keep track of whether we last told the battery stats we had started. 753 */ 754 private boolean mReportedRunning = false; 755 756 /** 757 * Most recently set source of starting WIFI. 758 */ 759 private final WorkSource mRunningWifiUids = new WorkSource(); 760 761 /** 762 * The last reported UIDs that were responsible for starting WIFI. 763 */ 764 private final WorkSource mLastRunningWifiUids = new WorkSource(); 765 766 private final IBatteryStats mBatteryStats; 767 768 private BatchedScanSettings mBatchedScanSettings = null; 769 770 /** 771 * Track the worksource/cost of the current settings and track what's been noted 772 * to the battery stats, so we can mark the end of the previous when changing. 773 */ 774 private WorkSource mBatchedScanWorkSource = null; 775 private int mBatchedScanCsph = 0; 776 private WorkSource mNotedBatchedScanWorkSource = null; 777 private int mNotedBatchedScanCsph = 0; 778 779 private AtomicBoolean mFrameworkAutoJoin = new AtomicBoolean(true); //enable by default 780 781 public WifiStateMachine(Context context, String wlanInterface, 782 WifiTrafficPoller trafficPoller){ 783 super("WifiStateMachine"); 784 mContext = context; 785 mInterfaceName = wlanInterface; 786 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); 787 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 788 BatteryStats.SERVICE_NAME)); 789 790 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 791 mNwService = INetworkManagementService.Stub.asInterface(b); 792 793 mP2pSupported = mContext.getPackageManager().hasSystemFeature( 794 PackageManager.FEATURE_WIFI_DIRECT); 795 796 mWifiNative = new WifiNative(mInterfaceName); 797 mWifiConfigStore = new WifiConfigStore(context, mWifiNative); 798 mWifiAutoJoinController = new WifiAutoJoinController(context, this, 799 mWifiConfigStore, mWifiConnectionStatistics, mWifiNative); 800 mWifiMonitor = new WifiMonitor(this, mWifiNative); 801 mWifiInfo = new WifiInfo(); 802 mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, 803 getHandler()); 804 mLinkProperties = new LinkProperties(); 805 806 IBinder s1 = ServiceManager.getService(Context.WIFI_P2P_SERVICE); 807 mWifiP2pServiceImpl = (WifiP2pServiceImpl)IWifiP2pManager.Stub.asInterface(s1); 808 809 IBinder s2 = ServiceManager.getService(Context.WIFI_PASSPOINT_SERVICE); 810 mPasspointServiceImpl = 811 (WifiPasspointServiceImpl)IWifiPasspointManager.Stub.asInterface(s2); 812 813 mNetworkInfo.setIsAvailable(false); 814 mLastBssid = null; 815 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 816 mLastSignalLevel = -1; 817 818 mNetlinkTracker = new NetlinkTracker(mInterfaceName, new NetlinkTracker.Callback() { 819 public void update() { 820 sendMessage(CMD_UPDATE_LINKPROPERTIES); 821 } 822 }); 823 try { 824 mNwService.registerObserver(mNetlinkTracker); 825 } catch (RemoteException e) { 826 loge("Couldn't register netlink tracker: " + e.toString()); 827 } 828 829 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 830 Intent scanIntent = new Intent(ACTION_START_SCAN, null); 831 mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0); 832 833 Intent batchedIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null); 834 mBatchedScanIntervalIntent = PendingIntent.getBroadcast(mContext, 0, batchedIntent, 0); 835 836 mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger( 837 R.integer.config_wifi_framework_scan_interval); 838 839 mDriverStopDelayMs = mContext.getResources().getInteger( 840 R.integer.config_wifi_driver_stop_delay); 841 842 mBackgroundScanSupported = mContext.getResources().getBoolean( 843 R.bool.config_wifi_background_scan_support); 844 845 mPrimaryDeviceType = mContext.getResources().getString( 846 R.string.config_wifi_p2p_device_type); 847 848 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 849 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 850 851 mFrameworkAutoJoin.set(Settings.Global.getInt(mContext.getContentResolver(), 852 Settings.Global.WIFI_ENHANCED_AUTO_JOIN, 1) == 1); 853 854 mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); 855 mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 856 mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 857 mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024); 858 mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024); 859 // TODO - needs to be a bit more dynamic 860 mNetworkCapabilities = new NetworkCapabilities(mNetworkCapabilitiesFilter); 861 862 mContext.registerReceiver( 863 new BroadcastReceiver() { 864 @Override 865 public void onReceive(Context context, Intent intent) { 866 ArrayList<String> available = intent.getStringArrayListExtra( 867 ConnectivityManager.EXTRA_AVAILABLE_TETHER); 868 ArrayList<String> active = intent.getStringArrayListExtra( 869 ConnectivityManager.EXTRA_ACTIVE_TETHER); 870 sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active)); 871 } 872 },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); 873 874 mContext.registerReceiver( 875 new BroadcastReceiver() { 876 @Override 877 public void onReceive(Context context, Intent intent) { 878 startScan(SCAN_ALARM_SOURCE, null, null); 879 if (VDBG) 880 loge("WiFiStateMachine SCAN ALARM"); 881 } 882 }, 883 new IntentFilter(ACTION_START_SCAN)); 884 885 IntentFilter filter = new IntentFilter(); 886 filter.addAction(Intent.ACTION_SCREEN_ON); 887 filter.addAction(Intent.ACTION_SCREEN_OFF); 888 filter.addAction(ACTION_REFRESH_BATCHED_SCAN); 889 mContext.registerReceiver( 890 new BroadcastReceiver() { 891 @Override 892 public void onReceive(Context context, Intent intent) { 893 String action = intent.getAction(); 894 895 if (action.equals(Intent.ACTION_SCREEN_ON)) { 896 handleScreenStateChanged(true); 897 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 898 handleScreenStateChanged(false); 899 } else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) { 900 startNextBatchedScanAsync(); 901 } 902 } 903 }, filter); 904 905 mContext.registerReceiver( 906 new BroadcastReceiver() { 907 @Override 908 public void onReceive(Context context, Intent intent) { 909 int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0); 910 sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0); 911 } 912 }, 913 new IntentFilter(ACTION_DELAYED_DRIVER_STOP)); 914 915 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 916 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false, 917 new ContentObserver(getHandler()) { 918 @Override 919 public void onChange(boolean selfChange) { 920 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 921 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 922 } 923 }); 924 925 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 926 Settings.Global.WIFI_ENHANCED_AUTO_JOIN), false, 927 new ContentObserver(getHandler()) { 928 @Override 929 public void onChange(boolean selfChange) { 930 mFrameworkAutoJoin.set(Settings.Global.getInt(mContext.getContentResolver(), 931 Settings.Global.WIFI_ENHANCED_AUTO_JOIN, 0) == 1); 932 } 933 }); 934 935 mContext.registerReceiver( 936 new BroadcastReceiver() { 937 @Override 938 public void onReceive(Context context, Intent intent) { 939 sendMessage(CMD_BOOT_COMPLETED); 940 } 941 }, 942 new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); 943 944 mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE); 945 946 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 947 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName()); 948 949 mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend"); 950 mSuspendWakeLock.setReferenceCounted(false); 951 952 addState(mDefaultState); 953 addState(mInitialState, mDefaultState); 954 addState(mSupplicantStartingState, mDefaultState); 955 addState(mSupplicantStartedState, mDefaultState); 956 addState(mDriverStartingState, mSupplicantStartedState); 957 addState(mDriverStartedState, mSupplicantStartedState); 958 addState(mScanModeState, mDriverStartedState); 959 addState(mConnectModeState, mDriverStartedState); 960 addState(mL2ConnectedState, mConnectModeState); 961 addState(mObtainingIpState, mL2ConnectedState); 962 addState(mVerifyingLinkState, mL2ConnectedState); 963 addState(mConnectedState, mL2ConnectedState); 964 addState(mRoamingState, mL2ConnectedState); 965 addState(mDisconnectingState, mConnectModeState); 966 addState(mDisconnectedState, mConnectModeState); 967 addState(mWpsRunningState, mConnectModeState); 968 addState(mWaitForP2pDisableState, mSupplicantStartedState); 969 addState(mDriverStoppingState, mSupplicantStartedState); 970 addState(mDriverStoppedState, mSupplicantStartedState); 971 addState(mSupplicantStoppingState, mDefaultState); 972 addState(mSoftApStartingState, mDefaultState); 973 addState(mSoftApStartedState, mDefaultState); 974 addState(mTetheringState, mSoftApStartedState); 975 addState(mTetheredState, mSoftApStartedState); 976 addState(mUntetheringState, mSoftApStartedState); 977 978 setInitialState(mInitialState); 979 980 setLogRecSize(5000); 981 setLogOnlyTransitions(false); 982 if (VDBG) setDbg(true); 983 984 //start the state machine 985 start(); 986 987 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 988 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 989 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 990 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 991 } 992 993 private int mVerboseLoggingLevel = 0; 994 995 int getVerboseLoggingLevel() { 996 return mVerboseLoggingLevel; 997 } 998 999 void enableVerboseLogging(int verbose) { 1000 mVerboseLoggingLevel = verbose; 1001 if (verbose > 0) { 1002 DBG = true; 1003 VDBG = true; 1004 PDBG = true; 1005 mLogMessages = true; 1006 mWifiNative.setSupplicantLogLevel("DEBUG"); 1007 } else { 1008 DBG = false; 1009 VDBG = false; 1010 PDBG = false; 1011 mLogMessages = false; 1012 mWifiNative.setSupplicantLogLevel("INFO"); 1013 } 1014 mWifiAutoJoinController.enableVerboseLogging(verbose); 1015 mWifiMonitor.enableVerboseLogging(verbose); 1016 mWifiNative.enableVerboseLogging(verbose); 1017 mWifiConfigStore.enableVerboseLogging(verbose); 1018 mSupplicantStateTracker.enableVerboseLogging(verbose); 1019 } 1020 1021 private int mAggressiveHandover = 0; 1022 1023 int getAggressiveHandover() { 1024 return mAggressiveHandover; 1025 } 1026 1027 void enableAggressiveHandover(int enabled) { 1028 mAggressiveHandover = enabled; 1029 } 1030 1031 private int mAllowScansWithTraffic = 0; 1032 1033 public void setAllowScansWithTraffic(int enabled) { 1034 mAllowScansWithTraffic = enabled; 1035 } 1036 1037 public int getAllowScansWithTraffic() { 1038 return mAllowScansWithTraffic; 1039 } 1040 1041 /* 1042 * 1043 * Framework scan control 1044 */ 1045 1046 private boolean mAlarmEnabled = false; 1047 /* This is set from the overlay config file or from a secure setting. 1048 * A value of 0 disables scanning in the framework. 1049 */ 1050 private long mFrameworkScanIntervalMs = 10000; 1051 1052 private long mCurrentScanAlarmMs = 10000; 1053 private void setScanAlarm(boolean enabled) { 1054 if (PDBG) { 1055 loge("setScanAlarm " + enabled + " period " + mCurrentScanAlarmMs); 1056 } 1057 if (mCurrentScanAlarmMs <= 0) enabled = false; 1058 if (enabled == mAlarmEnabled) return; 1059 if (enabled) { 1060 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 1061 System.currentTimeMillis() + mCurrentScanAlarmMs, 1062 mCurrentScanAlarmMs, 1063 mScanIntent); 1064 mAlarmEnabled = true; 1065 } else { 1066 mAlarmManager.cancel(mScanIntent); 1067 mAlarmEnabled = false; 1068 } 1069 } 1070 1071 /********************************************************* 1072 * Methods exposed for public use 1073 ********************************************************/ 1074 1075 public Messenger getMessenger() { 1076 return new Messenger(getHandler()); 1077 } 1078 1079 public WifiMonitor getWifiMonitor() { 1080 return mWifiMonitor; 1081 } 1082 1083 /** 1084 * TODO: doc 1085 */ 1086 public boolean syncPingSupplicant(AsyncChannel channel) { 1087 Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT); 1088 boolean result = (resultMsg.arg1 != FAILURE); 1089 resultMsg.recycle(); 1090 return result; 1091 } 1092 1093 public List<WifiChannel> syncGetChannelList(AsyncChannel channel) { 1094 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CAPABILITY_FREQ); 1095 List<WifiChannel> list = null; 1096 if (resultMsg.obj != null) { 1097 list = new ArrayList<WifiChannel>(); 1098 String freqs = (String) resultMsg.obj; 1099 String[] lines = freqs.split("\n"); 1100 for (String line : lines) 1101 if (line.contains("MHz")) { 1102 // line format: " 52 = 5260 MHz (NO_IBSS) (DFS)" 1103 WifiChannel c = new WifiChannel(); 1104 String[] prop = line.split(" "); 1105 if (prop.length < 5) continue; 1106 try { 1107 c.channelNum = Integer.parseInt(prop[1]); 1108 c.freqMHz = Integer.parseInt(prop[3]); 1109 } catch (NumberFormatException e) { } 1110 c.isDFS = line.contains("(DFS)"); 1111 list.add(c); 1112 } else if (line.contains("Mode[B] Channels:")) { 1113 // B channels are the same as G channels, skipped 1114 break; 1115 } 1116 } 1117 resultMsg.recycle(); 1118 return (list != null && list.size() > 0) ? list : null; 1119 } 1120 1121 1122 /** 1123 * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is 1124 * given to callingUid. 1125 * 1126 * @param callingUid The uid initiating the wifi scan. Blame will be given here unless 1127 * workSource is specified. 1128 * @param workSource If not null, blame is given to workSource. 1129 * @param settings Scan settings, see {@link ScanSettings}. 1130 */ 1131 public void startScan(int callingUid, ScanSettings settings, WorkSource workSource) { 1132 Bundle bundle = new Bundle(); 1133 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings); 1134 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1135 sendMessage(CMD_START_SCAN, callingUid, 0, bundle); 1136 } 1137 1138 /** 1139 * start or stop batched scanning using the given settings 1140 */ 1141 public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph, 1142 WorkSource workSource) { 1143 Bundle bundle = new Bundle(); 1144 bundle.putParcelable(BATCHED_SETTING, settings); 1145 bundle.putParcelable(BATCHED_WORKSOURCE, workSource); 1146 sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle); 1147 } 1148 1149 public List<BatchedScanResult> syncGetBatchedScanResultsList() { 1150 synchronized (mBatchedScanResults) { 1151 List<BatchedScanResult> batchedScanList = 1152 new ArrayList<BatchedScanResult>(mBatchedScanResults.size()); 1153 for(BatchedScanResult result: mBatchedScanResults) { 1154 batchedScanList.add(new BatchedScanResult(result)); 1155 } 1156 return batchedScanList; 1157 } 1158 } 1159 1160 public void requestBatchedScanPoll() { 1161 sendMessage(CMD_POLL_BATCHED_SCAN); 1162 } 1163 1164 private void startBatchedScan() { 1165 if (mBatchedScanSettings == null) return; 1166 1167 if (mDhcpActive) { 1168 if (DBG) log("not starting Batched Scans due to DHCP"); 1169 return; 1170 } 1171 1172 // first grab any existing data 1173 retrieveBatchedScanData(); 1174 1175 if (PDBG) loge("try starting Batched Scans due to DHCP"); 1176 1177 1178 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1179 1180 String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings); 1181 try { 1182 mExpectedBatchedScans = Integer.parseInt(scansExpected); 1183 setNextBatchedAlarm(mExpectedBatchedScans); 1184 if (mExpectedBatchedScans > 0) noteBatchedScanStart(); 1185 } catch (NumberFormatException e) { 1186 stopBatchedScan(); 1187 loge("Exception parsing WifiNative.setBatchedScanSettings response " + e); 1188 } 1189 } 1190 1191 // called from BroadcastListener 1192 private void startNextBatchedScanAsync() { 1193 sendMessage(CMD_START_NEXT_BATCHED_SCAN); 1194 } 1195 1196 private void startNextBatchedScan() { 1197 // first grab any existing data 1198 retrieveBatchedScanData(); 1199 1200 setNextBatchedAlarm(mExpectedBatchedScans); 1201 } 1202 1203 private void handleBatchedScanPollRequest() { 1204 if (DBG) { 1205 log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" + 1206 mBatchedScanMinPollTime + " , mBatchedScanSettings=" + 1207 mBatchedScanSettings); 1208 } 1209 // if there is no appropriate PollTime that's because we either aren't 1210 // batching or we've already set a time for a poll request 1211 if (mBatchedScanMinPollTime == 0) return; 1212 if (mBatchedScanSettings == null) return; 1213 1214 long now = System.currentTimeMillis(); 1215 1216 if (now > mBatchedScanMinPollTime) { 1217 // do the poll and reset our timers 1218 startNextBatchedScan(); 1219 } else { 1220 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime, 1221 mBatchedScanIntervalIntent); 1222 mBatchedScanMinPollTime = 0; 1223 } 1224 } 1225 1226 // return true if new/different 1227 private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) { 1228 BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING); 1229 WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE); 1230 1231 if (DBG) { 1232 log("set batched scan to " + settings + " for uid=" + responsibleUid + 1233 ", worksource=" + responsibleWorkSource); 1234 } 1235 if (settings != null) { 1236 if (settings.equals(mBatchedScanSettings)) return false; 1237 } else { 1238 if (mBatchedScanSettings == null) return false; 1239 } 1240 mBatchedScanSettings = settings; 1241 if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid); 1242 mBatchedScanWorkSource = responsibleWorkSource; 1243 mBatchedScanCsph = csph; 1244 return true; 1245 } 1246 1247 private void stopBatchedScan() { 1248 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1249 retrieveBatchedScanData(); 1250 mWifiNative.setBatchedScanSettings(null); 1251 noteBatchedScanStop(); 1252 } 1253 1254 private void setNextBatchedAlarm(int scansExpected) { 1255 1256 if (mBatchedScanSettings == null || scansExpected < 1) return; 1257 1258 mBatchedScanMinPollTime = System.currentTimeMillis() + 1259 mBatchedScanSettings.scanIntervalSec * 1000; 1260 1261 if (mBatchedScanSettings.maxScansPerBatch < scansExpected) { 1262 scansExpected = mBatchedScanSettings.maxScansPerBatch; 1263 } 1264 1265 int secToFull = mBatchedScanSettings.scanIntervalSec; 1266 secToFull *= scansExpected; 1267 1268 int debugPeriod = SystemProperties.getInt("wifi.batchedScan.pollPeriod", 0); 1269 if (debugPeriod > 0) secToFull = debugPeriod; 1270 1271 // set the alarm to do the next poll. We set it a little short as we'd rather 1272 // wake up wearly than miss a scan due to buffer overflow 1273 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 1274 + ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000), 1275 mBatchedScanIntervalIntent); 1276 } 1277 1278 /** 1279 * Start reading new scan data 1280 * Data comes in as: 1281 * "scancount=5\n" 1282 * "nextcount=5\n" 1283 * "apcount=3\n" 1284 * "trunc\n" (optional) 1285 * "bssid=...\n" 1286 * "ssid=...\n" 1287 * "freq=...\n" (in Mhz) 1288 * "level=...\n" 1289 * "dist=...\n" (in cm) 1290 * "distsd=...\n" (standard deviation, in cm) 1291 * "====" 1292 * "bssid=...\n" 1293 * etc 1294 * "====" 1295 * "bssid=...\n" 1296 * etc 1297 * "%%%%" 1298 * "apcount=2\n" 1299 * "bssid=...\n" 1300 * etc 1301 * "%%%% 1302 * etc 1303 * "----" 1304 */ 1305 private final static boolean DEBUG_PARSE = false; 1306 private void retrieveBatchedScanData() { 1307 String rawData = mWifiNative.getBatchedScanResults(); 1308 if (DEBUG_PARSE) log("rawData = " + rawData); 1309 mBatchedScanMinPollTime = 0; 1310 if (rawData == null || rawData.equalsIgnoreCase("OK")) { 1311 loge("Unexpected BatchedScanResults :" + rawData); 1312 return; 1313 } 1314 1315 int scanCount = 0; 1316 final String END_OF_BATCHES = "----"; 1317 final String SCANCOUNT = "scancount="; 1318 final String TRUNCATED = "trunc"; 1319 final String AGE = "age="; 1320 final String DIST = "dist="; 1321 final String DISTSD = "distSd="; 1322 1323 String splitData[] = rawData.split("\n"); 1324 int n = 0; 1325 if (splitData[n].startsWith(SCANCOUNT)) { 1326 try { 1327 scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length())); 1328 } catch (NumberFormatException e) { 1329 loge("scancount parseInt Exception from " + splitData[n]); 1330 } 1331 } else log("scancount not found"); 1332 if (scanCount == 0) { 1333 loge("scanCount==0 - aborting"); 1334 return; 1335 } 1336 1337 final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION); 1338 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1339 1340 synchronized (mBatchedScanResults) { 1341 mBatchedScanResults.clear(); 1342 BatchedScanResult batchedScanResult = new BatchedScanResult(); 1343 1344 String bssid = null; 1345 WifiSsid wifiSsid = null; 1346 int level = 0; 1347 int freq = 0; 1348 int dist, distSd; 1349 long tsf = 0; 1350 dist = distSd = ScanResult.UNSPECIFIED; 1351 final long now = SystemClock.elapsedRealtime(); 1352 final int bssidStrLen = BSSID_STR.length(); 1353 1354 while (true) { 1355 while (n < splitData.length) { 1356 if (DEBUG_PARSE) logd("parsing " + splitData[n]); 1357 if (splitData[n].equals(END_OF_BATCHES)) { 1358 if (n+1 != splitData.length) { 1359 loge("didn't consume " + (splitData.length-n)); 1360 } 1361 if (mBatchedScanResults.size() > 0) { 1362 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1363 } 1364 logd("retrieveBatchedScanResults X"); 1365 return; 1366 } 1367 if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) { 1368 if (bssid != null) { 1369 batchedScanResult.scanResults.add(new ScanResult( 1370 wifiSsid, bssid, "", level, freq, tsf, dist, distSd)); 1371 wifiSsid = null; 1372 bssid = null; 1373 level = 0; 1374 freq = 0; 1375 tsf = 0; 1376 dist = distSd = ScanResult.UNSPECIFIED; 1377 } 1378 if (splitData[n].equals(END_STR)) { 1379 if (batchedScanResult.scanResults.size() != 0) { 1380 mBatchedScanResults.add(batchedScanResult); 1381 batchedScanResult = new BatchedScanResult(); 1382 } else { 1383 logd("Found empty batch"); 1384 } 1385 } 1386 } else if (splitData[n].equals(TRUNCATED)) { 1387 batchedScanResult.truncated = true; 1388 } else if (splitData[n].startsWith(BSSID_STR)) { 1389 bssid = new String(splitData[n].getBytes(), bssidStrLen, 1390 splitData[n].length() - bssidStrLen); 1391 } else if (splitData[n].startsWith(FREQ_STR)) { 1392 try { 1393 freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length())); 1394 } catch (NumberFormatException e) { 1395 loge("Invalid freqency: " + splitData[n]); 1396 freq = 0; 1397 } 1398 } else if (splitData[n].startsWith(AGE)) { 1399 try { 1400 tsf = now - Long.parseLong(splitData[n].substring(AGE.length())); 1401 tsf *= 1000; // convert mS -> uS 1402 } catch (NumberFormatException e) { 1403 loge("Invalid timestamp: " + splitData[n]); 1404 tsf = 0; 1405 } 1406 } else if (splitData[n].startsWith(SSID_STR)) { 1407 wifiSsid = WifiSsid.createFromAsciiEncoded( 1408 splitData[n].substring(SSID_STR.length())); 1409 } else if (splitData[n].startsWith(LEVEL_STR)) { 1410 try { 1411 level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length())); 1412 if (level > 0) level -= 256; 1413 } catch (NumberFormatException e) { 1414 loge("Invalid level: " + splitData[n]); 1415 level = 0; 1416 } 1417 } else if (splitData[n].startsWith(DIST)) { 1418 try { 1419 dist = Integer.parseInt(splitData[n].substring(DIST.length())); 1420 } catch (NumberFormatException e) { 1421 loge("Invalid distance: " + splitData[n]); 1422 dist = ScanResult.UNSPECIFIED; 1423 } 1424 } else if (splitData[n].startsWith(DISTSD)) { 1425 try { 1426 distSd = Integer.parseInt(splitData[n].substring(DISTSD.length())); 1427 } catch (NumberFormatException e) { 1428 loge("Invalid distanceSd: " + splitData[n]); 1429 distSd = ScanResult.UNSPECIFIED; 1430 } 1431 } else { 1432 loge("Unable to parse batched scan result line: " + splitData[n]); 1433 } 1434 n++; 1435 } 1436 rawData = mWifiNative.getBatchedScanResults(); 1437 if (DEBUG_PARSE) log("reading more data:\n" + rawData); 1438 if (rawData == null) { 1439 loge("Unexpected null BatchedScanResults"); 1440 return; 1441 } 1442 splitData = rawData.split("\n"); 1443 if (splitData.length == 0 || splitData[0].equals("ok")) { 1444 loge("batch scan results just ended!"); 1445 if (mBatchedScanResults.size() > 0) { 1446 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1447 } 1448 return; 1449 } 1450 n = 0; 1451 } 1452 } 1453 } 1454 1455 //keeping track of scan requests 1456 private long lastStartScanTimeStamp = 0; 1457 private long lastScanDuration = 0; 1458 //last connect attempt is used to prevent scan requests: 1459 // - for a period of 10 seconds after attempting to connect 1460 private long lastConnectAttempt = 0; 1461 private String lastScanFreqs = null; 1462 1463 //TODO: this is used only to track connection attempts, however the link state and packet per 1464 //TODO: second logic should be folded into that 1465 private boolean isScanAllowed() { 1466 long now = System.currentTimeMillis(); 1467 if (lastConnectAttempt != 0 && (now - lastConnectAttempt) < 10000) { 1468 return false; 1469 } 1470 return true; 1471 } 1472 1473 // If workSource is not null, blame is given to it, otherwise blame is given to callingUid. 1474 private void noteScanStart(int callingUid, WorkSource workSource) { 1475 long now = System.currentTimeMillis(); 1476 lastStartScanTimeStamp = now; 1477 lastScanDuration = 0; 1478 if (DBG) { 1479 String ts = String.format("[%,d ms]", now); 1480 if (workSource != null) { 1481 loge(ts + " noteScanStart" + workSource.toString() 1482 + " uid " + Integer.toString(callingUid)); 1483 } else { 1484 loge(ts + " noteScanstart no scan source"); 1485 } 1486 } 1487 if (mScanWorkSource == null && ((callingUid != UNKNOWN_SCAN_SOURCE 1488 && callingUid != SCAN_ALARM_SOURCE) 1489 || workSource != null)) { 1490 mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid); 1491 try { 1492 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource); 1493 } catch (RemoteException e) { 1494 log(e.toString()); 1495 } 1496 } 1497 } 1498 1499 private void noteScanEnd() { 1500 long now = System.currentTimeMillis(); 1501 if (lastStartScanTimeStamp != 0) { 1502 lastScanDuration = now - lastStartScanTimeStamp; 1503 } 1504 lastStartScanTimeStamp = 0; 1505 if (DBG) { 1506 String ts = String.format("[%,d ms]", now); 1507 1508 if (mScanWorkSource != null) 1509 loge(ts + " noteScanEnd " + mScanWorkSource.toString()); 1510 else 1511 loge(ts + " noteScanEnd no scan source"); 1512 } 1513 if (mScanWorkSource != null) { 1514 try { 1515 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource); 1516 } catch (RemoteException e) { 1517 log(e.toString()); 1518 } finally { 1519 mScanWorkSource = null; 1520 } 1521 } 1522 } 1523 1524 private void noteBatchedScanStart() { 1525 if (PDBG) loge("noteBatchedScanstart()"); 1526 // note the end of a previous scan set 1527 if (mNotedBatchedScanWorkSource != null && 1528 (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false || 1529 mNotedBatchedScanCsph != mBatchedScanCsph)) { 1530 try { 1531 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1532 } catch (RemoteException e) { 1533 log(e.toString()); 1534 } finally { 1535 mNotedBatchedScanWorkSource = null; 1536 mNotedBatchedScanCsph = 0; 1537 } 1538 } 1539 // note the start of the new 1540 try { 1541 mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource, 1542 mBatchedScanCsph); 1543 mNotedBatchedScanWorkSource = mBatchedScanWorkSource; 1544 mNotedBatchedScanCsph = mBatchedScanCsph; 1545 } catch (RemoteException e) { 1546 log(e.toString()); 1547 } 1548 } 1549 1550 private void noteBatchedScanStop() { 1551 if (PDBG) loge("noteBatchedScanstop()"); 1552 1553 if (mNotedBatchedScanWorkSource != null) { 1554 try { 1555 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1556 } catch (RemoteException e) { 1557 log(e.toString()); 1558 } finally { 1559 mNotedBatchedScanWorkSource = null; 1560 mNotedBatchedScanCsph = 0; 1561 } 1562 } 1563 } 1564 1565 private void handleScanRequest(int type, Message message) { 1566 // unbundle parameters 1567 Bundle bundle = (Bundle) message.obj; 1568 ScanSettings settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING); 1569 WorkSource workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE); 1570 1571 // parse scan settings 1572 String freqs = null; 1573 if (settings != null && settings.channelSet != null) { 1574 StringBuilder sb = new StringBuilder(); 1575 boolean first = true; 1576 for (WifiChannel channel : settings.channelSet) { 1577 if (!first) sb.append(','); else first = false; 1578 sb.append(channel.freqMHz); 1579 } 1580 freqs = sb.toString(); 1581 } 1582 1583 // call wifi native to start the scan 1584 if (startScanNative(type, freqs)) { 1585 // only count battery consumption if scan request is accepted 1586 noteScanStart(message.arg1, workSource); 1587 // a full scan covers everything, clearing scan request buffer 1588 if (freqs == null) 1589 mBufferedScanMsg.clear(); 1590 return; 1591 } 1592 1593 // if reach here, scan request is rejected 1594 1595 if (!mIsScanOngoing) { 1596 // if rejection is NOT due to ongoing scan (e.g. bad scan parameters), 1597 // discard this request and pop up the next one 1598 if (mBufferedScanMsg.size() > 0) 1599 sendMessage(mBufferedScanMsg.remove()); 1600 } else if (!mIsFullScanOngoing) { 1601 // if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan, 1602 // buffer the scan request to make sure specified channels will be scanned eventually 1603 if (freqs == null) 1604 mBufferedScanMsg.clear(); 1605 if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) { 1606 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, 0, bundle); 1607 mBufferedScanMsg.add(msg); 1608 } else { 1609 // if too many requests in buffer, combine them into a single full scan 1610 bundle = new Bundle(); 1611 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null); 1612 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1613 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, 0, bundle); 1614 mBufferedScanMsg.clear(); 1615 mBufferedScanMsg.add(msg); 1616 } 1617 } 1618 } 1619 1620 1621 /** return true iff scan request is accepted */ 1622 private boolean startScanNative(int type, String freqs) { 1623 if (mWifiNative.scan(type, freqs)) { 1624 mIsScanOngoing = true; 1625 mIsFullScanOngoing = (freqs == null); 1626 lastScanFreqs = freqs; 1627 return true; 1628 } 1629 return false; 1630 } 1631 1632 /** 1633 * TODO: doc 1634 */ 1635 public void setSupplicantRunning(boolean enable) { 1636 if (enable) { 1637 sendMessage(CMD_START_SUPPLICANT); 1638 } else { 1639 sendMessage(CMD_STOP_SUPPLICANT); 1640 } 1641 } 1642 1643 /** 1644 * TODO: doc 1645 */ 1646 public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) { 1647 if (enable) { 1648 sendMessage(CMD_START_AP, wifiConfig); 1649 } else { 1650 sendMessage(CMD_STOP_AP); 1651 } 1652 } 1653 1654 public void setWifiApConfiguration(WifiConfiguration config) { 1655 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 1656 } 1657 1658 public WifiConfiguration syncGetWifiApConfiguration() { 1659 Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG); 1660 WifiConfiguration ret = (WifiConfiguration) resultMsg.obj; 1661 resultMsg.recycle(); 1662 return ret; 1663 } 1664 1665 /** 1666 * TODO: doc 1667 */ 1668 public int syncGetWifiState() { 1669 return mWifiState.get(); 1670 } 1671 1672 /** 1673 * TODO: doc 1674 */ 1675 public String syncGetWifiStateByName() { 1676 switch (mWifiState.get()) { 1677 case WIFI_STATE_DISABLING: 1678 return "disabling"; 1679 case WIFI_STATE_DISABLED: 1680 return "disabled"; 1681 case WIFI_STATE_ENABLING: 1682 return "enabling"; 1683 case WIFI_STATE_ENABLED: 1684 return "enabled"; 1685 case WIFI_STATE_UNKNOWN: 1686 return "unknown state"; 1687 default: 1688 return "[invalid state]"; 1689 } 1690 } 1691 1692 /** 1693 * TODO: doc 1694 */ 1695 public int syncGetWifiApState() { 1696 return mWifiApState.get(); 1697 } 1698 1699 /** 1700 * TODO: doc 1701 */ 1702 public String syncGetWifiApStateByName() { 1703 switch (mWifiApState.get()) { 1704 case WIFI_AP_STATE_DISABLING: 1705 return "disabling"; 1706 case WIFI_AP_STATE_DISABLED: 1707 return "disabled"; 1708 case WIFI_AP_STATE_ENABLING: 1709 return "enabling"; 1710 case WIFI_AP_STATE_ENABLED: 1711 return "enabled"; 1712 case WIFI_AP_STATE_FAILED: 1713 return "failed"; 1714 default: 1715 return "[invalid state]"; 1716 } 1717 } 1718 1719 /** 1720 * Get status information for the current connection, if any. 1721 * @return a {@link WifiInfo} object containing information about the current connection 1722 * 1723 */ 1724 public WifiInfo syncRequestConnectionInfo() { 1725 return mWifiInfo; 1726 } 1727 1728 public DhcpResults syncGetDhcpResults() { 1729 synchronized (mDhcpResultsLock) { 1730 return new DhcpResults(mDhcpResults); 1731 } 1732 } 1733 1734 /** 1735 * TODO: doc 1736 */ 1737 public void setDriverStart(boolean enable) { 1738 if (enable) { 1739 sendMessage(CMD_START_DRIVER); 1740 } else { 1741 sendMessage(CMD_STOP_DRIVER); 1742 } 1743 } 1744 1745 /** 1746 * TODO: doc 1747 */ 1748 public void setOperationalMode(int mode) { 1749 if (DBG) log("setting operational mode to " + String.valueOf(mode)); 1750 sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0); 1751 } 1752 1753 /** 1754 * TODO: doc 1755 */ 1756 public List<ScanResult> syncGetScanResultsList() { 1757 synchronized (mScanResultCache) { 1758 List<ScanResult> scanList = new ArrayList<ScanResult>(); 1759 for(ScanResult result: mScanResults) { 1760 scanList.add(new ScanResult(result)); 1761 } 1762 return scanList; 1763 } 1764 } 1765 1766 /** 1767 * Disconnect from Access Point 1768 */ 1769 public void disconnectCommand() { 1770 sendMessage(CMD_DISCONNECT); 1771 } 1772 1773 /** 1774 * Initiate a reconnection to AP 1775 */ 1776 public void reconnectCommand() { 1777 sendMessage(CMD_RECONNECT); 1778 } 1779 1780 /** 1781 * Initiate a re-association to AP 1782 */ 1783 public void reassociateCommand() { 1784 sendMessage(CMD_REASSOCIATE); 1785 } 1786 1787 /** 1788 * Reload networks and then reconnect; helps load correct data for TLS networks 1789 */ 1790 1791 public void reloadTlsNetworksAndReconnect() { 1792 sendMessage(CMD_RELOAD_TLS_AND_RECONNECT); 1793 } 1794 1795 /** 1796 * Add a network synchronously 1797 * 1798 * @return network id of the new network 1799 */ 1800 public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) { 1801 Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config); 1802 int result = resultMsg.arg1; 1803 resultMsg.recycle(); 1804 return result; 1805 } 1806 1807 /** 1808 * Get configured networks synchronously 1809 * @param channel 1810 * @return 1811 */ 1812 1813 public List<WifiConfiguration> syncGetConfiguredNetworks(AsyncChannel channel) { 1814 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS); 1815 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 1816 resultMsg.recycle(); 1817 return result; 1818 } 1819 1820 public List<WifiConfiguration> syncGetPrivilegedConfiguredNetwork(AsyncChannel channel) { 1821 Message resultMsg = channel.sendMessageSynchronously( 1822 CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS); 1823 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 1824 resultMsg.recycle(); 1825 return result; 1826 } 1827 1828 1829 /** 1830 * Get connection statistics synchronously 1831 * @param channel 1832 * @return 1833 */ 1834 1835 public WifiConnectionStatistics syncGetConnectionStatistics(AsyncChannel channel) { 1836 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONNECTION_STATISTICS); 1837 WifiConnectionStatistics result = (WifiConnectionStatistics) resultMsg.obj; 1838 resultMsg.recycle(); 1839 return result; 1840 } 1841 1842 /** 1843 * Get adaptors synchronously 1844 */ 1845 1846 public List<WifiAdapter> syncGetAdaptors(AsyncChannel channel) { 1847 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_ADAPTORS); 1848 List<WifiAdapter> result = (List<WifiAdapter>) resultMsg.obj; 1849 resultMsg.recycle(); 1850 return result; 1851 } 1852 1853 /** 1854 * Delete a network 1855 * 1856 * @param networkId id of the network to be removed 1857 */ 1858 public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) { 1859 Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId); 1860 boolean result = (resultMsg.arg1 != FAILURE); 1861 resultMsg.recycle(); 1862 return result; 1863 } 1864 1865 /** 1866 * Enable a network 1867 * 1868 * @param netId network id of the network 1869 * @param disableOthers true, if all other networks have to be disabled 1870 * @return {@code true} if the operation succeeds, {@code false} otherwise 1871 */ 1872 public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) { 1873 Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId, 1874 disableOthers ? 1 : 0); 1875 boolean result = (resultMsg.arg1 != FAILURE); 1876 resultMsg.recycle(); 1877 return result; 1878 } 1879 1880 /** 1881 * Disable a network 1882 * 1883 * @param netId network id of the network 1884 * @return {@code true} if the operation succeeds, {@code false} otherwise 1885 */ 1886 public boolean syncDisableNetwork(AsyncChannel channel, int netId) { 1887 Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId); 1888 boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED); 1889 resultMsg.recycle(); 1890 return result; 1891 } 1892 1893 /** 1894 * Retrieves a WPS-NFC configuration token for the specified network 1895 * @return a hex string representation of the WPS-NFC configuration token 1896 */ 1897 public String syncGetWpsNfcConfigurationToken(int netId) { 1898 return mWifiNative.getNfcWpsConfigurationToken(netId); 1899 } 1900 1901 /** 1902 * Blacklist a BSSID. This will avoid the AP if there are 1903 * alternate APs to connect 1904 * 1905 * @param bssid BSSID of the network 1906 */ 1907 public void addToBlacklist(String bssid) { 1908 sendMessage(CMD_BLACKLIST_NETWORK, bssid); 1909 } 1910 1911 /** 1912 * Clear the blacklist list 1913 * 1914 */ 1915 public void clearBlacklist() { 1916 sendMessage(CMD_CLEAR_BLACKLIST); 1917 } 1918 1919 public void enableRssiPolling(boolean enabled) { 1920 sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0); 1921 } 1922 1923 public void enableBackgroundScanCommand(boolean enabled) { 1924 sendMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0); 1925 } 1926 1927 public void enableAllNetworks() { 1928 sendMessage(CMD_ENABLE_ALL_NETWORKS); 1929 } 1930 1931 /** 1932 * Start filtering Multicast v4 packets 1933 */ 1934 public void startFilteringMulticastV4Packets() { 1935 mFilteringMulticastV4Packets.set(true); 1936 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0); 1937 } 1938 1939 /** 1940 * Stop filtering Multicast v4 packets 1941 */ 1942 public void stopFilteringMulticastV4Packets() { 1943 mFilteringMulticastV4Packets.set(false); 1944 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0); 1945 } 1946 1947 /** 1948 * Start filtering Multicast v4 packets 1949 */ 1950 public void startFilteringMulticastV6Packets() { 1951 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0); 1952 } 1953 1954 /** 1955 * Stop filtering Multicast v4 packets 1956 */ 1957 public void stopFilteringMulticastV6Packets() { 1958 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0); 1959 } 1960 1961 /** 1962 * Set high performance mode of operation. 1963 * Enabling would set active power mode and disable suspend optimizations; 1964 * disabling would set auto power mode and enable suspend optimizations 1965 * @param enable true if enable, false otherwise 1966 */ 1967 public void setHighPerfModeEnabled(boolean enable) { 1968 sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0); 1969 } 1970 1971 /** 1972 * Set the country code 1973 * @param countryCode following ISO 3166 format 1974 * @param persist {@code true} if the setting should be remembered. 1975 */ 1976 public void setCountryCode(String countryCode, boolean persist) { 1977 // If it's a good country code, apply after the current 1978 // wifi connection is terminated; ignore resetting of code 1979 // for now (it is unclear what the chipset should do when 1980 // country code is reset) 1981 int countryCodeSequence = mCountryCodeSequence.incrementAndGet(); 1982 if (TextUtils.isEmpty(countryCode)) { 1983 log("Ignoring resetting of country code"); 1984 } else { 1985 sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, countryCode); 1986 } 1987 } 1988 1989 /** 1990 * Set the operational frequency band 1991 * @param band 1992 * @param persist {@code true} if the setting should be remembered. 1993 */ 1994 public void setFrequencyBand(int band, boolean persist) { 1995 if (persist) { 1996 Settings.Global.putInt(mContext.getContentResolver(), 1997 Settings.Global.WIFI_FREQUENCY_BAND, 1998 band); 1999 } 2000 sendMessage(CMD_SET_FREQUENCY_BAND, band, 0); 2001 } 2002 2003 /** 2004 * Enable TDLS for a specific MAC address 2005 */ 2006 public void enableTdls(String remoteMacAddress, boolean enable) { 2007 int enabler = enable ? 1 : 0; 2008 sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress); 2009 } 2010 2011 /** 2012 * Returns the operational frequency band 2013 */ 2014 public int getFrequencyBand() { 2015 return mFrequencyBand.get(); 2016 } 2017 2018 /** 2019 * Returns the wifi configuration file 2020 */ 2021 public String getConfigFile() { 2022 return mWifiConfigStore.getConfigFile(); 2023 } 2024 2025 /** 2026 * Send a message indicating bluetooth adapter connection state changed 2027 */ 2028 public void sendBluetoothAdapterStateChange(int state) { 2029 sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0); 2030 } 2031 2032 /** 2033 * Save configuration on supplicant 2034 * 2035 * @return {@code true} if the operation succeeds, {@code false} otherwise 2036 * 2037 * TODO: deprecate this 2038 */ 2039 public boolean syncSaveConfig(AsyncChannel channel) { 2040 Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG); 2041 boolean result = (resultMsg.arg1 != FAILURE); 2042 resultMsg.recycle(); 2043 return result; 2044 } 2045 2046 public void updateBatteryWorkSource(WorkSource newSource) { 2047 synchronized (mRunningWifiUids) { 2048 try { 2049 if (newSource != null) { 2050 mRunningWifiUids.set(newSource); 2051 } 2052 if (mIsRunning) { 2053 if (mReportedRunning) { 2054 // If the work source has changed since last time, need 2055 // to remove old work from battery stats. 2056 if (mLastRunningWifiUids.diff(mRunningWifiUids)) { 2057 mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids, 2058 mRunningWifiUids); 2059 mLastRunningWifiUids.set(mRunningWifiUids); 2060 } 2061 } else { 2062 // Now being started, report it. 2063 mBatteryStats.noteWifiRunning(mRunningWifiUids); 2064 mLastRunningWifiUids.set(mRunningWifiUids); 2065 mReportedRunning = true; 2066 } 2067 } else { 2068 if (mReportedRunning) { 2069 // Last reported we were running, time to stop. 2070 mBatteryStats.noteWifiStopped(mLastRunningWifiUids); 2071 mLastRunningWifiUids.clear(); 2072 mReportedRunning = false; 2073 } 2074 } 2075 mWakeLock.setWorkSource(newSource); 2076 } catch (RemoteException ignore) { 2077 } 2078 } 2079 } 2080 2081 @Override 2082 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2083 super.dump(fd, pw, args); 2084 mSupplicantStateTracker.dump(fd, pw, args); 2085 pw.println("mLinkProperties " + mLinkProperties); 2086 pw.println("mWifiInfo " + mWifiInfo); 2087 pw.println("mDhcpResults " + mDhcpResults); 2088 pw.println("mNetworkInfo " + mNetworkInfo); 2089 pw.println("mLastSignalLevel " + mLastSignalLevel); 2090 pw.println("mLastBssid " + mLastBssid); 2091 pw.println("mLastNetworkId " + mLastNetworkId); 2092 pw.println("mOperationalMode " + mOperationalMode); 2093 pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt); 2094 pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 2095 pw.println("Supplicant status " + mWifiNative.status()); 2096 pw.println("mEnableBackgroundScan " + mEnableBackgroundScan); 2097 pw.println("mLastSetCountryCode " + mLastSetCountryCode); 2098 pw.println("mPersistedCountryCode " + mPersistedCountryCode); 2099 pw.println(); 2100 mWifiConfigStore.dump(fd, pw, args); 2101 } 2102 2103 /********************************************************* 2104 * Internal private functions 2105 ********************************************************/ 2106 2107 private void logStateAndMessage(Message message, String state) { 2108 if (mLogMessages) { 2109 //long now = SystemClock.elapsedRealtimeNanos(); 2110 //String ts = String.format("[%,d us]", now/1000); 2111 2112 loge( " " + state + " " + getLogRecString(message)); 2113 } 2114 } 2115 2116 /** 2117 * Return the additional string to be logged by LogRec, default 2118 * 2119 * @param msg that was processed 2120 * @return information to be logged as a String 2121 */ 2122 protected String getLogRecString(Message msg) { 2123 WifiConfiguration config; 2124 StringBuilder sb = new StringBuilder(); 2125 if (mScreenOn) { 2126 sb.append("!"); 2127 } 2128 sb.append(smToString(msg)); 2129 2130 switch (msg.what) { 2131 case CMD_START_SCAN: 2132 sb.append(" "); 2133 sb.append(Integer.toString(msg.arg1)); 2134 sb.append(" "); 2135 sb.append(Integer.toString(msg.arg2)); 2136 if (mIsScanOngoing) sb.append(" onGoing"); 2137 if (mIsFullScanOngoing) sb.append(" full"); 2138 if (lastStartScanTimeStamp != 0) { 2139 sb.append(" started:").append(lastStartScanTimeStamp); 2140 } 2141 if (lastScanDuration != 0) { 2142 sb.append(" dur:").append(lastScanDuration); 2143 } 2144 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2145 sb.append(" f=").append(mWifiInfo.getFrequency()); 2146 sb.append(" sc=").append(mWifiInfo.score); 2147 sb.append(" link=").append(mWifiInfo.getLinkSpeed()); 2148 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate)); 2149 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate)); 2150 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate)); 2151 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate)); 2152 if (lastScanFreqs != null) sb.append(" ").append(lastScanFreqs); 2153 break; 2154 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2155 sb.append(" "); 2156 sb.append(Integer.toString(msg.arg1)); 2157 sb.append(" "); 2158 sb.append(Integer.toString(msg.arg2)); 2159 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj; 2160 if (stateChangeResult != null) { 2161 sb.append(stateChangeResult.toString()); 2162 } 2163 break; 2164 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 2165 sb.append(" "); 2166 sb.append(Integer.toString(msg.arg1)); 2167 sb.append(" "); 2168 sb.append(Integer.toString(msg.arg2)); 2169 String bssid = (String)msg.obj; 2170 if (bssid != null && bssid.length()>0) { 2171 sb.append(" "); 2172 sb.append(bssid); 2173 } 2174 sb.append(" blacklist=" + Boolean.toString(didBlackListBSSID)); 2175 break; 2176 case WifiMonitor.SCAN_RESULTS_EVENT: 2177 sb.append(" "); 2178 sb.append(Integer.toString(msg.arg1)); 2179 sb.append(" "); 2180 sb.append(Integer.toString(msg.arg2)); 2181 if (mScanResults != null) { 2182 sb.append(mScanResults.size()); 2183 } 2184 if (lastScanDuration != 0) { 2185 sb.append(" dur:").append(lastScanDuration); 2186 } 2187 break; 2188 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2189 sb.append(" "); 2190 sb.append(Integer.toString(msg.arg1)); 2191 sb.append(" "); 2192 sb.append(Integer.toString(msg.arg2)); 2193 sb.append(" ").append(mLastBssid); 2194 sb.append(" nid=").append(mLastNetworkId); 2195 config = getCurrentWifiConfiguration(); 2196 if (config != null) { 2197 sb.append(" ").append(config.configKey()); 2198 } 2199 break; 2200 case CMD_TARGET_BSSID: 2201 sb.append(" "); 2202 sb.append(Integer.toString(msg.arg1)); 2203 sb.append(" "); 2204 sb.append(Integer.toString(msg.arg2)); 2205 if (msg.obj != null) { 2206 sb.append(" BSSID=").append((String)msg.obj); 2207 } 2208 if (mTargetRoamBSSID != null) { 2209 sb.append(" Target=").append(mTargetRoamBSSID); 2210 } 2211 sb.append(" roam=").append(Integer.toString(mAutoRoaming)); 2212 break; 2213 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2214 if (msg.obj != null) { 2215 sb.append(" ").append((String)msg.obj); 2216 } 2217 sb.append(" nid=").append(msg.arg1); 2218 sb.append(" reason=").append(msg.arg2); 2219 if (mLastBssid != null) { 2220 sb.append(" lastbssid=").append(mLastBssid); 2221 } 2222 if (mWifiInfo.getFrequency() != -1) { 2223 sb.append(" freq=").append(mWifiInfo.getFrequency()); 2224 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2225 } 2226 if (linkDebouncing) { 2227 sb.append(" debounce"); 2228 } 2229 break; 2230 case WifiMonitor.SSID_TEMP_DISABLED: 2231 case WifiMonitor.SSID_REENABLED: 2232 sb.append(" nid=").append(msg.arg1); 2233 if (msg.obj != null) { 2234 sb.append(" ").append((String)msg.obj); 2235 } 2236 break; 2237 case CMD_RSSI_POLL: 2238 case CMD_UNWANTED_NETWORK: 2239 case WifiManager.RSSI_PKTCNT_FETCH: 2240 sb.append(" "); 2241 sb.append(Integer.toString(msg.arg1)); 2242 sb.append(" "); 2243 sb.append(Integer.toString(msg.arg2)); 2244 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2245 sb.append(" f=").append(mWifiInfo.getFrequency()); 2246 sb.append(" sc=").append(mWifiInfo.score); 2247 sb.append(" link=").append(mWifiInfo.getLinkSpeed()); 2248 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate)); 2249 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate)); 2250 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate)); 2251 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate)); 2252 break; 2253 case CMD_AUTO_CONNECT: 2254 case WifiManager.CONNECT_NETWORK: 2255 sb.append(" "); 2256 sb.append(Integer.toString(msg.arg1)); 2257 sb.append(" "); 2258 sb.append(Integer.toString(msg.arg2)); 2259 config = (WifiConfiguration) msg.obj; 2260 if (config != null) { 2261 sb.append(" ").append(config.configKey()); 2262 if (config.visibility != null) { 2263 sb.append(" [").append(config.visibility.num24); 2264 sb.append(" ,").append(config.visibility.rssi24); 2265 sb.append(" ;").append(config.visibility.num5); 2266 sb.append(" ,").append(config.visibility.rssi5).append("]"); 2267 } 2268 } 2269 if (mTargetRoamBSSID != null) { 2270 sb.append(" ").append(mTargetRoamBSSID); 2271 } 2272 sb.append(" roam=").append(Integer.toString(mAutoRoaming)); 2273 break; 2274 case CMD_AUTO_ROAM: 2275 sb.append(" "); 2276 sb.append(Integer.toString(msg.arg1)); 2277 sb.append(" "); 2278 sb.append(Integer.toString(msg.arg2)); 2279 ScanResult result = (ScanResult)msg.obj; 2280 if (result != null) { 2281 sb.append(" rssi=").append(result.level); 2282 sb.append(" freq=").append(result.frequency); 2283 sb.append(" ").append(result.BSSID); 2284 } 2285 if (mTargetRoamBSSID != null) { 2286 sb.append(" ").append(mTargetRoamBSSID); 2287 } 2288 sb.append(" roam=").append(Integer.toString(mAutoRoaming)); 2289 break; 2290 case CMD_ENABLE_NETWORK: 2291 sb.append(" "); 2292 sb.append(Integer.toString(msg.arg1)); 2293 sb.append(" "); 2294 sb.append(Integer.toString(msg.arg2)); 2295 String key = mWifiConfigStore.getLastSelectedConfiguration(); 2296 if (key != null) { 2297 sb.append(" ").append(key); 2298 } 2299 break; 2300 case CMD_GET_CONFIGURED_NETWORKS: 2301 sb.append(" "); 2302 sb.append(Integer.toString(msg.arg1)); 2303 sb.append(" "); 2304 sb.append(Integer.toString(msg.arg2)); 2305 sb.append(" num=").append(mWifiConfigStore.getConfiguredNetworksSize()); 2306 break; 2307 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 2308 sb.append(" "); 2309 sb.append(Integer.toString(msg.arg1)); 2310 sb.append(" "); 2311 sb.append(Integer.toString(msg.arg2)); 2312 if (msg.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 2313 sb.append(" OK "); 2314 } else if (msg.arg1 == DhcpStateMachine.DHCP_FAILURE) { 2315 sb.append(" FAIL "); 2316 } 2317 if (mLinkProperties != null) { 2318 if (mLinkProperties.hasIPv4Address()) { 2319 sb.append(" v4"); 2320 } 2321 if (mLinkProperties.hasGlobalIPv6Address()) { 2322 sb.append(" v6"); 2323 } 2324 if (mLinkProperties.hasIPv4DefaultRoute()) { 2325 sb.append(" v4r"); 2326 } 2327 if (mLinkProperties.hasIPv6DefaultRoute()) { 2328 sb.append(" v6r"); 2329 } 2330 if (mLinkProperties.hasIPv4DnsServer()) { 2331 sb.append(" v4dns"); 2332 } 2333 if (mLinkProperties.hasIPv6DnsServer()) { 2334 sb.append(" v6dns"); 2335 } 2336 } 2337 break; 2338 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 2339 sb.append(" "); 2340 sb.append(Integer.toString(msg.arg1)); 2341 sb.append(" "); 2342 sb.append(Integer.toString(msg.arg2)); 2343 if (msg.obj != null) { 2344 NetworkInfo info = (NetworkInfo)msg.obj; 2345 NetworkInfo.State state = info.getState(); 2346 NetworkInfo.DetailedState detailedState = info.getDetailedState(); 2347 if (state != null) { 2348 sb.append(" st=").append(state); 2349 } 2350 if (detailedState != null) { 2351 sb.append("/").append(detailedState); 2352 } 2353 } 2354 break; 2355 case CMD_IP_CONFIGURATION_LOST: 2356 int count = -1; 2357 WifiConfiguration c = getCurrentWifiConfiguration(); 2358 if (c != null) count = c.numConnectionFailures; 2359 sb.append(" "); 2360 sb.append(Integer.toString(msg.arg1)); 2361 sb.append(" "); 2362 sb.append(Integer.toString(msg.arg2)); 2363 sb.append(" failures: "); 2364 sb.append(Integer.toString(count)); 2365 sb.append("/"); 2366 sb.append(Integer.toString(mWifiConfigStore.getMaxDhcpRetries())); 2367 break; 2368 case CMD_UPDATE_LINKPROPERTIES: 2369 sb.append(" "); 2370 sb.append(Integer.toString(msg.arg1)); 2371 sb.append(" "); 2372 sb.append(Integer.toString(msg.arg2)); 2373 if (mLinkProperties != null) { 2374 if (mLinkProperties.hasIPv4Address()) { 2375 sb.append(" v4"); 2376 } 2377 if (mLinkProperties.hasGlobalIPv6Address()) { 2378 sb.append(" v6"); 2379 } 2380 if (mLinkProperties.hasIPv4DefaultRoute()) { 2381 sb.append(" v4r"); 2382 } 2383 if (mLinkProperties.hasIPv6DefaultRoute()) { 2384 sb.append(" v6r"); 2385 } 2386 if (mLinkProperties.hasIPv4DnsServer()) { 2387 sb.append(" v4dns"); 2388 } 2389 if (mLinkProperties.hasIPv6DnsServer()) { 2390 sb.append(" v6dns"); 2391 } 2392 } 2393 break; 2394 default: 2395 sb.append(" "); 2396 sb.append(Integer.toString(msg.arg1)); 2397 sb.append(" "); 2398 sb.append(Integer.toString(msg.arg2)); 2399 break; 2400 } 2401 2402 return sb.toString(); 2403 } 2404 2405 private void handleScreenStateChanged(boolean screenOn) { 2406 mScreenOn = screenOn; 2407 if (PDBG) { 2408 loge(" handleScreenStateChanged Enter: screenOn=" + screenOn 2409 + "mCurrentScanAlarmMs = " + Long.toString(mCurrentScanAlarmMs) 2410 + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt 2411 + " autojoin " + mFrameworkAutoJoin 2412 + " state " + getCurrentState().getName() 2413 + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); 2414 } 2415 enableRssiPolling(screenOn); 2416 if (mBackgroundScanSupported) { 2417 enableBackgroundScanCommand(screenOn == false); 2418 } 2419 2420 if (screenOn) enableAllNetworks(); 2421 if (mUserWantsSuspendOpt.get()) { 2422 if (screenOn) { 2423 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0); 2424 } else { 2425 //Allow 2s for suspend optimizations to be set 2426 mSuspendWakeLock.acquire(2000); 2427 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0); 2428 } 2429 } 2430 mScreenBroadcastReceived.set(true); 2431 2432 if (screenOn) { 2433 fullBandConnectedTimeIntervalMilli = 20 * 1000; //start at 20 seconds interval 2434 if (mFrameworkAutoJoin.get()) { 2435 //start the scan alarm so as to enable autojoin 2436 if (getCurrentState() == mConnectedState) { 2437 mCurrentScanAlarmMs = mConnectedScanPeriodMs; 2438 } else if (getCurrentState() == mDisconnectedState) { 2439 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 2440 //kick a scan right now 2441 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 2442 } else if (getCurrentState() == mDisconnectingState) { 2443 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 2444 //kick a scan right now 2445 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 2446 } 2447 } 2448 setScanAlarm(true); 2449 2450 } else { 2451 setScanAlarm(false); 2452 } 2453 2454 if (DBG) log("handleScreenStateChanged Exit: " + screenOn); 2455 } 2456 2457 private void checkAndSetConnectivityInstance() { 2458 if (mCm == null) { 2459 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 2460 } 2461 } 2462 2463 private boolean startTethering(ArrayList<String> available) { 2464 2465 boolean wifiAvailable = false; 2466 2467 checkAndSetConnectivityInstance(); 2468 2469 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 2470 2471 for (String intf : available) { 2472 for (String regex : wifiRegexs) { 2473 if (intf.matches(regex)) { 2474 2475 InterfaceConfiguration ifcg = null; 2476 try { 2477 ifcg = mNwService.getInterfaceConfig(intf); 2478 if (ifcg != null) { 2479 /* IP/netmask: 192.168.43.1/255.255.255.0 */ 2480 ifcg.setLinkAddress(new LinkAddress( 2481 NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); 2482 ifcg.setInterfaceUp(); 2483 2484 mNwService.setInterfaceConfig(intf, ifcg); 2485 } 2486 } catch (Exception e) { 2487 loge("Error configuring interface " + intf + ", :" + e); 2488 return false; 2489 } 2490 2491 if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 2492 loge("Error tethering on " + intf); 2493 return false; 2494 } 2495 mTetherInterfaceName = intf; 2496 return true; 2497 } 2498 } 2499 } 2500 // We found no interfaces to tether 2501 return false; 2502 } 2503 2504 private void stopTethering() { 2505 2506 checkAndSetConnectivityInstance(); 2507 2508 /* Clear the interface config to allow dhcp correctly configure new 2509 ip settings */ 2510 InterfaceConfiguration ifcg = null; 2511 try { 2512 ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName); 2513 if (ifcg != null) { 2514 ifcg.setLinkAddress( 2515 new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); 2516 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg); 2517 } 2518 } catch (Exception e) { 2519 loge("Error resetting interface " + mTetherInterfaceName + ", :" + e); 2520 } 2521 2522 if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 2523 loge("Untether initiate failed!"); 2524 } 2525 } 2526 2527 private boolean isWifiTethered(ArrayList<String> active) { 2528 2529 checkAndSetConnectivityInstance(); 2530 2531 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 2532 for (String intf : active) { 2533 for (String regex : wifiRegexs) { 2534 if (intf.matches(regex)) { 2535 return true; 2536 } 2537 } 2538 } 2539 // We found no interfaces that are tethered 2540 return false; 2541 } 2542 2543 /** 2544 * Set the country code from the system setting value, if any. 2545 */ 2546 private void setCountryCode() { 2547 String countryCode = Settings.Global.getString(mContext.getContentResolver(), 2548 Settings.Global.WIFI_COUNTRY_CODE); 2549 if (countryCode != null && !countryCode.isEmpty()) { 2550 setCountryCode(countryCode, false); 2551 } else { 2552 //use driver default 2553 } 2554 } 2555 2556 /** 2557 * Set the frequency band from the system setting value, if any. 2558 */ 2559 private void setFrequencyBand() { 2560 int band = Settings.Global.getInt(mContext.getContentResolver(), 2561 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO); 2562 setFrequencyBand(band, false); 2563 } 2564 2565 private void setSuspendOptimizationsNative(int reason, boolean enabled) { 2566 if (DBG) { 2567 log("setSuspendOptimizationsNative: " + reason + " " + enabled 2568 + " -want " + mUserWantsSuspendOpt.get() 2569 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2570 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 2571 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 2572 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 2573 } 2574 //mWifiNative.setSuspendOptimizations(enabled); 2575 2576 if (enabled) { 2577 mSuspendOptNeedsDisabled &= ~reason; 2578 /* None of dhcp, screen or highperf need it disabled and user wants it enabled */ 2579 if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) { 2580 if (DBG) { 2581 log("setSuspendOptimizationsNative do it " + reason + " " + enabled 2582 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2583 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 2584 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 2585 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 2586 } 2587 mWifiNative.setSuspendOptimizations(true); 2588 } 2589 } else { 2590 mSuspendOptNeedsDisabled |= reason; 2591 mWifiNative.setSuspendOptimizations(false); 2592 } 2593 } 2594 2595 private void setSuspendOptimizations(int reason, boolean enabled) { 2596 if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled); 2597 if (enabled) { 2598 mSuspendOptNeedsDisabled &= ~reason; 2599 } else { 2600 mSuspendOptNeedsDisabled |= reason; 2601 } 2602 if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 2603 } 2604 2605 private void setWifiState(int wifiState) { 2606 final int previousWifiState = mWifiState.get(); 2607 2608 try { 2609 if (wifiState == WIFI_STATE_ENABLED) { 2610 mBatteryStats.noteWifiOn(); 2611 } else if (wifiState == WIFI_STATE_DISABLED) { 2612 mBatteryStats.noteWifiOff(); 2613 } 2614 } catch (RemoteException e) { 2615 loge("Failed to note battery stats in wifi"); 2616 } 2617 2618 mWifiState.set(wifiState); 2619 2620 if (DBG) log("setWifiState: " + syncGetWifiStateByName()); 2621 2622 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 2623 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2624 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 2625 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 2626 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2627 } 2628 2629 private void setWifiApState(int wifiApState) { 2630 final int previousWifiApState = mWifiApState.get(); 2631 2632 try { 2633 if (wifiApState == WIFI_AP_STATE_ENABLED) { 2634 mBatteryStats.noteWifiOn(); 2635 } else if (wifiApState == WIFI_AP_STATE_DISABLED) { 2636 mBatteryStats.noteWifiOff(); 2637 } 2638 } catch (RemoteException e) { 2639 loge("Failed to note battery stats in wifi"); 2640 } 2641 2642 // Update state 2643 mWifiApState.set(wifiApState); 2644 2645 if (DBG) log("setWifiApState: " + syncGetWifiApStateByName()); 2646 2647 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 2648 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2649 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); 2650 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); 2651 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2652 } 2653 2654 private static final String ID_STR = "id="; 2655 private static final String BSSID_STR = "bssid="; 2656 private static final String FREQ_STR = "freq="; 2657 private static final String LEVEL_STR = "level="; 2658 private static final String TSF_STR = "tsf="; 2659 private static final String FLAGS_STR = "flags="; 2660 private static final String SSID_STR = "ssid="; 2661 private static final String DELIMITER_STR = "===="; 2662 private static final String END_STR = "####"; 2663 2664 /** 2665 * Format: 2666 * 2667 * id=1 2668 * bssid=68:7f:76:d7:1a:6e 2669 * freq=2412 2670 * level=-44 2671 * tsf=1344626243700342 2672 * flags=[WPA2-PSK-CCMP][WPS][ESS] 2673 * ssid=zfdy 2674 * ==== 2675 * id=2 2676 * bssid=68:5f:74:d7:1a:6f 2677 * freq=5180 2678 * level=-73 2679 * tsf=1344626243700373 2680 * flags=[WPA2-PSK-CCMP][WPS][ESS] 2681 * ssid=zuby 2682 * ==== 2683 */ 2684 private void setScanResults() { 2685 String bssid = ""; 2686 int level = 0; 2687 int freq = 0; 2688 long tsf = 0; 2689 String flags = ""; 2690 WifiSsid wifiSsid = null; 2691 String scanResults; 2692 String tmpResults; 2693 StringBuffer scanResultsBuf = new StringBuffer(); 2694 int sid = 0; 2695 2696 while (true) { 2697 tmpResults = mWifiNative.scanResults(sid); 2698 if (TextUtils.isEmpty(tmpResults)) break; 2699 scanResultsBuf.append(tmpResults); 2700 scanResultsBuf.append("\n"); 2701 String[] lines = tmpResults.split("\n"); 2702 sid = -1; 2703 for (int i=lines.length - 1; i >= 0; i--) { 2704 if (lines[i].startsWith(END_STR)) { 2705 break; 2706 } else if (lines[i].startsWith(ID_STR)) { 2707 try { 2708 sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1; 2709 } catch (NumberFormatException e) { 2710 // Nothing to do 2711 } 2712 break; 2713 } 2714 } 2715 if (sid == -1) break; 2716 } 2717 2718 scanResults = scanResultsBuf.toString(); 2719 if (TextUtils.isEmpty(scanResults)) { 2720 return; 2721 } 2722 2723 // note that all these splits and substrings keep references to the original 2724 // huge string buffer while the amount we really want is generally pretty small 2725 // so make copies instead (one example b/11087956 wasted 400k of heap here). 2726 synchronized(mScanResultCache) { 2727 mScanResults = new ArrayList<ScanResult>(); 2728 String[] lines = scanResults.split("\n"); 2729 final int bssidStrLen = BSSID_STR.length(); 2730 final int flagLen = FLAGS_STR.length(); 2731 2732 for (String line : lines) { 2733 if (line.startsWith(BSSID_STR)) { 2734 bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen); 2735 } else if (line.startsWith(FREQ_STR)) { 2736 try { 2737 freq = Integer.parseInt(line.substring(FREQ_STR.length())); 2738 } catch (NumberFormatException e) { 2739 freq = 0; 2740 } 2741 } else if (line.startsWith(LEVEL_STR)) { 2742 try { 2743 level = Integer.parseInt(line.substring(LEVEL_STR.length())); 2744 /* some implementations avoid negative values by adding 256 2745 * so we need to adjust for that here. 2746 */ 2747 if (level > 0) level -= 256; 2748 } catch(NumberFormatException e) { 2749 level = 0; 2750 } 2751 } else if (line.startsWith(TSF_STR)) { 2752 try { 2753 tsf = Long.parseLong(line.substring(TSF_STR.length())); 2754 } catch (NumberFormatException e) { 2755 tsf = 0; 2756 } 2757 } else if (line.startsWith(FLAGS_STR)) { 2758 flags = new String(line.getBytes(), flagLen, line.length() - flagLen); 2759 } else if (line.startsWith(SSID_STR)) { 2760 wifiSsid = WifiSsid.createFromAsciiEncoded( 2761 line.substring(SSID_STR.length())); 2762 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) { 2763 if (bssid != null) { 2764 String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 2765 String key = bssid + ssid; 2766 ScanResult scanResult = mScanResultCache.get(key); 2767 if (scanResult != null) { 2768 scanResult.level = level; 2769 scanResult.wifiSsid = wifiSsid; 2770 // Keep existing API 2771 scanResult.SSID = (wifiSsid != null) ? wifiSsid.toString() : 2772 WifiSsid.NONE; 2773 scanResult.capabilities = flags; 2774 scanResult.frequency = freq; 2775 scanResult.timestamp = tsf; 2776 scanResult.seen = System.currentTimeMillis(); 2777 } else { 2778 scanResult = 2779 new ScanResult( 2780 wifiSsid, bssid, flags, level, freq, tsf); 2781 mScanResultCache.put(key, scanResult); 2782 } 2783 mScanResults.add(scanResult); 2784 } 2785 bssid = null; 2786 level = 0; 2787 freq = 0; 2788 tsf = 0; 2789 flags = ""; 2790 wifiSsid = null; 2791 } 2792 } 2793 } 2794 boolean attemptAutoJoin = true; 2795 if (getCurrentState() == mRoamingState 2796 || getCurrentState() == mObtainingIpState 2797 || linkDebouncing) { 2798 // Dont attempt auto-joining again while we are already attempting to join 2799 // and/or obtaining Ip address 2800 attemptAutoJoin = false; 2801 } 2802 mWifiAutoJoinController.newSupplicantResults(attemptAutoJoin); 2803 if (linkDebouncing) { 2804 // If debouncing, we dont re-select a SSID or BSSID hence 2805 // there is no need to call the network selection code 2806 // in WifiAutoJoinController, instead, 2807 // just try to reconnect to the same SSID by triggering a roam 2808 sendMessage(CMD_AUTO_ROAM, mLastNetworkId, 1, null); 2809 } 2810 } 2811 2812 /* 2813 * Fetch RSSI, linkspeed, and frequency on current connection 2814 */ 2815 private void fetchRssiLinkSpeedAndFrequencyNative() { 2816 int newRssi = -1; 2817 int newLinkSpeed = -1; 2818 int newFrequency = -1; 2819 2820 String signalPoll = mWifiNative.signalPoll(); 2821 2822 if (signalPoll != null) { 2823 String[] lines = signalPoll.split("\n"); 2824 for (String line : lines) { 2825 String[] prop = line.split("="); 2826 if (prop.length < 2) continue; 2827 try { 2828 if (prop[0].equals("RSSI")) { 2829 newRssi = Integer.parseInt(prop[1]); 2830 } else if (prop[0].equals("LINKSPEED")) { 2831 newLinkSpeed = Integer.parseInt(prop[1]); 2832 } else if (prop[0].equals("FREQUENCY")) { 2833 newFrequency = Integer.parseInt(prop[1]); 2834 } 2835 } catch (NumberFormatException e) { 2836 //Ignore, defaults on rssi and linkspeed are assigned 2837 } 2838 } 2839 } 2840 2841 if (PDBG) { 2842 loge("fetchRssiLinkSpeedAndFrequencyNative rssi=" 2843 + Integer.toString(newRssi) + " linkspeed=" 2844 + Integer.toString(newLinkSpeed)); 2845 } 2846 2847 if (newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) { 2848 // screen out invalid values 2849 /* some implementations avoid negative values by adding 256 2850 * so we need to adjust for that here. 2851 */ 2852 if (newRssi > 0) newRssi -= 256; 2853 mWifiInfo.setRssi(newRssi); 2854 /* 2855 * Rather then sending the raw RSSI out every time it 2856 * changes, we precalculate the signal level that would 2857 * be displayed in the status bar, and only send the 2858 * broadcast if that much more coarse-grained number 2859 * changes. This cuts down greatly on the number of 2860 * broadcasts, at the cost of not informing others 2861 * interested in RSSI of all the changes in signal 2862 * level. 2863 */ 2864 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); 2865 if (newSignalLevel != mLastSignalLevel) { 2866 sendRssiChangeBroadcast(newRssi); 2867 } 2868 mLastSignalLevel = newSignalLevel; 2869 } else { 2870 mWifiInfo.setRssi(WifiInfo.INVALID_RSSI); 2871 } 2872 2873 if (newLinkSpeed != -1) { 2874 mWifiInfo.setLinkSpeed(newLinkSpeed); 2875 } 2876 if (newFrequency > 0) { 2877 if (ScanResult.is24GHz(newFrequency)) { 2878 mWifiConnectionStatistics.num5GhzConnected++; 2879 } 2880 if (ScanResult.is24GHz(newFrequency)) { 2881 mWifiConnectionStatistics.num24GhzConnected++; 2882 } 2883 mWifiInfo.setFrequency(newFrequency); 2884 } 2885 mWifiConfigStore.updateConfiguration(mWifiInfo); 2886 } 2887 2888 /** 2889 * Determine if we need to switch network: 2890 * - the delta determine the urgency to switch and/or or the expected evilness of the disruption 2891 * - match the uregncy of the switch versus the packet usage at the interface 2892 */ 2893 boolean shouldSwitchNetwork(int networkDelta) { 2894 int delta; 2895 if (networkDelta <= 0) { 2896 return false; 2897 } 2898 delta = networkDelta; 2899 if (mWifiInfo != null) { 2900 if (!mWifiConfigStore.enableAutoJoinWhileAssociated 2901 && mWifiInfo.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 2902 // If AutoJoin while associated is not enabled, 2903 // we should never switch network when already associated 2904 delta = -1000; 2905 } else { 2906 // TODO: Look at per AC packet count, do not switch if VO/VI traffic is present 2907 // TODO: at the interface. We should also discriminate between ucast and mcast, 2908 // TODO: since the rxSuccessRate include all the bonjour and Ipv6 2909 // TODO: broadcasts 2910 if ((mWifiInfo.txSuccessRate > 20) || (mWifiInfo.rxSuccessRate > 80)) { 2911 delta -= 999; 2912 } else if ((mWifiInfo.txSuccessRate > 5) || (mWifiInfo.rxSuccessRate > 30)) { 2913 delta -= 6; 2914 } 2915 loge("WifiStateMachine shouldSwitchNetwork " 2916 + " txSuccessRate=" + String.format("%.2f", mWifiInfo.txSuccessRate) 2917 + " rxSuccessRate=" + String.format("%.2f", mWifiInfo.rxSuccessRate) 2918 + " delta " + networkDelta + " -> " + delta); 2919 } 2920 } else { 2921 loge("WifiStateMachine shouldSwitchNetwork " 2922 + " delta " + networkDelta + " -> " + delta); 2923 } 2924 if (delta > 0) { 2925 return true; 2926 } 2927 return false; 2928 } 2929 2930 private void calculateWifiScore(WifiLinkLayerStats stats) { 2931 2932 if (stats == null || mWifiLinkLayerStatsSupported <= 0) { 2933 long mTxPkts = TrafficStats.getTxPackets(mInterfaceName); 2934 long mRxPkts = TrafficStats.getRxPackets(mInterfaceName); 2935 mWifiInfo.updatePacketRates(mTxPkts, mRxPkts); 2936 2937 } else { 2938 mWifiInfo.updatePacketRates(stats); 2939 } 2940 int score = 56; //starting score, temporarily hardcoded in between 50 and 60 2941 boolean isBadLinkspeed = (mWifiInfo.is24GHz() 2942 && mWifiInfo.getLinkSpeed() < 6) 2943 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed() < 12); 2944 boolean isGoodLinkspeed = (mWifiInfo.is24GHz() 2945 && mWifiInfo.getLinkSpeed() >= 24) 2946 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed() >= 48); 2947 2948 2949 /** 2950 * We want to make sure that we use the 24GHz RSSI thresholds is 2951 * there are 2.4GHz scan results 2952 * otherwise we end up lowering the score based on 5GHz values 2953 * which may cause a switch to LTE before roaming has a chance to try 2.4GHz 2954 * We also might unblacklist the configuation based on 2.4GHz 2955 * thresholds but joining 5GHz anyhow, and failing over to 2.4GHz because 5GHz is not good 2956 */ 2957 boolean use24Thresholds = false; 2958 boolean homeNetworkBoost = false; 2959 WifiConfiguration currentConfiguration = getCurrentWifiConfiguration(); 2960 if (currentConfiguration != null 2961 && currentConfiguration.scanResultCache != null) { 2962 currentConfiguration.setVisibility(12000); 2963 if (currentConfiguration.visibility != null) { 2964 if (currentConfiguration.visibility.rssi24 != WifiConfiguration.INVALID_RSSI 2965 && currentConfiguration.visibility.rssi24 2966 >= (currentConfiguration.visibility.rssi5-2)) { 2967 use24Thresholds = true; 2968 } 2969 } 2970 if (currentConfiguration.scanResultCache.size() <= 4 2971 && currentConfiguration.allowedKeyManagement.cardinality() == 1 2972 && currentConfiguration.allowedKeyManagement. 2973 get(WifiConfiguration.KeyMgmt.WPA_PSK) == true) { 2974 // A PSK network with less than 4 known BSSIDs 2975 // This is most likely a home network and thus we want to stick to wifi more 2976 homeNetworkBoost = true; 2977 } 2978 } 2979 2980 int rssi = mWifiInfo.getRssi() - 6 * mAggressiveHandover 2981 + (homeNetworkBoost ? WifiConfiguration.HOME_NETWORK_RSSI_BOOST : 0); 2982 boolean is24GHz = use24Thresholds || mWifiInfo.is24GHz(); 2983 2984 boolean isBadRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdBadRssi24) 2985 || (!is24GHz && rssi < mWifiConfigStore.thresholdBadRssi5); 2986 boolean isLowRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdLowRssi24) 2987 || (!is24GHz && mWifiInfo.getRssi() < mWifiConfigStore.thresholdLowRssi5); 2988 boolean isHighRSSI = (is24GHz && rssi >= mWifiConfigStore.thresholdGoodRssi24) 2989 || (!is24GHz && mWifiInfo.getRssi() >= mWifiConfigStore.thresholdGoodRssi5); 2990 2991 if (PDBG) { 2992 String rssiStatus = ""; 2993 if (isBadRSSI) rssiStatus += " badRSSI "; 2994 else if (isHighRSSI) rssiStatus += " highRSSI "; 2995 else if (isLowRSSI) rssiStatus += " lowRSSI "; 2996 if (isBadLinkspeed) rssiStatus += " lowSpeed "; 2997 loge("calculateWifiScore freq=" + Integer.toString(mWifiInfo.getFrequency()) 2998 + " speed=" + Integer.toString(mWifiInfo.getLinkSpeed()) 2999 + " score=" + Integer.toString(mWifiInfo.score) 3000 + rssiStatus 3001 + " -> txbadrate=" + String.format( "%.2f", mWifiInfo.txBadRate ) 3002 + " txgoodrate=" + String.format("%.2f", mWifiInfo.txSuccessRate) 3003 + " txretriesrate=" + String.format("%.2f", mWifiInfo.txRetriesRate) 3004 + " rxrate=" + String.format("%.2f", mWifiInfo.rxSuccessRate) 3005 ); 3006 } 3007 3008 if ((mWifiInfo.txBadRate >= 1) && (mWifiInfo.txSuccessRate < 3) 3009 && (isBadRSSI || isLowRSSI)) { 3010 // Link is stuck 3011 if (mWifiInfo.linkStuckCount < 5) 3012 mWifiInfo.linkStuckCount += 1; 3013 if (PDBG) loge(" bad link -> stuck count =" 3014 + Integer.toString(mWifiInfo.linkStuckCount)); 3015 } else if (mWifiInfo.txSuccessRate > 2 || mWifiInfo.txBadRate < 0.1) { 3016 if (mWifiInfo.linkStuckCount > 0) 3017 mWifiInfo.linkStuckCount -= 1; 3018 if (PDBG) loge(" good link -> stuck count =" 3019 + Integer.toString(mWifiInfo.linkStuckCount)); 3020 } 3021 3022 if (mWifiInfo.linkStuckCount > 1) { 3023 // Once link gets stuck for more than 3 seconds, start reducing the score 3024 score = score - 2 * (mWifiInfo.linkStuckCount - 1); 3025 } 3026 3027 if (isBadLinkspeed) { 3028 score -= 4; 3029 if (PDBG) loge(" isBadLinkspeed ---> score=" + Integer.toString(score)); 3030 } else if ((isGoodLinkspeed) && (mWifiInfo.txSuccessRate > 5)) { 3031 score += 4; // So as bad rssi alone dont kill us 3032 } 3033 3034 if (isBadRSSI) { 3035 if (mWifiInfo.badRssiCount < 7) 3036 mWifiInfo.badRssiCount += 1; 3037 } else if (isLowRSSI) { 3038 mWifiInfo.lowRssiCount = 1; // Dont increment 3039 if (mWifiInfo.badRssiCount > 0) { 3040 mWifiInfo.badRssiCount -= 1; 3041 } 3042 } else { 3043 mWifiInfo.badRssiCount = 0; 3044 mWifiInfo.lowRssiCount = 0; 3045 } 3046 3047 score -= mWifiInfo.badRssiCount * 2 + mWifiInfo.lowRssiCount ; 3048 3049 if (PDBG) loge(" badRSSI count" + Integer.toString(mWifiInfo.badRssiCount) 3050 + " lowRSSI count" + Integer.toString(mWifiInfo.lowRssiCount) 3051 + " --> score " + Integer.toString(score)); 3052 3053 3054 if (isHighRSSI) { 3055 score += 5; 3056 if (PDBG) loge(" isHighRSSI ---> score=" + Integer.toString(score)); 3057 } 3058 3059 //sanitize boundaries 3060 if (score > NetworkAgent.WIFI_BASE_SCORE) 3061 score = NetworkAgent.WIFI_BASE_SCORE; 3062 if (score < 0) 3063 score = 0; 3064 3065 //report score 3066 if (score != mWifiInfo.score) { 3067 if (DBG) { 3068 loge("calculateWifiScore() report new score " + Integer.toString(score)); 3069 } 3070 mWifiInfo.score = score; 3071 if (mNetworkAgent != null) { 3072 mNetworkAgent.sendNetworkScore(score); 3073 } 3074 } 3075 } 3076 3077 public double getTxPacketRate() { 3078 if (mWifiInfo != null) { 3079 return mWifiInfo.txSuccessRate; 3080 } 3081 return -1; 3082 } 3083 3084 public double getRxPacketRate() { 3085 if (mWifiInfo != null) { 3086 return mWifiInfo.rxSuccessRate; 3087 } 3088 return -1; 3089 } 3090 3091 /** 3092 * Fetch TX packet counters on current connection 3093 */ 3094 private void fetchPktcntNative(RssiPacketCountInfo info) { 3095 String pktcntPoll = mWifiNative.pktcntPoll(); 3096 3097 if (pktcntPoll != null) { 3098 String[] lines = pktcntPoll.split("\n"); 3099 for (String line : lines) { 3100 String[] prop = line.split("="); 3101 if (prop.length < 2) continue; 3102 try { 3103 if (prop[0].equals("TXGOOD")) { 3104 info.txgood = Integer.parseInt(prop[1]); 3105 } else if (prop[0].equals("TXBAD")) { 3106 info.txbad = Integer.parseInt(prop[1]); 3107 } 3108 } catch (NumberFormatException e) { 3109 // Ignore 3110 } 3111 } 3112 } 3113 } 3114 3115 private boolean isProvisioned(LinkProperties lp) { 3116 // LinkProperties#isProvisioned returns true even if all we have is an IPv4 address and no 3117 // connectivity. This turns out not to be very useful, because we can't distinguish it from 3118 // a state where we have an IPv4 address assigned to the interface but are still running 3119 // DHCP. 3120 // TODO: Fix LinkProperties and remove this function. 3121 if (mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 3122 return lp.hasIPv4Address(); 3123 } else { 3124 return (lp.hasIPv4Address() && lp.hasIPv4DefaultRoute() && lp.hasIPv4DnsServer()) || 3125 (lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute() && lp.hasIPv6DnsServer()); 3126 } 3127 } 3128 3129 /** 3130 * Updates mLinkProperties by merging information from various sources. 3131 * 3132 * This is needed because the information in mLinkProperties comes from multiple sources (DHCP, 3133 * netlink, static configuration, ...). When one of these sources of information has updated 3134 * link properties, we can't just assign them to mLinkProperties or we'd lose track of the 3135 * information that came from other sources. Instead, when one of those sources has new 3136 * information, we update the object that tracks the information from that source and then 3137 * call this method to apply the change to mLinkProperties. 3138 * 3139 * The information in mLinkProperties is currently obtained as follows: 3140 * - Interface name: set in the constructor. 3141 * - IPv4 and IPv6 addresses: netlink, passed in by mNetlinkTracker. 3142 * - IPv4 routes, DNS servers, and domains: DHCP. 3143 * - IPv6 routes and DNS servers: netlink, passed in by mNetlinkTracker. 3144 * - HTTP proxy: the wifi config store. 3145 */ 3146 private void updateLinkProperties(int reason) { 3147 LinkProperties newLp = new LinkProperties(); 3148 3149 // Interface name and proxy are locally configured. 3150 newLp.setInterfaceName(mInterfaceName); 3151 newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); 3152 3153 // IPv4/v6 addresses, IPv6 routes and IPv6 DNS servers come from netlink. 3154 LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties(); 3155 newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses()); 3156 for (RouteInfo route : netlinkLinkProperties.getRoutes()) { 3157 newLp.addRoute(route); 3158 } 3159 for (InetAddress dns : netlinkLinkProperties.getDnsServers()) { 3160 newLp.addDnsServer(dns); 3161 } 3162 3163 // IPv4 routes, DNS servers and domains come from mDhcpResults. 3164 synchronized (mDhcpResultsLock) { 3165 // Even when we're using static configuration, we don't need to look at the config 3166 // store, because static IP configuration also populates mDhcpResults. 3167 if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) { 3168 LinkProperties lp = mDhcpResults.linkProperties; 3169 for (RouteInfo route : lp.getRoutes()) { 3170 newLp.addRoute(route); 3171 } 3172 for (InetAddress dns : lp.getDnsServers()) { 3173 newLp.addDnsServer(dns); 3174 } 3175 newLp.setDomains(lp.getDomains()); 3176 } 3177 } 3178 3179 final boolean linkChanged = !newLp.equals(mLinkProperties); 3180 final boolean wasProvisioned = isProvisioned(mLinkProperties); 3181 final boolean isProvisioned = isProvisioned(newLp); 3182 final DetailedState detailedState = getNetworkDetailedState(); 3183 3184 if (linkChanged) { 3185 if (DBG) { 3186 log("Link configuration changed for netId: " + mLastNetworkId 3187 + " old: " + mLinkProperties + " new: " + newLp); 3188 } 3189 mLinkProperties = newLp; 3190 mLinkProperties.setTcpBufferSizes(TCP_BUFFER_SIZES_WIFI); 3191 if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); 3192 } 3193 3194 if (DBG) { 3195 StringBuilder sb = new StringBuilder(); 3196 sb.append("updateLinkProperties nid: " + mLastNetworkId); 3197 sb.append(" state: " + detailedState); 3198 sb.append(" reason: " + smToString(reason)); 3199 3200 if (mLinkProperties != null) { 3201 if (mLinkProperties.hasIPv4Address()) { 3202 sb.append(" v4"); 3203 } 3204 if (mLinkProperties.hasGlobalIPv6Address()) { 3205 sb.append(" v6"); 3206 } 3207 if (mLinkProperties.hasIPv4DefaultRoute()) { 3208 sb.append(" v4r"); 3209 } 3210 if (mLinkProperties.hasIPv6DefaultRoute()) { 3211 sb.append(" v6r"); 3212 } 3213 if (mLinkProperties.hasIPv4DnsServer()) { 3214 sb.append(" v4dns"); 3215 } 3216 if (mLinkProperties.hasIPv6DnsServer()) { 3217 sb.append(" v6dns"); 3218 } 3219 if (isProvisioned) { 3220 sb.append(" isprov"); 3221 } 3222 } 3223 loge(sb.toString()); 3224 } 3225 3226 // If we just configured or lost IP configuration, do the needful. 3227 // We don't just call handleSuccessfulIpConfiguration() or handleIpConfigurationLost() 3228 // here because those should only be called if we're attempting to connect or already 3229 // connected, whereas updateLinkProperties can be called at any time. 3230 switch (reason) { 3231 case DhcpStateMachine.DHCP_SUCCESS: 3232 case CMD_STATIC_IP_SUCCESS: 3233 // IPv4 provisioning succeded. Advance to connected state. 3234 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 3235 if (!isProvisioned) { 3236 // Can never happen unless DHCP reports success but isProvisioned thinks the 3237 // resulting configuration is invalid (e.g., no IPv4 address, or the state in 3238 // mLinkProperties is out of sync with reality, or there's a bug in this code). 3239 // TODO: disconnect here instead. If our configuration is not usable, there's no 3240 // point in staying connected, and if mLinkProperties is out of sync with 3241 // reality, that will cause problems in the future. 3242 loge("IPv4 config succeeded, but not provisioned"); 3243 } 3244 break; 3245 3246 case DhcpStateMachine.DHCP_FAILURE: 3247 // DHCP failed. If we're not already provisioned, give up and disconnect. 3248 // If we're already provisioned (e.g., IPv6-only network), stay connected. 3249 if (!isProvisioned) { 3250 sendMessage(CMD_IP_CONFIGURATION_LOST); 3251 } else { 3252 // DHCP failed, but we're provisioned (e.g., if we're on an IPv6-only network). 3253 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 3254 3255 // To be sure we don't get stuck with a non-working network if all we had is 3256 // IPv4, remove the IPv4 address from the interface (since we're using DHCP, 3257 // and DHCP failed). If we had an IPv4 address before, the deletion of the 3258 // address will cause a CMD_UPDATE_LINKPROPERTIES. If the IPv4 address was 3259 // necessary for provisioning, its deletion will cause us to disconnect. 3260 // 3261 // This should never happen, because a DHCP failure will have empty DhcpResults 3262 // and thus empty LinkProperties, and isProvisioned will not return true if 3263 // we're using DHCP and don't have an IPv4 default route. So for now it's only 3264 // here for extra redundancy. However, it will increase robustness if we move 3265 // to getting IPv4 routes from netlink as well. 3266 loge("DHCP failure: provisioned, should not happen! Clearing IPv4 address."); 3267 try { 3268 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 3269 ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0")); 3270 ifcg.setInterfaceUp(); 3271 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 3272 } catch (RemoteException e) { 3273 sendMessage(CMD_IP_CONFIGURATION_LOST); 3274 } 3275 } 3276 break; 3277 3278 case CMD_STATIC_IP_FAILURE: 3279 // Static configuration was invalid, or an error occurred in applying it. Give up. 3280 sendMessage(CMD_IP_CONFIGURATION_LOST); 3281 break; 3282 3283 case CMD_UPDATE_LINKPROPERTIES: 3284 // IP addresses, DNS servers, etc. changed. Act accordingly. 3285 if (wasProvisioned && !isProvisioned) { 3286 // We no longer have a usable network configuration. Disconnect. 3287 sendMessage(CMD_IP_CONFIGURATION_LOST); 3288 } else if (!wasProvisioned && isProvisioned) { 3289 // We have a usable IPv6-only config. Advance to connected state. 3290 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 3291 } 3292 if (linkChanged && getNetworkDetailedState() == DetailedState.CONNECTED) { 3293 // If anything has changed and we're already connected, send out a notification. 3294 sendLinkConfigurationChangedBroadcast(); 3295 } 3296 break; 3297 } 3298 } 3299 3300 /** 3301 * Clears all our link properties. 3302 */ 3303 private void clearLinkProperties() { 3304 // If the network used DHCP, clear the LinkProperties we stored in the config store. 3305 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 3306 mWifiConfigStore.clearLinkProperties(mLastNetworkId); 3307 } 3308 3309 // Clear the link properties obtained from DHCP and netlink. 3310 synchronized (mDhcpResultsLock) { 3311 if (mDhcpResults != null && mDhcpResults.linkProperties != null) { 3312 mDhcpResults.linkProperties.clear(); 3313 } 3314 } 3315 mNetlinkTracker.clearLinkProperties(); 3316 3317 // Now clear the merged link properties. 3318 mLinkProperties.clear(); 3319 if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); 3320 } 3321 3322 /** 3323 * try to update default route MAC address. 3324 */ 3325 private String updateDefaultRouteMacAddress(int timeout) { 3326 String address = null; 3327 for (RouteInfo route : mLinkProperties.getRoutes()) { 3328 if (route.isDefaultRoute() && route.hasGateway()) { 3329 InetAddress gateway = route.getGateway(); 3330 if (gateway instanceof Inet4Address) { 3331 if (PDBG) { 3332 loge("updateDefaultRouteMacAddress found Ipv4 default :" 3333 + gateway.getHostAddress()); 3334 } 3335 address = macAddressFromRoute(gateway.getHostAddress()); 3336 /* The gateway's MAC address is known */ 3337 if ((address == null) && (timeout > 0)) { 3338 boolean reachable = false; 3339 try { 3340 reachable = gateway.isReachable(timeout); 3341 } catch (Exception e) { 3342 loge("updateDefaultRouteMacAddress exception reaching :" 3343 + gateway.getHostAddress()); 3344 3345 } finally { 3346 if (reachable == true) { 3347 3348 address = macAddressFromRoute(gateway.getHostAddress()); 3349 if (PDBG) { 3350 loge("updateDefaultRouteMacAddress reachable (tried again) :" 3351 + gateway.getHostAddress() + " found " + address); 3352 } 3353 } 3354 } 3355 } 3356 if (address != null) { 3357 mWifiConfigStore.setLinkProperties(mLastNetworkId, 3358 new LinkProperties(mLinkProperties)); 3359 mWifiConfigStore.setDefaultGwMacAddress(mLastNetworkId, address); 3360 3361 } 3362 } 3363 } 3364 } 3365 return address; 3366 } 3367 3368 private void sendScanResultsAvailableBroadcast() { 3369 noteScanEnd(); 3370 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 3371 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3372 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 3373 } 3374 3375 private void sendRssiChangeBroadcast(final int newRssi) { 3376 try { 3377 mBatteryStats.noteWifiRssiChanged(newRssi); 3378 } catch (RemoteException e) { 3379 // Won't happen. 3380 } 3381 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); 3382 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3383 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); 3384 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3385 } 3386 3387 private void sendNetworkStateChangeBroadcast(String bssid) { 3388 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); 3389 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3390 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 3391 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties)); 3392 if (bssid != null) 3393 intent.putExtra(WifiManager.EXTRA_BSSID, bssid); 3394 if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK || 3395 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { 3396 intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo)); 3397 } 3398 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3399 } 3400 3401 private void sendLinkConfigurationChangedBroadcast() { 3402 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); 3403 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3404 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); 3405 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 3406 } 3407 3408 private void sendSupplicantConnectionChangedBroadcast(boolean connected) { 3409 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 3410 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3411 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); 3412 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 3413 } 3414 3415 /** 3416 * Record the detailed state of a network. 3417 * @param state the new {@code DetailedState} 3418 */ 3419 private void setNetworkDetailedState(NetworkInfo.DetailedState state) { 3420 boolean hidden = false; 3421 3422 if (linkDebouncing || isRoaming()) { 3423 // There is generally a confusion in the system about colluding 3424 // WiFi Layer 2 state (as reported by supplicant) and the Network state 3425 // which leads to multiple confusion. 3426 // 3427 // If link is de-bouncing or roaming, we already have an IP address 3428 // as well we were connected and are doing L2 cycles of 3429 // reconnecting or renewing IP address to check that we still have it 3430 // This L2 link flapping should ne be reflected into the Network state 3431 // which is the state of the WiFi Network visible to Layer 3 and applications 3432 // Note that once debouncing and roaming are completed, we will 3433 // set the Network state to where it should be, or leave it as unchanged 3434 // 3435 hidden = true; 3436 } 3437 if (DBG) { 3438 log("setDetailed state, old =" 3439 + mNetworkInfo.getDetailedState() + " and new state=" + state 3440 + " hidden=" + hidden); 3441 } 3442 if (hidden == true) return; 3443 3444 if (state != mNetworkInfo.getDetailedState()) { 3445 mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); 3446 if (mNetworkAgent != null) { 3447 mNetworkAgent.sendNetworkInfo(mNetworkInfo); 3448 } 3449 } 3450 } 3451 3452 private DetailedState getNetworkDetailedState() { 3453 return mNetworkInfo.getDetailedState(); 3454 } 3455 3456 3457 private SupplicantState handleSupplicantStateChange(Message message) { 3458 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 3459 SupplicantState state = stateChangeResult.state; 3460 // Supplicant state change 3461 // [31-13] Reserved for future use 3462 // [8 - 0] Supplicant state (as defined in SupplicantState.java) 3463 // 50023 supplicant_state_changed (custom|1|5) 3464 mWifiInfo.setSupplicantState(state); 3465 // Network id is only valid when we start connecting 3466 if (SupplicantState.isConnecting(state)) { 3467 mWifiInfo.setNetworkId(stateChangeResult.networkId); 3468 } else { 3469 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 3470 } 3471 3472 mWifiInfo.setBSSID(stateChangeResult.BSSID); 3473 mWifiInfo.setSSID(stateChangeResult.wifiSsid); 3474 3475 mSupplicantStateTracker.sendMessage(Message.obtain(message)); 3476 3477 return state; 3478 } 3479 3480 /** 3481 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 3482 * using the interface, stopping DHCP & disabling interface 3483 */ 3484 private void handleNetworkDisconnect() { 3485 if (DBG) log("handleNetworkDisconnect: Stopping DHCP and clearing IP" 3486 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 3487 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 3488 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 3489 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 3490 3491 stopDhcp(); 3492 3493 try { 3494 mNwService.clearInterfaceAddresses(mInterfaceName); 3495 mNwService.disableIpv6(mInterfaceName); 3496 } catch (Exception e) { 3497 loge("Failed to clear addresses or disable ipv6" + e); 3498 } 3499 3500 /* Reset data structures */ 3501 mWifiInfo.reset(); 3502 linkDebouncing = false; 3503 /* Reset roaming parameters */ 3504 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 3505 fullBandConnectedTimeIntervalMilli = 20 * 1000; // Start scans at 20 seconds interval 3506 3507 setNetworkDetailedState(DetailedState.DISCONNECTED); 3508 if (mNetworkAgent != null) { 3509 mNetworkAgent.sendNetworkInfo(mNetworkInfo); 3510 mNetworkAgent = null; 3511 } 3512 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 3513 3514 /* Clear network properties */ 3515 clearLinkProperties(); 3516 3517 /* Cend event to CM & network change broadcast */ 3518 sendNetworkStateChangeBroadcast(mLastBssid); 3519 3520 /* Cancel auto roam requests */ 3521 autoRoamSetBSSID(mLastNetworkId, "any"); 3522 3523 mLastBssid= null; 3524 registerDisconnected(); 3525 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 3526 } 3527 3528 private void handleSupplicantConnectionLoss() { 3529 /* Socket connection can be lost when we do a graceful shutdown 3530 * or when the driver is hung. Ensure supplicant is stopped here. 3531 */ 3532 mWifiMonitor.killSupplicant(mP2pSupported); 3533 mWifiNative.closeSupplicantConnection(); 3534 sendSupplicantConnectionChangedBroadcast(false); 3535 setWifiState(WIFI_STATE_DISABLED); 3536 } 3537 3538 void handlePreDhcpSetup() { 3539 mDhcpActive = true; 3540 if (!mBluetoothConnectionActive) { 3541 /* 3542 * There are problems setting the Wi-Fi driver's power 3543 * mode to active when bluetooth coexistence mode is 3544 * enabled or sense. 3545 * <p> 3546 * We set Wi-Fi to active mode when 3547 * obtaining an IP address because we've found 3548 * compatibility issues with some routers with low power 3549 * mode. 3550 * <p> 3551 * In order for this active power mode to properly be set, 3552 * we disable coexistence mode until we're done with 3553 * obtaining an IP address. One exception is if we 3554 * are currently connected to a headset, since disabling 3555 * coexistence would interrupt that connection. 3556 */ 3557 // Disable the coexistence mode 3558 mWifiNative.setBluetoothCoexistenceMode( 3559 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); 3560 } 3561 3562 // Disable power save and suspend optimizations during DHCP 3563 // Note: The order here is important for now. Brcm driver changes 3564 // power settings when we control suspend mode optimizations. 3565 // TODO: Remove this comment when the driver is fixed. 3566 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false); 3567 mWifiNative.setPowerSave(false); 3568 3569 stopBatchedScan(); 3570 WifiNative.pauseScan(); 3571 3572 /* P2p discovery breaks dhcp, shut it down in order to get through this */ 3573 Message msg = new Message(); 3574 msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY; 3575 msg.arg1 = WifiP2pServiceImpl.ENABLED; 3576 msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE; 3577 msg.obj = mDhcpStateMachine; 3578 mWifiP2pChannel.sendMessage(msg); 3579 } 3580 3581 3582 void startDhcp() { 3583 if (mDhcpStateMachine == null) { 3584 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 3585 mContext, WifiStateMachine.this, mInterfaceName); 3586 3587 } 3588 mDhcpStateMachine.registerForPreDhcpNotification(); 3589 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); 3590 } 3591 3592 void renewDhcp() { 3593 if (mDhcpStateMachine == null) { 3594 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 3595 mContext, WifiStateMachine.this, mInterfaceName); 3596 3597 } 3598 mDhcpStateMachine.registerForPreDhcpNotification(); 3599 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_RENEW_DHCP); 3600 } 3601 3602 void stopDhcp() { 3603 if (mDhcpStateMachine != null) { 3604 /* In case we were in middle of DHCP operation restore back powermode */ 3605 handlePostDhcpSetup(); 3606 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); 3607 } 3608 } 3609 3610 void handlePostDhcpSetup() { 3611 /* Restore power save and suspend optimizations */ 3612 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true); 3613 mWifiNative.setPowerSave(true); 3614 3615 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED); 3616 3617 // Set the coexistence mode back to its default value 3618 mWifiNative.setBluetoothCoexistenceMode( 3619 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); 3620 3621 mDhcpActive = false; 3622 3623 startBatchedScan(); 3624 WifiNative.restartScan(); 3625 } 3626 3627 private void handleIPv4Success(DhcpResults dhcpResults, int reason) { 3628 3629 if (PDBG) { 3630 loge("wifistatemachine handleIPv4Success <" + dhcpResults.toString() 3631 + "> linkaddress num " + dhcpResults.linkProperties.getLinkAddresses().size()); 3632 for (LinkAddress linkAddress : dhcpResults.linkProperties.getLinkAddresses()) { 3633 loge("link address " + linkAddress.toString()); 3634 } 3635 } 3636 3637 synchronized (mDhcpResultsLock) { 3638 mDhcpResults = dhcpResults; 3639 } 3640 LinkProperties linkProperties = dhcpResults.linkProperties; 3641 mWifiConfigStore.setLinkProperties(mLastNetworkId, new LinkProperties(linkProperties)); 3642 InetAddress addr = null; 3643 Iterator<InetAddress> addrs = linkProperties.getAddresses().iterator(); 3644 if (addrs.hasNext()) { 3645 addr = addrs.next(); 3646 } 3647 3648 if (isRoaming()) { 3649 if (addr instanceof Inet4Address) { 3650 int previousAddress = mWifiInfo.getIpAddress(); 3651 int newAddress = NetworkUtils.inetAddressToInt((Inet4Address)addr); 3652 if (previousAddress != newAddress) { 3653 loge("handleIPv4Success, roaming and address changed" + 3654 mWifiInfo + " got: " + addr); 3655 } else { 3656 3657 } 3658 } else { 3659 loge("handleIPv4Success, roaming and didnt get an IPv4 address" + 3660 addr.toString()); 3661 3662 3663 } 3664 } 3665 mWifiInfo.setInetAddress(addr); 3666 mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint()); 3667 updateLinkProperties(reason); 3668 } 3669 3670 private void handleSuccessfulIpConfiguration() { 3671 mLastSignalLevel = -1; // Force update of signal strength 3672 WifiConfiguration c = getCurrentWifiConfiguration(); 3673 // Reset IP failure tracking 3674 if (c != null) { 3675 c.numConnectionFailures = 0; 3676 } 3677 } 3678 3679 private void handleIPv4Failure(int reason) { 3680 synchronized(mDhcpResultsLock) { 3681 if (mDhcpResults != null && mDhcpResults.linkProperties != null) { 3682 mDhcpResults.linkProperties.clear(); 3683 } 3684 } 3685 if (PDBG) { 3686 loge("wifistatemachine handleIPv4Failure"); 3687 } 3688 updateLinkProperties(reason); 3689 } 3690 3691 private void handleIpConfigurationLost() { 3692 mWifiInfo.setInetAddress(null); 3693 mWifiInfo.setMeteredHint(false); 3694 3695 mWifiConfigStore.handleSSIDStateChange(mLastNetworkId, false, "DHCP FAILURE"); 3696 3697 /* DHCP times out after about 30 seconds, we do a 3698 * disconnect thru supplicant, we will let autojoin retry connecting to the network 3699 */ 3700 mWifiNative.disconnect(); 3701 } 3702 3703 /* Current design is to not set the config on a running hostapd but instead 3704 * stop and start tethering when user changes config on a running access point 3705 * 3706 * TODO: Add control channel setup through hostapd that allows changing config 3707 * on a running daemon 3708 */ 3709 private void startSoftApWithConfig(final WifiConfiguration config) { 3710 // Start hostapd on a separate thread 3711 new Thread(new Runnable() { 3712 public void run() { 3713 try { 3714 mNwService.startAccessPoint(config, mInterfaceName); 3715 } catch (Exception e) { 3716 loge("Exception in softap start " + e); 3717 try { 3718 mNwService.stopAccessPoint(mInterfaceName); 3719 mNwService.startAccessPoint(config, mInterfaceName); 3720 } catch (Exception e1) { 3721 loge("Exception in softap re-start " + e1); 3722 sendMessage(CMD_START_AP_FAILURE); 3723 return; 3724 } 3725 } 3726 if (DBG) log("Soft AP start successful"); 3727 sendMessage(CMD_START_AP_SUCCESS); 3728 } 3729 }).start(); 3730 } 3731 3732 3733 /* 3734 * Read a MAC address in /proc/arp/table, used by WifistateMachine 3735 * so as to record MAC address of default gateway. 3736 **/ 3737 private String macAddressFromRoute(String ipAddress) { 3738 String macAddress = null; 3739 BufferedReader reader = null; 3740 try { 3741 reader = new BufferedReader(new FileReader("/proc/net/arp")); 3742 3743 // Skip over the line bearing colum titles 3744 String line = reader.readLine(); 3745 3746 while ((line = reader.readLine()) != null) { 3747 String[] tokens = line.split("[ ]+"); 3748 if (tokens.length < 6) { 3749 continue; 3750 } 3751 3752 // ARP column format is 3753 // Address HWType HWAddress Flags Mask IFace 3754 String ip = tokens[0]; 3755 String mac = tokens[3]; 3756 3757 if (ipAddress.equals(ip)) { 3758 macAddress = mac; 3759 break; 3760 } 3761 } 3762 3763 if (macAddress == null) { 3764 loge("Did not find remoteAddress {" + ipAddress + "} in " + 3765 "/proc/net/arp"); 3766 } 3767 3768 } catch (FileNotFoundException e) { 3769 loge("Could not open /proc/net/arp to lookup mac address"); 3770 } catch (IOException e) { 3771 loge("Could not read /proc/net/arp to lookup mac address"); 3772 } finally { 3773 try { 3774 if (reader != null) { 3775 reader.close(); 3776 } 3777 } catch (IOException e) { 3778 // Do nothing 3779 } 3780 } 3781 return macAddress; 3782 3783 } 3784 3785 private class WifiNetworkFactory extends NetworkFactory { 3786 public WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f) { 3787 super(l, c, TAG, f); 3788 } 3789 protected void startNetwork() { 3790 // TODO 3791 // Enter association mode. 3792 } 3793 protected void stopNetwork() { 3794 // TODO 3795 // Stop associating. 3796 } 3797 } 3798 /******************************************************** 3799 * HSM states 3800 *******************************************************/ 3801 3802 class DefaultState extends State { 3803 @Override 3804 public boolean processMessage(Message message) { 3805 logStateAndMessage(message, getClass().getSimpleName()); 3806 3807 switch (message.what) { 3808 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 3809 AsyncChannel ac = (AsyncChannel) message.obj; 3810 if (ac == mWifiP2pChannel) { 3811 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 3812 mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 3813 } else { 3814 loge("WifiP2pService connection failure, error=" + message.arg1); 3815 } 3816 } else { 3817 loge("got HALF_CONNECTED for unknown channel"); 3818 } 3819 break; 3820 } 3821 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 3822 AsyncChannel ac = (AsyncChannel) message.obj; 3823 if (ac == mWifiP2pChannel) { 3824 loge("WifiP2pService channel lost, message.arg1 =" + message.arg1); 3825 //TODO: Re-establish connection to state machine after a delay 3826 // mWifiP2pChannel.connect(mContext, getHandler(), 3827 // mWifiP2pManager.getMessenger()); 3828 } 3829 break; 3830 } 3831 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 3832 mBluetoothConnectionActive = (message.arg1 != 3833 BluetoothAdapter.STATE_DISCONNECTED); 3834 break; 3835 /* Synchronous call returns */ 3836 case CMD_PING_SUPPLICANT: 3837 case CMD_ENABLE_NETWORK: 3838 case CMD_ADD_OR_UPDATE_NETWORK: 3839 case CMD_REMOVE_NETWORK: 3840 case CMD_SAVE_CONFIG: 3841 replyToMessage(message, message.what, FAILURE); 3842 break; 3843 case CMD_GET_CAPABILITY_FREQ: 3844 replyToMessage(message, message.what, null); 3845 break; 3846 case CMD_GET_CONFIGURED_NETWORKS: 3847 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 3848 break; 3849 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS: 3850 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 3851 break; 3852 case CMD_ENABLE_RSSI_POLL: 3853 mEnableRssiPolling = (message.arg1 == 1); 3854 break; 3855 case CMD_ENABLE_BACKGROUND_SCAN: 3856 mEnableBackgroundScan = (message.arg1 == 1); 3857 break; 3858 case CMD_SET_HIGH_PERF_MODE: 3859 if (message.arg1 == 1) { 3860 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false); 3861 } else { 3862 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true); 3863 } 3864 break; 3865 case CMD_BOOT_COMPLETED: 3866 String countryCode = mPersistedCountryCode; 3867 if (TextUtils.isEmpty(countryCode) == false) { 3868 Settings.Global.putString(mContext.getContentResolver(), 3869 Settings.Global.WIFI_COUNTRY_CODE, 3870 countryCode); 3871 // It may be that the state transition that should send this info 3872 // to the driver happened between mPersistedCountryCode getting set 3873 // and now, so simply persisting it here would mean we have sent 3874 // nothing to the driver. Send the cmd so it might be set now. 3875 int sequenceNum = mCountryCodeSequence.incrementAndGet(); 3876 sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE, 3877 sequenceNum, 0, countryCode); 3878 } 3879 3880 checkAndSetConnectivityInstance(); 3881 mNetworkFactory = new WifiNetworkFactory(getHandler().getLooper(), mContext, 3882 NETWORKTYPE, mNetworkCapabilitiesFilter); 3883 mNetworkFactory.setScoreFilter(60); 3884 mCm.registerNetworkFactory(new Messenger(mNetworkFactory), NETWORKTYPE); 3885 break; 3886 case CMD_SET_BATCHED_SCAN: 3887 recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj); 3888 break; 3889 case CMD_POLL_BATCHED_SCAN: 3890 handleBatchedScanPollRequest(); 3891 break; 3892 case CMD_START_NEXT_BATCHED_SCAN: 3893 startNextBatchedScan(); 3894 break; 3895 /* Discard */ 3896 case CMD_START_SCAN: 3897 case CMD_START_SUPPLICANT: 3898 case CMD_STOP_SUPPLICANT: 3899 case CMD_STOP_SUPPLICANT_FAILED: 3900 case CMD_START_DRIVER: 3901 case CMD_STOP_DRIVER: 3902 case CMD_DELAYED_STOP_DRIVER: 3903 case CMD_DRIVER_START_TIMED_OUT: 3904 case CMD_START_AP: 3905 case CMD_START_AP_SUCCESS: 3906 case CMD_START_AP_FAILURE: 3907 case CMD_STOP_AP: 3908 case CMD_TETHER_STATE_CHANGE: 3909 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 3910 case CMD_DISCONNECT: 3911 case CMD_RECONNECT: 3912 case CMD_REASSOCIATE: 3913 case CMD_RELOAD_TLS_AND_RECONNECT: 3914 case WifiMonitor.SUP_CONNECTION_EVENT: 3915 case WifiMonitor.SUP_DISCONNECTION_EVENT: 3916 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3917 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 3918 case WifiMonitor.SCAN_RESULTS_EVENT: 3919 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3920 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 3921 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 3922 case WifiMonitor.WPS_OVERLAP_EVENT: 3923 case CMD_BLACKLIST_NETWORK: 3924 case CMD_CLEAR_BLACKLIST: 3925 case CMD_SET_OPERATIONAL_MODE: 3926 case CMD_SET_COUNTRY_CODE: 3927 case CMD_SET_FREQUENCY_BAND: 3928 case CMD_RSSI_POLL: 3929 case CMD_ENABLE_ALL_NETWORKS: 3930 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 3931 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 3932 /* Handled by WifiApConfigStore */ 3933 case CMD_SET_AP_CONFIG: 3934 case CMD_SET_AP_CONFIG_COMPLETED: 3935 case CMD_REQUEST_AP_CONFIG: 3936 case CMD_RESPONSE_AP_CONFIG: 3937 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 3938 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 3939 case CMD_NO_NETWORKS_PERIODIC_SCAN: 3940 case CMD_DISABLE_P2P_RSP: 3941 case WifiMonitor.SUP_REQUEST_IDENTITY: 3942 case CMD_TEST_NETWORK_DISCONNECT: 3943 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: 3944 case WifiMonitor.SUP_REQUEST_SIM_AUTH: 3945 case CMD_TARGET_BSSID: 3946 break; 3947 case DhcpStateMachine.CMD_ON_QUIT: 3948 mDhcpStateMachine = null; 3949 break; 3950 case CMD_SET_SUSPEND_OPT_ENABLED: 3951 if (message.arg1 == 1) { 3952 mSuspendWakeLock.release(); 3953 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true); 3954 } else { 3955 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false); 3956 } 3957 break; 3958 case WifiMonitor.DRIVER_HUNG_EVENT: 3959 setSupplicantRunning(false); 3960 setSupplicantRunning(true); 3961 break; 3962 case WifiManager.CONNECT_NETWORK: 3963 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 3964 WifiManager.BUSY); 3965 break; 3966 case WifiManager.FORGET_NETWORK: 3967 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 3968 WifiManager.BUSY); 3969 break; 3970 case WifiManager.SAVE_NETWORK: 3971 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 3972 WifiManager.BUSY); 3973 break; 3974 case WifiManager.START_WPS: 3975 replyToMessage(message, WifiManager.WPS_FAILED, 3976 WifiManager.BUSY); 3977 break; 3978 case WifiManager.CANCEL_WPS: 3979 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, 3980 WifiManager.BUSY); 3981 break; 3982 case WifiManager.DISABLE_NETWORK: 3983 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 3984 WifiManager.BUSY); 3985 break; 3986 case WifiManager.RSSI_PKTCNT_FETCH: 3987 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED, 3988 WifiManager.BUSY); 3989 break; 3990 case CMD_GET_ADAPTORS: 3991 if (WifiNative.startHal()) { 3992 List<WifiAdapter> adaptors = new ArrayList<WifiAdapter>(); 3993 int featureSet = WifiNative.getSupportedFeatureSet(); 3994 /* TODO: Get capabilities from adaptors themselves */ 3995 for (int i = 0; i < WifiNative.getInterfaces(); i++) { 3996 String name = WifiNative.getInterfaceName(i); 3997 WifiAdapter adaptor; 3998 if (name.startsWith("wlan")) { 3999 adaptor = new WifiAdapter( 4000 name, featureSet & ~WifiAdapter.WIFI_FEATURE_P2P); 4001 } else if (name.startsWith("p2p")) { 4002 adaptor = new WifiAdapter( 4003 name, featureSet & WifiAdapter.WIFI_FEATURE_P2P); 4004 } else { 4005 logd("Ignoring adaptor with name" + name); 4006 continue; 4007 } 4008 adaptors.add(adaptor); 4009 } 4010 replyToMessage(message, message.what, adaptors); 4011 } else { 4012 List<WifiAdapter> adaptors = new ArrayList<WifiAdapter>(); 4013 replyToMessage(message, message.what, adaptors); 4014 } 4015 break; 4016 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 4017 NetworkInfo info = (NetworkInfo) message.obj; 4018 mP2pConnected.set(info.isConnected()); 4019 break; 4020 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 4021 mTemporarilyDisconnectWifi = (message.arg1 == 1); 4022 replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 4023 break; 4024 /* Link configuration (IP address, DNS, ...) changes notified via netlink */ 4025 case CMD_UPDATE_LINKPROPERTIES: 4026 updateLinkProperties(CMD_UPDATE_LINKPROPERTIES); 4027 break; 4028 case CMD_IP_CONFIGURATION_SUCCESSFUL: 4029 case CMD_IP_CONFIGURATION_LOST: 4030 break; 4031 case CMD_GET_CONNECTION_STATISTICS: 4032 replyToMessage(message, message.what, mWifiConnectionStatistics); 4033 break; 4034 default: 4035 loge("Error! unhandled message" + message); 4036 break; 4037 } 4038 return HANDLED; 4039 } 4040 } 4041 4042 class InitialState extends State { 4043 @Override 4044 public void enter() { 4045 mWifiNative.unloadDriver(); 4046 4047 if (mWifiP2pChannel == null) { 4048 mWifiP2pChannel = new AsyncChannel(); 4049 mWifiP2pChannel.connect(mContext, getHandler(), 4050 mWifiP2pServiceImpl.getP2pStateMachineMessenger()); 4051 } 4052 4053 if (mWifiApConfigChannel == null) { 4054 mWifiApConfigChannel = new AsyncChannel(); 4055 WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore( 4056 mContext, getHandler()); 4057 wifiApConfigStore.loadApConfiguration(); 4058 mWifiApConfigChannel.connectSync(mContext, getHandler(), 4059 wifiApConfigStore.getMessenger()); 4060 } 4061 } 4062 @Override 4063 public boolean processMessage(Message message) { 4064 logStateAndMessage(message, getClass().getSimpleName()); 4065 switch (message.what) { 4066 case CMD_START_SUPPLICANT: 4067 if (mWifiNative.loadDriver()) { 4068 try { 4069 mNwService.wifiFirmwareReload(mInterfaceName, "STA"); 4070 } catch (Exception e) { 4071 loge("Failed to reload STA firmware " + e); 4072 // Continue 4073 } 4074 4075 try { 4076 // A runtime crash can leave the interface up and 4077 // IP addresses configured, and this affects 4078 // connectivity when supplicant starts up. 4079 // Ensure interface is down and we have no IP 4080 // addresses before a supplicant start. 4081 mNwService.setInterfaceDown(mInterfaceName); 4082 mNwService.clearInterfaceAddresses(mInterfaceName); 4083 4084 // Set privacy extensions 4085 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); 4086 4087 // IPv6 is enabled only as long as access point is connected since: 4088 // - IPv6 addresses and routes stick around after disconnection 4089 // - kernel is unaware when connected and fails to start IPv6 negotiation 4090 // - kernel can start autoconfiguration when 802.1x is not complete 4091 mNwService.disableIpv6(mInterfaceName); 4092 } catch (RemoteException re) { 4093 loge("Unable to change interface settings: " + re); 4094 } catch (IllegalStateException ie) { 4095 loge("Unable to change interface settings: " + ie); 4096 } 4097 4098 /* Stop a running supplicant after a runtime restart 4099 * Avoids issues with drivers that do not handle interface down 4100 * on a running supplicant properly. 4101 */ 4102 mWifiMonitor.killSupplicant(mP2pSupported); 4103 if(mWifiNative.startSupplicant(mP2pSupported)) { 4104 setWifiState(WIFI_STATE_ENABLING); 4105 if (DBG) log("Supplicant start successful"); 4106 mWifiMonitor.startMonitoring(); 4107 transitionTo(mSupplicantStartingState); 4108 } else { 4109 loge("Failed to start supplicant!"); 4110 } 4111 } else { 4112 loge("Failed to load driver"); 4113 } 4114 break; 4115 case CMD_START_AP: 4116 if (mWifiNative.loadDriver()) { 4117 setWifiApState(WIFI_AP_STATE_ENABLING); 4118 transitionTo(mSoftApStartingState); 4119 } else { 4120 loge("Failed to load driver for softap"); 4121 } 4122 default: 4123 return NOT_HANDLED; 4124 } 4125 return HANDLED; 4126 } 4127 } 4128 4129 class SupplicantStartingState extends State { 4130 private void initializeWpsDetails() { 4131 String detail; 4132 detail = SystemProperties.get("ro.product.name", ""); 4133 if (!mWifiNative.setDeviceName(detail)) { 4134 loge("Failed to set device name " + detail); 4135 } 4136 detail = SystemProperties.get("ro.product.manufacturer", ""); 4137 if (!mWifiNative.setManufacturer(detail)) { 4138 loge("Failed to set manufacturer " + detail); 4139 } 4140 detail = SystemProperties.get("ro.product.model", ""); 4141 if (!mWifiNative.setModelName(detail)) { 4142 loge("Failed to set model name " + detail); 4143 } 4144 detail = SystemProperties.get("ro.product.model", ""); 4145 if (!mWifiNative.setModelNumber(detail)) { 4146 loge("Failed to set model number " + detail); 4147 } 4148 detail = SystemProperties.get("ro.serialno", ""); 4149 if (!mWifiNative.setSerialNumber(detail)) { 4150 loge("Failed to set serial number " + detail); 4151 } 4152 if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) { 4153 loge("Failed to set WPS config methods"); 4154 } 4155 if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) { 4156 loge("Failed to set primary device type " + mPrimaryDeviceType); 4157 } 4158 } 4159 4160 @Override 4161 public boolean processMessage(Message message) { 4162 logStateAndMessage(message, getClass().getSimpleName()); 4163 4164 switch(message.what) { 4165 case WifiMonitor.SUP_CONNECTION_EVENT: 4166 if (DBG) log("Supplicant connection established"); 4167 setWifiState(WIFI_STATE_ENABLED); 4168 mSupplicantRestartCount = 0; 4169 /* Reset the supplicant state to indicate the supplicant 4170 * state is not known at this time */ 4171 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 4172 /* Initialize data structures */ 4173 mLastBssid = null; 4174 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 4175 mLastSignalLevel = -1; 4176 4177 mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); 4178 mWifiNative.enableSaveConfig(); 4179 mWifiConfigStore.loadAndEnableAllNetworks(); 4180 initializeWpsDetails(); 4181 4182 sendSupplicantConnectionChangedBroadcast(true); 4183 transitionTo(mDriverStartedState); 4184 break; 4185 case WifiMonitor.SUP_DISCONNECTION_EVENT: 4186 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { 4187 loge("Failed to setup control channel, restart supplicant"); 4188 mWifiMonitor.killSupplicant(mP2pSupported); 4189 transitionTo(mInitialState); 4190 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 4191 } else { 4192 loge("Failed " + mSupplicantRestartCount + 4193 " times to start supplicant, unload driver"); 4194 mSupplicantRestartCount = 0; 4195 setWifiState(WIFI_STATE_UNKNOWN); 4196 transitionTo(mInitialState); 4197 } 4198 break; 4199 case CMD_START_SUPPLICANT: 4200 case CMD_STOP_SUPPLICANT: 4201 case CMD_START_AP: 4202 case CMD_STOP_AP: 4203 case CMD_START_DRIVER: 4204 case CMD_STOP_DRIVER: 4205 case CMD_SET_OPERATIONAL_MODE: 4206 case CMD_SET_COUNTRY_CODE: 4207 case CMD_SET_FREQUENCY_BAND: 4208 case CMD_START_PACKET_FILTERING: 4209 case CMD_STOP_PACKET_FILTERING: 4210 deferMessage(message); 4211 break; 4212 default: 4213 return NOT_HANDLED; 4214 } 4215 return HANDLED; 4216 } 4217 } 4218 4219 class SupplicantStartedState extends State { 4220 @Override 4221 public void enter() { 4222 /* Wifi is available as long as we have a connection to supplicant */ 4223 mNetworkInfo.setIsAvailable(true); 4224 if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo); 4225 4226 int defaultInterval = mContext.getResources().getInteger( 4227 R.integer.config_wifi_supplicant_scan_interval); 4228 4229 mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 4230 Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, 4231 defaultInterval); 4232 4233 mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000); 4234 mWifiNative.setExternalSim(true); 4235 4236 if (mFrameworkAutoJoin.get()) { 4237 mWifiNative.enableAutoConnect(false); 4238 } 4239 4240 } 4241 @Override 4242 public boolean processMessage(Message message) { 4243 logStateAndMessage(message, getClass().getSimpleName()); 4244 4245 switch(message.what) { 4246 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ 4247 if (mP2pSupported) { 4248 transitionTo(mWaitForP2pDisableState); 4249 } else { 4250 transitionTo(mSupplicantStoppingState); 4251 } 4252 break; 4253 case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ 4254 loge("Connection lost, restart supplicant"); 4255 handleSupplicantConnectionLoss(); 4256 handleNetworkDisconnect(); 4257 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 4258 if (mP2pSupported) { 4259 transitionTo(mWaitForP2pDisableState); 4260 } else { 4261 transitionTo(mInitialState); 4262 } 4263 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 4264 break; 4265 case WifiMonitor.SCAN_RESULTS_EVENT: 4266 setScanResults(); 4267 sendScanResultsAvailableBroadcast(); 4268 mIsScanOngoing = false; 4269 mIsFullScanOngoing = false; 4270 if (mBufferedScanMsg.size() > 0) 4271 sendMessage(mBufferedScanMsg.remove()); 4272 break; 4273 case CMD_PING_SUPPLICANT: 4274 boolean ok = mWifiNative.ping(); 4275 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 4276 break; 4277 case CMD_GET_CAPABILITY_FREQ: 4278 String freqs = mWifiNative.getFreqCapability(); 4279 replyToMessage(message, message.what, freqs); 4280 break; 4281 case CMD_START_AP: 4282 /* Cannot start soft AP while in client mode */ 4283 loge("Failed to start soft AP with a running supplicant"); 4284 setWifiApState(WIFI_AP_STATE_FAILED); 4285 break; 4286 case CMD_SET_OPERATIONAL_MODE: 4287 mOperationalMode = message.arg1; 4288 break; 4289 case CMD_TARGET_BSSID: 4290 break; 4291 default: 4292 return NOT_HANDLED; 4293 } 4294 return HANDLED; 4295 } 4296 4297 @Override 4298 public void exit() { 4299 mNetworkInfo.setIsAvailable(false); 4300 if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo); 4301 } 4302 } 4303 4304 class SupplicantStoppingState extends State { 4305 @Override 4306 public void enter() { 4307 /* Send any reset commands to supplicant before shutting it down */ 4308 handleNetworkDisconnect(); 4309 if (mDhcpStateMachine != null) { 4310 mDhcpStateMachine.doQuit(); 4311 } 4312 4313 if (DBG) log("stopping supplicant"); 4314 mWifiMonitor.stopSupplicant(); 4315 4316 /* Send ourselves a delayed message to indicate failure after a wait time */ 4317 sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED, 4318 ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS); 4319 setWifiState(WIFI_STATE_DISABLING); 4320 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 4321 } 4322 @Override 4323 public boolean processMessage(Message message) { 4324 logStateAndMessage(message, getClass().getSimpleName()); 4325 4326 switch(message.what) { 4327 case WifiMonitor.SUP_CONNECTION_EVENT: 4328 loge("Supplicant connection received while stopping"); 4329 break; 4330 case WifiMonitor.SUP_DISCONNECTION_EVENT: 4331 if (DBG) log("Supplicant connection lost"); 4332 handleSupplicantConnectionLoss(); 4333 transitionTo(mInitialState); 4334 break; 4335 case CMD_STOP_SUPPLICANT_FAILED: 4336 if (message.arg1 == mSupplicantStopFailureToken) { 4337 loge("Timed out on a supplicant stop, kill and proceed"); 4338 handleSupplicantConnectionLoss(); 4339 transitionTo(mInitialState); 4340 } 4341 break; 4342 case CMD_START_SUPPLICANT: 4343 case CMD_STOP_SUPPLICANT: 4344 case CMD_START_AP: 4345 case CMD_STOP_AP: 4346 case CMD_START_DRIVER: 4347 case CMD_STOP_DRIVER: 4348 case CMD_SET_OPERATIONAL_MODE: 4349 case CMD_SET_COUNTRY_CODE: 4350 case CMD_SET_FREQUENCY_BAND: 4351 case CMD_START_PACKET_FILTERING: 4352 case CMD_STOP_PACKET_FILTERING: 4353 deferMessage(message); 4354 break; 4355 default: 4356 return NOT_HANDLED; 4357 } 4358 return HANDLED; 4359 } 4360 } 4361 4362 class DriverStartingState extends State { 4363 private int mTries; 4364 @Override 4365 public void enter() { 4366 mTries = 1; 4367 /* Send ourselves a delayed message to start driver a second time */ 4368 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 4369 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 4370 } 4371 @Override 4372 public boolean processMessage(Message message) { 4373 logStateAndMessage(message, getClass().getSimpleName()); 4374 4375 switch(message.what) { 4376 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4377 SupplicantState state = handleSupplicantStateChange(message); 4378 /* If suplicant is exiting out of INTERFACE_DISABLED state into 4379 * a state that indicates driver has started, it is ready to 4380 * receive driver commands 4381 */ 4382 if (SupplicantState.isDriverActive(state)) { 4383 transitionTo(mDriverStartedState); 4384 } 4385 break; 4386 case CMD_DRIVER_START_TIMED_OUT: 4387 if (message.arg1 == mDriverStartToken) { 4388 if (mTries >= 2) { 4389 loge("Failed to start driver after " + mTries); 4390 transitionTo(mDriverStoppedState); 4391 } else { 4392 loge("Driver start failed, retrying"); 4393 mWakeLock.acquire(); 4394 mWifiNative.startDriver(); 4395 mWakeLock.release(); 4396 4397 ++mTries; 4398 /* Send ourselves a delayed message to start driver again */ 4399 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 4400 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 4401 } 4402 } 4403 break; 4404 /* Queue driver commands & connection events */ 4405 case CMD_START_DRIVER: 4406 case CMD_STOP_DRIVER: 4407 case WifiMonitor.NETWORK_CONNECTION_EVENT: 4408 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 4409 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 4410 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 4411 case WifiMonitor.WPS_OVERLAP_EVENT: 4412 case CMD_SET_COUNTRY_CODE: 4413 case CMD_SET_FREQUENCY_BAND: 4414 case CMD_START_PACKET_FILTERING: 4415 case CMD_STOP_PACKET_FILTERING: 4416 case CMD_START_SCAN: 4417 case CMD_DISCONNECT: 4418 case CMD_REASSOCIATE: 4419 case CMD_RECONNECT: 4420 deferMessage(message); 4421 break; 4422 default: 4423 return NOT_HANDLED; 4424 } 4425 return HANDLED; 4426 } 4427 } 4428 4429 class DriverStartedState extends State { 4430 @Override 4431 public void enter() { 4432 4433 if (PDBG) { 4434 loge("Driverstarted State enter"); 4435 } 4436 mIsRunning = true; 4437 mInDelayedStop = false; 4438 mDelayedStopCounter++; 4439 updateBatteryWorkSource(null); 4440 /** 4441 * Enable bluetooth coexistence scan mode when bluetooth connection is active. 4442 * When this mode is on, some of the low-level scan parameters used by the 4443 * driver are changed to reduce interference with bluetooth 4444 */ 4445 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 4446 /* set country code */ 4447 setCountryCode(); 4448 /* set frequency band of operation */ 4449 setFrequencyBand(); 4450 /* initialize network state */ 4451 setNetworkDetailedState(DetailedState.DISCONNECTED); 4452 4453 /* Remove any filtering on Multicast v6 at start */ 4454 mWifiNative.stopFilteringMulticastV6Packets(); 4455 4456 /* Reset Multicast v4 filtering state */ 4457 if (mFilteringMulticastV4Packets.get()) { 4458 mWifiNative.startFilteringMulticastV4Packets(); 4459 } else { 4460 mWifiNative.stopFilteringMulticastV4Packets(); 4461 } 4462 4463 mDhcpActive = false; 4464 4465 startBatchedScan(); 4466 4467 if (mOperationalMode != CONNECT_MODE) { 4468 mWifiNative.disconnect(); 4469 mWifiConfigStore.disableAllNetworks(); 4470 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 4471 setWifiState(WIFI_STATE_DISABLED); 4472 } 4473 transitionTo(mScanModeState); 4474 } else { 4475 /* Driver stop may have disabled networks, enable right after start */ 4476 mWifiConfigStore.enableAllNetworks(); 4477 4478 if (DBG) loge("Attempting to reconnect to wifi network .."); 4479 mWifiNative.reconnect(); 4480 4481 // Status pulls in the current supplicant state and network connection state 4482 // events over the monitor connection. This helps framework sync up with 4483 // current supplicant state 4484 mWifiNative.status(); 4485 transitionTo(mDisconnectedState); 4486 } 4487 4488 // We may have missed screen update at boot 4489 if (mScreenBroadcastReceived.get() == false) { 4490 PowerManager powerManager = (PowerManager)mContext.getSystemService( 4491 Context.POWER_SERVICE); 4492 handleScreenStateChanged(powerManager.isScreenOn()); 4493 } else { 4494 // Set the right suspend mode settings 4495 mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0 4496 && mUserWantsSuspendOpt.get()); 4497 } 4498 mWifiNative.setPowerSave(true); 4499 4500 if (mP2pSupported) { 4501 if (mOperationalMode == CONNECT_MODE) { 4502 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); 4503 } else { 4504 // P2P statemachine starts in disabled state, and is not enabled until 4505 // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to 4506 // keep it disabled. 4507 } 4508 } 4509 4510 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 4511 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4512 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED); 4513 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 4514 4515 if (PDBG) { 4516 loge("Driverstarted State enter done"); 4517 } 4518 } 4519 4520 @Override 4521 public boolean processMessage(Message message) { 4522 logStateAndMessage(message, getClass().getSimpleName()); 4523 4524 switch(message.what) { 4525 case CMD_START_SCAN: 4526 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 4527 break; 4528 case CMD_SET_BATCHED_SCAN: 4529 if (recordBatchedScanSettings(message.arg1, message.arg2, 4530 (Bundle)message.obj)) { 4531 if (mBatchedScanSettings != null) { 4532 startBatchedScan(); 4533 } else { 4534 stopBatchedScan(); 4535 } 4536 } 4537 break; 4538 case CMD_SET_COUNTRY_CODE: 4539 String country = (String) message.obj; 4540 final boolean persist = (message.arg2 == 1); 4541 final int sequence = message.arg1; 4542 if (sequence != mCountryCodeSequence.get()) { 4543 if (DBG) log("set country code ignored due to sequnce num"); 4544 break; 4545 } 4546 if (DBG) log("set country code " + country); 4547 if (persist) { 4548 mPersistedCountryCode = country; 4549 Settings.Global.putString(mContext.getContentResolver(), 4550 Settings.Global.WIFI_COUNTRY_CODE, 4551 country); 4552 } 4553 country = country.toUpperCase(Locale.ROOT); 4554 if (mLastSetCountryCode == null 4555 || country.equals(mLastSetCountryCode) == false) { 4556 if (mWifiNative.setCountryCode(country)) { 4557 mLastSetCountryCode = country; 4558 } else { 4559 loge("Failed to set country code " + country); 4560 } 4561 } 4562 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.SET_COUNTRY_CODE, country); 4563 break; 4564 case CMD_SET_FREQUENCY_BAND: 4565 int band = message.arg1; 4566 if (DBG) log("set frequency band " + band); 4567 if (mWifiNative.setBand(band)) { 4568 4569 if (PDBG) loge("did set frequency band " + band); 4570 4571 mFrequencyBand.set(band); 4572 // Flush old data - like scan results 4573 mWifiNative.bssFlush(); 4574 // Fetch the latest scan results when frequency band is set 4575 if (mFrameworkAutoJoin.get()) 4576 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 4577 else 4578 startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP, null); 4579 if (PDBG) loge("done set frequency band " + band); 4580 4581 } else { 4582 loge("Failed to set frequency band " + band); 4583 } 4584 break; 4585 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 4586 mBluetoothConnectionActive = (message.arg1 != 4587 BluetoothAdapter.STATE_DISCONNECTED); 4588 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 4589 break; 4590 case CMD_STOP_DRIVER: 4591 int mode = message.arg1; 4592 4593 /* Already doing a delayed stop */ 4594 if (mInDelayedStop) { 4595 if (DBG) log("Already in delayed stop"); 4596 break; 4597 } 4598 /* disconnect right now, but leave the driver running for a bit */ 4599 mWifiConfigStore.disableAllNetworks(); 4600 4601 mInDelayedStop = true; 4602 mDelayedStopCounter++; 4603 if (DBG) log("Delayed stop message " + mDelayedStopCounter); 4604 4605 /* send regular delayed shut down */ 4606 Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); 4607 driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); 4608 mDriverStopIntent = PendingIntent.getBroadcast(mContext, 4609 DRIVER_STOP_REQUEST, driverStopIntent, 4610 PendingIntent.FLAG_UPDATE_CURRENT); 4611 4612 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 4613 + mDriverStopDelayMs, mDriverStopIntent); 4614 break; 4615 case CMD_START_DRIVER: 4616 if (mInDelayedStop) { 4617 mInDelayedStop = false; 4618 mDelayedStopCounter++; 4619 mAlarmManager.cancel(mDriverStopIntent); 4620 if (DBG) log("Delayed stop ignored due to start"); 4621 if (mOperationalMode == CONNECT_MODE) { 4622 mWifiConfigStore.enableAllNetworks(); 4623 } 4624 } 4625 break; 4626 case CMD_DELAYED_STOP_DRIVER: 4627 if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter); 4628 if (message.arg1 != mDelayedStopCounter) break; 4629 if (getCurrentState() != mDisconnectedState) { 4630 mWifiNative.disconnect(); 4631 handleNetworkDisconnect(); 4632 } 4633 mWakeLock.acquire(); 4634 mWifiNative.stopDriver(); 4635 mWakeLock.release(); 4636 if (mP2pSupported) { 4637 transitionTo(mWaitForP2pDisableState); 4638 } else { 4639 transitionTo(mDriverStoppingState); 4640 } 4641 break; 4642 case CMD_START_PACKET_FILTERING: 4643 if (message.arg1 == MULTICAST_V6) { 4644 mWifiNative.startFilteringMulticastV6Packets(); 4645 } else if (message.arg1 == MULTICAST_V4) { 4646 mWifiNative.startFilteringMulticastV4Packets(); 4647 } else { 4648 loge("Illegal arugments to CMD_START_PACKET_FILTERING"); 4649 } 4650 break; 4651 case CMD_STOP_PACKET_FILTERING: 4652 if (message.arg1 == MULTICAST_V6) { 4653 mWifiNative.stopFilteringMulticastV6Packets(); 4654 } else if (message.arg1 == MULTICAST_V4) { 4655 mWifiNative.stopFilteringMulticastV4Packets(); 4656 } else { 4657 loge("Illegal arugments to CMD_STOP_PACKET_FILTERING"); 4658 } 4659 break; 4660 case CMD_SET_SUSPEND_OPT_ENABLED: 4661 if (message.arg1 == 1) { 4662 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true); 4663 mSuspendWakeLock.release(); 4664 } else { 4665 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false); 4666 } 4667 break; 4668 case CMD_SET_HIGH_PERF_MODE: 4669 if (message.arg1 == 1) { 4670 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false); 4671 } else { 4672 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true); 4673 } 4674 break; 4675 case CMD_ENABLE_TDLS: 4676 if (message.obj != null) { 4677 String remoteAddress = (String) message.obj; 4678 boolean enable = (message.arg1 == 1); 4679 mWifiNative.startTdls(remoteAddress, enable); 4680 } 4681 break; 4682 default: 4683 return NOT_HANDLED; 4684 } 4685 return HANDLED; 4686 } 4687 @Override 4688 public void exit() { 4689 mIsRunning = false; 4690 updateBatteryWorkSource(null); 4691 mScanResults = new ArrayList<ScanResult>(); 4692 4693 stopBatchedScan(); 4694 4695 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 4696 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4697 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 4698 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 4699 noteScanEnd(); // wrap up any pending request. 4700 mBufferedScanMsg.clear(); 4701 4702 mLastSetCountryCode = null; 4703 } 4704 } 4705 4706 class WaitForP2pDisableState extends State { 4707 private State mTransitionToState; 4708 @Override 4709 public void enter() { 4710 switch (getCurrentMessage().what) { 4711 case WifiMonitor.SUP_DISCONNECTION_EVENT: 4712 mTransitionToState = mInitialState; 4713 break; 4714 case CMD_DELAYED_STOP_DRIVER: 4715 mTransitionToState = mDriverStoppingState; 4716 break; 4717 case CMD_STOP_SUPPLICANT: 4718 mTransitionToState = mSupplicantStoppingState; 4719 break; 4720 default: 4721 mTransitionToState = mDriverStoppingState; 4722 break; 4723 } 4724 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ); 4725 } 4726 @Override 4727 public boolean processMessage(Message message) { 4728 logStateAndMessage(message, getClass().getSimpleName()); 4729 4730 switch(message.what) { 4731 case WifiStateMachine.CMD_DISABLE_P2P_RSP: 4732 transitionTo(mTransitionToState); 4733 break; 4734 /* Defer wifi start/shut and driver commands */ 4735 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4736 case CMD_START_SUPPLICANT: 4737 case CMD_STOP_SUPPLICANT: 4738 case CMD_START_AP: 4739 case CMD_STOP_AP: 4740 case CMD_START_DRIVER: 4741 case CMD_STOP_DRIVER: 4742 case CMD_SET_OPERATIONAL_MODE: 4743 case CMD_SET_COUNTRY_CODE: 4744 case CMD_SET_FREQUENCY_BAND: 4745 case CMD_START_PACKET_FILTERING: 4746 case CMD_STOP_PACKET_FILTERING: 4747 case CMD_START_SCAN: 4748 case CMD_DISCONNECT: 4749 case CMD_REASSOCIATE: 4750 case CMD_RECONNECT: 4751 deferMessage(message); 4752 break; 4753 default: 4754 return NOT_HANDLED; 4755 } 4756 return HANDLED; 4757 } 4758 } 4759 4760 class DriverStoppingState extends State { 4761 @Override 4762 public boolean processMessage(Message message) { 4763 logStateAndMessage(message, getClass().getSimpleName()); 4764 4765 switch(message.what) { 4766 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4767 SupplicantState state = handleSupplicantStateChange(message); 4768 if (state == SupplicantState.INTERFACE_DISABLED) { 4769 transitionTo(mDriverStoppedState); 4770 } 4771 break; 4772 /* Queue driver commands */ 4773 case CMD_START_DRIVER: 4774 case CMD_STOP_DRIVER: 4775 case CMD_SET_COUNTRY_CODE: 4776 case CMD_SET_FREQUENCY_BAND: 4777 case CMD_START_PACKET_FILTERING: 4778 case CMD_STOP_PACKET_FILTERING: 4779 case CMD_START_SCAN: 4780 case CMD_DISCONNECT: 4781 case CMD_REASSOCIATE: 4782 case CMD_RECONNECT: 4783 deferMessage(message); 4784 break; 4785 default: 4786 return NOT_HANDLED; 4787 } 4788 return HANDLED; 4789 } 4790 } 4791 4792 class DriverStoppedState extends State { 4793 @Override 4794 public boolean processMessage(Message message) { 4795 logStateAndMessage(message, getClass().getSimpleName()); 4796 switch (message.what) { 4797 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4798 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 4799 SupplicantState state = stateChangeResult.state; 4800 // A WEXT bug means that we can be back to driver started state 4801 // unexpectedly 4802 if (SupplicantState.isDriverActive(state)) { 4803 transitionTo(mDriverStartedState); 4804 } 4805 break; 4806 case CMD_START_DRIVER: 4807 mWakeLock.acquire(); 4808 mWifiNative.startDriver(); 4809 mWakeLock.release(); 4810 transitionTo(mDriverStartingState); 4811 break; 4812 default: 4813 return NOT_HANDLED; 4814 } 4815 return HANDLED; 4816 } 4817 } 4818 4819 class ScanModeState extends State { 4820 private int mLastOperationMode; 4821 @Override 4822 public void enter() { 4823 mLastOperationMode = mOperationalMode; 4824 } 4825 @Override 4826 public boolean processMessage(Message message) { 4827 logStateAndMessage(message, getClass().getSimpleName()); 4828 4829 switch(message.what) { 4830 case CMD_SET_OPERATIONAL_MODE: 4831 if (message.arg1 == CONNECT_MODE) { 4832 4833 if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 4834 setWifiState(WIFI_STATE_ENABLED); 4835 // Load and re-enable networks when going back to enabled state 4836 // This is essential for networks to show up after restore 4837 mWifiConfigStore.loadAndEnableAllNetworks(); 4838 mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P); 4839 } else { 4840 mWifiConfigStore.enableAllNetworks(); 4841 } 4842 4843 mWifiNative.reconnect(); 4844 4845 mOperationalMode = CONNECT_MODE; 4846 transitionTo(mDisconnectedState); 4847 } else { 4848 // Nothing to do 4849 return HANDLED; 4850 } 4851 break; 4852 // Handle scan. All the connection related commands are 4853 // handled only in ConnectModeState 4854 case CMD_START_SCAN: 4855 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 4856 break; 4857 default: 4858 return NOT_HANDLED; 4859 } 4860 return HANDLED; 4861 } 4862 } 4863 4864 4865 String smToString(Message message) { 4866 return smToString(message.what); 4867 } 4868 4869 String smToString(int what) { 4870 String s = "unknown"; 4871 switch (what) { 4872 case WifiMonitor.DRIVER_HUNG_EVENT: 4873 s = "DRIVER_HUNG_EVENT"; 4874 break; 4875 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 4876 s = "AsyncChannel.CMD_CHANNEL_HALF_CONNECTED"; 4877 break; 4878 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 4879 s = "AsyncChannel.CMD_CHANNEL_DISCONNECTED"; 4880 break; 4881 case CMD_SET_FREQUENCY_BAND: 4882 s = "CMD_SET_FREQUENCY_BAND"; 4883 break; 4884 case CMD_DELAYED_NETWORK_DISCONNECT: 4885 s = "CMD_DELAYED_NETWORK_DISCONNECT"; 4886 break; 4887 case CMD_TEST_NETWORK_DISCONNECT: 4888 s = "CMD_TEST_NETWORK_DISCONNECT"; 4889 break; 4890 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: 4891 s = "CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER"; 4892 break; 4893 case CMD_START_DRIVER: 4894 s = "CMD_START_DRIVER"; 4895 break; 4896 case CMD_STOP_DRIVER: 4897 s = "CMD_STOP_DRIVER"; 4898 break; 4899 case CMD_STOP_SUPPLICANT: 4900 s = "CMD_STOP_SUPPLICANT"; 4901 break; 4902 case CMD_STOP_SUPPLICANT_FAILED: 4903 s = "CMD_STOP_SUPPLICANT_FAILED"; 4904 break; 4905 case CMD_START_SUPPLICANT: 4906 s = "CMD_START_SUPPLICANT"; 4907 break; 4908 case CMD_REQUEST_AP_CONFIG: 4909 s = "CMD_REQUEST_AP_CONFIG"; 4910 break; 4911 case CMD_RESPONSE_AP_CONFIG: 4912 s = "CMD_RESPONSE_AP_CONFIG"; 4913 break; 4914 case CMD_TETHER_STATE_CHANGE: 4915 s = "CMD_TETHER_STATE_CHANGE"; 4916 break; 4917 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 4918 s = "CMD_TETHER_NOTIFICATION_TIMED_OUT"; 4919 break; 4920 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 4921 s = "CMD_BLUETOOTH_ADAPTER_STATE_CHANGE"; 4922 break; 4923 case CMD_ADD_OR_UPDATE_NETWORK: 4924 s = "CMD_ADD_OR_UPDATE_NETWORK"; 4925 break; 4926 case CMD_REMOVE_NETWORK: 4927 s = "CMD_REMOVE_NETWORK"; 4928 break; 4929 case CMD_ENABLE_NETWORK: 4930 s = "CMD_ENABLE_NETWORK"; 4931 break; 4932 case CMD_ENABLE_ALL_NETWORKS: 4933 s = "CMD_ENABLE_ALL_NETWORKS"; 4934 break; 4935 case CMD_AUTO_CONNECT: 4936 s = "CMD_AUTO_CONNECT"; 4937 break; 4938 case CMD_AUTO_ROAM: 4939 s = "CMD_AUTO_ROAM"; 4940 break; 4941 case CMD_BOOT_COMPLETED: 4942 s = "CMD_BOOT_COMPLETED"; 4943 break; 4944 case DhcpStateMachine.CMD_START_DHCP: 4945 s = "CMD_START_DHCP"; 4946 break; 4947 case DhcpStateMachine.CMD_STOP_DHCP: 4948 s = "CMD_STOP_DHCP"; 4949 break; 4950 case DhcpStateMachine.CMD_RENEW_DHCP: 4951 s = "CMD_RENEW_DHCP"; 4952 break; 4953 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 4954 s = "CMD_PRE_DHCP_ACTION"; 4955 break; 4956 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 4957 s = "CMD_POST_DHCP_ACTION"; 4958 break; 4959 case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE: 4960 s = "CMD_PRE_DHCP_ACTION_COMPLETE"; 4961 break; 4962 case DhcpStateMachine.CMD_ON_QUIT: 4963 s = "CMD_ON_QUIT"; 4964 break; 4965 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 4966 s = "WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST"; 4967 break; 4968 case WifiManager.DISABLE_NETWORK: 4969 s = "WifiManager.DISABLE_NETWORK"; 4970 break; 4971 case CMD_BLACKLIST_NETWORK: 4972 s = "CMD_BLACKLIST_NETWORK"; 4973 break; 4974 case CMD_CLEAR_BLACKLIST: 4975 s = "CMD_CLEAR_BLACKLIST"; 4976 break; 4977 case CMD_SAVE_CONFIG: 4978 s = "CMD_SAVE_CONFIG"; 4979 break; 4980 case CMD_GET_CONFIGURED_NETWORKS: 4981 s = "CMD_GET_CONFIGURED_NETWORKS"; 4982 break; 4983 case CMD_GET_ADAPTORS: 4984 s = "CMD_GET_ADAPTORS"; 4985 break; 4986 case CMD_UNWANTED_NETWORK: 4987 s = "CMD_UNWANTED_NETWORK"; 4988 break; 4989 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS: 4990 s = "CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS"; 4991 break; 4992 case CMD_DISCONNECT: 4993 s = "CMD_DISCONNECT"; 4994 break; 4995 case CMD_RECONNECT: 4996 s = "CMD_RECONNECT"; 4997 break; 4998 case CMD_REASSOCIATE: 4999 s = "CMD_REASSOCIATE"; 5000 break; 5001 case CMD_GET_CONNECTION_STATISTICS: 5002 s = "CMD_GET_CONNECTION_STATISTICS"; 5003 break; 5004 case CMD_SET_HIGH_PERF_MODE: 5005 s = "CMD_SET_HIGH_PERF_MODE"; 5006 break; 5007 case CMD_SET_COUNTRY_CODE: 5008 s = "CMD_SET_COUNTRY_CODE"; 5009 break; 5010 case CMD_ENABLE_RSSI_POLL: 5011 s = "CMD_ENABLE_RSSI_POLL"; 5012 break; 5013 case CMD_RSSI_POLL: 5014 s = "CMD_RSSI_POLL"; 5015 break; 5016 case CMD_START_PACKET_FILTERING: 5017 s = "CMD_START_PACKET_FILTERING"; 5018 break; 5019 case CMD_STOP_PACKET_FILTERING: 5020 s = "CMD_STOP_PACKET_FILTERING"; 5021 break; 5022 case CMD_SET_SUSPEND_OPT_ENABLED: 5023 s = "CMD_SET_SUSPEND_OPT_ENABLED"; 5024 break; 5025 case CMD_NO_NETWORKS_PERIODIC_SCAN: 5026 s = "CMD_NO_NETWORKS_PERIODIC_SCAN"; 5027 break; 5028 case CMD_SET_BATCHED_SCAN: 5029 s = "CMD_SET_BATCHED_SCAN"; 5030 break; 5031 case CMD_START_NEXT_BATCHED_SCAN: 5032 s = "CMD_START_NEXT_BATCHED_SCAN"; 5033 break; 5034 case CMD_POLL_BATCHED_SCAN: 5035 s = "CMD_POLL_BATCHED_SCAN"; 5036 break; 5037 case CMD_UPDATE_LINKPROPERTIES: 5038 s = "CMD_UPDATE_LINKPROPERTIES"; 5039 break; 5040 case CMD_RELOAD_TLS_AND_RECONNECT: 5041 s = "CMD_RELOAD_TLS_AND_RECONNECT"; 5042 break; 5043 case WifiManager.CONNECT_NETWORK: 5044 s = "CONNECT_NETWORK"; 5045 break; 5046 case WifiManager.SAVE_NETWORK: 5047 s = "SAVE_NETWORK"; 5048 break; 5049 case WifiManager.FORGET_NETWORK: 5050 s = "FORGET_NETWORK"; 5051 break; 5052 case WifiMonitor.SUP_CONNECTION_EVENT: 5053 s = "SUP_CONNECTION_EVENT"; 5054 break; 5055 case WifiMonitor.SUP_DISCONNECTION_EVENT: 5056 s = "SUP_DISCONNECTION_EVENT"; 5057 break; 5058 case WifiMonitor.SCAN_RESULTS_EVENT: 5059 s = "SCAN_RESULTS_EVENT"; 5060 break; 5061 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5062 s = "SUPPLICANT_STATE_CHANGE_EVENT"; 5063 break; 5064 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 5065 s = "AUTHENTICATION_FAILURE_EVENT"; 5066 break; 5067 case WifiMonitor.SSID_TEMP_DISABLED: 5068 s = "SSID_TEMP_DISABLED"; 5069 break; 5070 case WifiMonitor.SSID_REENABLED: 5071 s = "SSID_REENABLED"; 5072 break; 5073 case WifiMonitor.WPS_SUCCESS_EVENT: 5074 s = "WPS_SUCCESS_EVENT"; 5075 break; 5076 case WifiMonitor.WPS_FAIL_EVENT: 5077 s = "WPS_FAIL_EVENT"; 5078 break; 5079 case WifiMonitor.SUP_REQUEST_IDENTITY: 5080 s = "SUP_REQUEST_IDENTITY"; 5081 break; 5082 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5083 s = "NETWORK_CONNECTION_EVENT"; 5084 break; 5085 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 5086 s = "NETWORK_DISCONNECTION_EVENT"; 5087 break; 5088 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 5089 s = "ASSOCIATION_REJECTION_EVENT"; 5090 break; 5091 case CMD_SET_OPERATIONAL_MODE: 5092 s = "CMD_SET_OPERATIONAL_MODE"; 5093 break; 5094 case CMD_START_SCAN: 5095 s = "CMD_START_SCAN"; 5096 break; 5097 case CMD_ENABLE_BACKGROUND_SCAN: 5098 s = "CMD_ENABLE_BACKGROUND_SCAN"; 5099 break; 5100 case CMD_DISABLE_P2P_RSP: 5101 s = "CMD_DISABLE_P2P_RSP"; 5102 break; 5103 case CMD_DISABLE_P2P_REQ: 5104 s = "CMD_DISABLE_P2P_REQ"; 5105 break; 5106 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 5107 s = "GOOD_LINK_DETECTED"; 5108 break; 5109 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 5110 s = "POOR_LINK_DETECTED"; 5111 break; 5112 case WifiP2pServiceImpl.GROUP_CREATING_TIMED_OUT: 5113 s = "GROUP_CREATING_TIMED_OUT"; 5114 break; 5115 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 5116 s = "P2P_CONNECTION_CHANGED"; 5117 break; 5118 case WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE: 5119 s = "P2P.DISCONNECT_WIFI_RESPONSE"; 5120 break; 5121 case WifiP2pServiceImpl.SET_MIRACAST_MODE: 5122 s = "P2P.SET_MIRACAST_MODE"; 5123 break; 5124 case WifiP2pServiceImpl.BLOCK_DISCOVERY: 5125 s = "P2P.BLOCK_DISCOVERY"; 5126 break; 5127 case WifiP2pServiceImpl.SET_COUNTRY_CODE: 5128 s = "P2P.SET_COUNTRY_CODE"; 5129 break; 5130 case WifiManager.CANCEL_WPS: 5131 s = "CANCEL_WPS"; 5132 break; 5133 case WifiManager.CANCEL_WPS_FAILED: 5134 s = "CANCEL_WPS_FAILED"; 5135 break; 5136 case WifiManager.CANCEL_WPS_SUCCEDED: 5137 s = "CANCEL_WPS_SUCCEDED"; 5138 break; 5139 case WifiManager.START_WPS: 5140 s = "START_WPS"; 5141 break; 5142 case WifiManager.START_WPS_SUCCEEDED: 5143 s = "START_WPS_SUCCEEDED"; 5144 break; 5145 case WifiManager.WPS_FAILED: 5146 s = "WPS_FAILED"; 5147 break; 5148 case WifiManager.WPS_COMPLETED: 5149 s = "WPS_COMPLETED"; 5150 break; 5151 case WifiManager.RSSI_PKTCNT_FETCH: 5152 s = "RSSI_PKTCNT_FETCH"; 5153 break; 5154 case CMD_IP_CONFIGURATION_LOST: 5155 s = "CMD_IP_CONFIGURATION_LOST"; 5156 break; 5157 case CMD_IP_CONFIGURATION_SUCCESSFUL: 5158 s = "CMD_IP_CONFIGURATION_SUCCESSFUL"; 5159 break; 5160 case CMD_STATIC_IP_SUCCESS: 5161 s = "CMD_STATIC_IP_SUCCESSFUL"; 5162 break; 5163 case CMD_STATIC_IP_FAILURE: 5164 s = "CMD_STATIC_IP_FAILURE"; 5165 break; 5166 case DhcpStateMachine.DHCP_SUCCESS: 5167 s = "DHCP_SUCCESS"; 5168 break; 5169 case DhcpStateMachine.DHCP_FAILURE: 5170 s = "DHCP_FAILURE"; 5171 break; 5172 case CMD_TARGET_BSSID: 5173 s = "CMD_TARGET_BSSID"; 5174 break; 5175 default: 5176 s = "what:" + Integer.toString(what); 5177 break; 5178 } 5179 return s; 5180 } 5181 5182 void registerConnected() { 5183 if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 5184 long now_ms = System.currentTimeMillis(); 5185 // We are switching away from this configuration, 5186 // hence record the time we were connected last 5187 WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 5188 if (config != null) { 5189 config.lastConnected = System.currentTimeMillis(); 5190 } 5191 } 5192 } 5193 5194 void registerDisconnected() { 5195 if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 5196 long now_ms = System.currentTimeMillis(); 5197 // We are switching away from this configuration, 5198 // hence record the time we were connected last 5199 WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 5200 if (config != null) { 5201 config.lastDisconnected = System.currentTimeMillis(); 5202 } 5203 } 5204 } 5205 5206 WifiConfiguration getCurrentWifiConfiguration() { 5207 if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) { 5208 return null; 5209 } 5210 return mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 5211 } 5212 5213 String getCurrentBSSID() { 5214 if (linkDebouncing) { 5215 return null; 5216 } 5217 return mLastBssid; 5218 } 5219 5220 class ConnectModeState extends State { 5221 @Override 5222 public boolean processMessage(Message message) { 5223 WifiConfiguration config; 5224 int netId; 5225 boolean ok; 5226 String bssid; 5227 String ssid; 5228 NetworkUpdateResult result; 5229 logStateAndMessage(message, getClass().getSimpleName()); 5230 5231 switch(message.what) { 5232 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 5233 didBlackListBSSID = false; 5234 bssid = (String)message.obj; 5235 if (bssid == null || TextUtils.isEmpty(bssid)) { 5236 // If BSSID is null, use the target roam BSSID 5237 bssid = mTargetRoamBSSID; 5238 } 5239 if (bssid != null) { 5240 // If we have a BSSID, tell configStore to black list it 5241 didBlackListBSSID = mWifiConfigStore.handleBSSIDBlackList(mLastNetworkId, bssid, false); 5242 } 5243 mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT); 5244 break; 5245 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 5246 mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT); 5247 break; 5248 case WifiMonitor.SSID_TEMP_DISABLED: 5249 case WifiMonitor.SSID_REENABLED: 5250 String substr = (String)message.obj; 5251 String en = message.what == WifiMonitor.SSID_TEMP_DISABLED ? 5252 "temp-disabled" : "re-enabled"; 5253 loge("ConnectModeState SSID state=" + en + " nid=" 5254 + Integer.toString(message.arg1) + " [" + substr + "]"); 5255 mWifiConfigStore.handleSSIDStateChange(message.arg1, message.what == 5256 WifiMonitor.SSID_REENABLED, substr); 5257 break; 5258 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5259 SupplicantState state = handleSupplicantStateChange(message); 5260 // A driver/firmware hang can now put the interface in a down state. 5261 // We detect the interface going down and recover from it 5262 if (!SupplicantState.isDriverActive(state)) { 5263 if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 5264 handleNetworkDisconnect(); 5265 } 5266 log("Detected an interface down, restart driver"); 5267 transitionTo(mDriverStoppedState); 5268 sendMessage(CMD_START_DRIVER); 5269 break; 5270 } 5271 5272 // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT 5273 // when authentication times out after a successful connection, 5274 // we can figure this from the supplicant state. If supplicant 5275 // state is DISCONNECTED, but the mNetworkInfo says we are not 5276 // disconnected, we need to handle a disconnection 5277 if (!linkDebouncing && state == SupplicantState.DISCONNECTED && 5278 mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 5279 if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect"); 5280 handleNetworkDisconnect(); 5281 transitionTo(mDisconnectedState); 5282 } 5283 break; 5284 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 5285 if (message.arg1 == 1) { 5286 mWifiNative.disconnect(); 5287 mTemporarilyDisconnectWifi = true; 5288 } else { 5289 mWifiNative.reconnect(); 5290 mTemporarilyDisconnectWifi = false; 5291 } 5292 break; 5293 case CMD_ADD_OR_UPDATE_NETWORK: 5294 config = (WifiConfiguration) message.obj; 5295 replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, 5296 mWifiConfigStore.addOrUpdateNetwork(config)); 5297 break; 5298 case CMD_REMOVE_NETWORK: 5299 ok = mWifiConfigStore.removeNetwork(message.arg1); 5300 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 5301 break; 5302 case CMD_ENABLE_NETWORK: 5303 boolean others = message.arg2 == 1; 5304 // Tell autojoin the user did try to select to that network 5305 // However, do NOT persist the choice by bumping the priority of the network 5306 if (others) { 5307 mWifiAutoJoinController. 5308 updateConfigurationHistory(message.arg1, true, false); 5309 // Set the last selected configuration so as to allow the system to 5310 // stick the last user choice without persisting the choice 5311 mWifiConfigStore.setLastSelectedConfiguration(message.arg1); 5312 5313 // Remember time of last connection attempt 5314 lastConnectAttempt = System.currentTimeMillis(); 5315 5316 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 5317 } 5318 // Cancel auto roam requests 5319 autoRoamSetBSSID(message.arg1, "any"); 5320 5321 ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); 5322 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 5323 break; 5324 case CMD_ENABLE_ALL_NETWORKS: 5325 long time = android.os.SystemClock.elapsedRealtime(); 5326 if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { 5327 mWifiConfigStore.enableAllNetworks(); 5328 mLastEnableAllNetworksTime = time; 5329 } 5330 break; 5331 case WifiManager.DISABLE_NETWORK: 5332 if (mWifiConfigStore.disableNetwork(message.arg1, 5333 WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) { 5334 replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); 5335 } else { 5336 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 5337 WifiManager.ERROR); 5338 } 5339 break; 5340 case CMD_BLACKLIST_NETWORK: 5341 mWifiNative.addToBlacklist((String)message.obj); 5342 break; 5343 case CMD_CLEAR_BLACKLIST: 5344 mWifiNative.clearBlacklist(); 5345 break; 5346 case CMD_SAVE_CONFIG: 5347 ok = mWifiConfigStore.saveConfig(); 5348 5349 if (DBG) loge("wifistatemachine did save config " + ok); 5350 replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); 5351 5352 // Inform the backup manager about a data change 5353 IBackupManager ibm = IBackupManager.Stub.asInterface( 5354 ServiceManager.getService(Context.BACKUP_SERVICE)); 5355 if (ibm != null) { 5356 try { 5357 ibm.dataChanged("com.android.providers.settings"); 5358 } catch (Exception e) { 5359 // Try again later 5360 } 5361 } 5362 break; 5363 case CMD_GET_CONFIGURED_NETWORKS: 5364 replyToMessage(message, message.what, 5365 mWifiConfigStore.getConfiguredNetworks()); 5366 break; 5367 case WifiMonitor.SUP_REQUEST_IDENTITY: 5368 // Supplicant lacks credentials to connect to that network, hence black list 5369 ssid = (String) message.obj; 5370 5371 if (targetWificonfiguration != null && ssid != null 5372 && targetWificonfiguration.SSID != null 5373 && targetWificonfiguration.SSID.equals("\"" + ssid + "\"")) { 5374 mWifiConfigStore.handleSSIDStateChange(targetWificonfiguration.networkId, 5375 false, "AUTH_FAILED no identity"); 5376 } 5377 // Disconnect now, as we don't have any way to fullfill the supplicant request. 5378 mWifiConfigStore.setLastSelectedConfiguration 5379 (WifiConfiguration.INVALID_NETWORK_ID); 5380 mWifiNative.disconnect(); 5381 break; 5382 case WifiMonitor.SUP_REQUEST_SIM_AUTH: 5383 logd("Received SUP_REQUEST_SIM_AUTH"); 5384 SimAuthRequestData requestData = (SimAuthRequestData) message.obj; 5385 if (requestData != null) { 5386 if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) { 5387 handleGsmAuthRequest(requestData); 5388 } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA) { 5389 handle3GAuthRequest(requestData); 5390 } 5391 } else { 5392 loge("Invalid sim auth request"); 5393 } 5394 break; 5395 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS: 5396 replyToMessage(message, message.what, 5397 mWifiConfigStore.getPrivilegedConfiguredNetworks()); 5398 break; 5399 /* Do a redundant disconnect without transition */ 5400 case CMD_DISCONNECT: 5401 mWifiConfigStore.setLastSelectedConfiguration 5402 (WifiConfiguration.INVALID_NETWORK_ID); 5403 mWifiNative.disconnect(); 5404 break; 5405 case CMD_RECONNECT: 5406 lastConnectAttempt = System.currentTimeMillis(); 5407 mWifiNative.reconnect(); 5408 break; 5409 case CMD_REASSOCIATE: 5410 lastConnectAttempt = System.currentTimeMillis(); 5411 mWifiNative.reassociate(); 5412 break; 5413 case CMD_RELOAD_TLS_AND_RECONNECT: 5414 if (mWifiConfigStore.needsUnlockedKeyStore()) { 5415 logd("Reconnecting to give a chance to un-connected TLS networks"); 5416 mWifiNative.disconnect(); 5417 lastConnectAttempt = System.currentTimeMillis(); 5418 mWifiNative.reconnect(); 5419 } 5420 break; 5421 case CMD_AUTO_ROAM: 5422 return HANDLED; 5423 case CMD_AUTO_CONNECT: 5424 /* Work Around: wpa_supplicant can get in a bad state where it returns a non 5425 * associated status to the STATUS command but somehow-someplace still thinks 5426 * it is associated and thus will ignore select/reconnect command with 5427 * following message: 5428 * "Already associated with the selected network - do nothing" 5429 * 5430 * Hence, sends a disconnect to supplicant first. 5431 */ 5432 mWifiNative.disconnect(); 5433 5434 /* connect command coming from auto-join */ 5435 config = (WifiConfiguration) message.obj; 5436 netId = message.arg1; 5437 int roam = message.arg2; 5438 loge("CMD_AUTO_CONNECT sup state " 5439 + mSupplicantStateTracker.getSupplicantStateName() 5440 + " my state " + getCurrentState().getName() 5441 + " nid=" + Integer.toString(netId) 5442 + " roam=" + Integer.toString(roam)); 5443 if (config == null) { 5444 loge("AUTO_CONNECT and no config, bail out..."); 5445 break; 5446 } 5447 5448 /* Make sure we cancel any previous roam request */ 5449 autoRoamSetBSSID(config, "any"); 5450 5451 /* Save the network config */ 5452 loge("CMD_AUTO_CONNECT will save config -> " + config.SSID 5453 + " nid=" + Integer.toString(netId)); 5454 result = mWifiConfigStore.saveNetwork(config); 5455 netId = result.getNetworkId(); 5456 loge("CMD_AUTO_CONNECT did save config -> " 5457 + " nid=" + Integer.toString(netId)); 5458 5459 if (mWifiConfigStore.selectNetwork(netId) && 5460 mWifiNative.reconnect()) { 5461 lastConnectAttempt = System.currentTimeMillis(); 5462 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 5463 // We selected a better config, 5464 // maybe because we could not see the last user 5465 // selection, then forget it. We will remember the selection 5466 // only if it was persisted. 5467 mWifiConfigStore. 5468 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 5469 5470 mAutoRoaming = roam; 5471 if (isRoaming() || linkDebouncing) { 5472 transitionTo(mRoamingState); 5473 } else { 5474 transitionTo(mDisconnectingState); 5475 } 5476 } else { 5477 loge("Failed to connect config: " + config + " netId: " + netId); 5478 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 5479 WifiManager.ERROR); 5480 break; 5481 } 5482 break; 5483 case WifiManager.CONNECT_NETWORK: 5484 /** 5485 * The connect message can contain a network id passed as arg1 on message or 5486 * or a config passed as obj on message. 5487 * For a new network, a config is passed to create and connect. 5488 * For an existing network, a network id is passed 5489 */ 5490 netId = message.arg1; 5491 config = (WifiConfiguration) message.obj; 5492 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 5493 5494 if (config == null) { 5495 loge("CONNECT_NETWORK id=" + Integer.toString(netId) + " " 5496 + mSupplicantStateTracker.getSupplicantStateName() + " my state " 5497 + getCurrentState().getName()); 5498 } else { 5499 loge("CONNECT_NETWORK id=" + Integer.toString(netId) 5500 + " config=" + config.SSID 5501 + " cnid=" + config.networkId 5502 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 5503 + " my state " + getCurrentState().getName()); 5504 } 5505 5506 autoRoamSetBSSID(netId, "any"); 5507 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 5508 5509 /* Save the network config */ 5510 if (config != null) { 5511 result = mWifiConfigStore.saveNetwork(config); 5512 netId = result.getNetworkId(); 5513 } 5514 if (mFrameworkAutoJoin.get()) { 5515 /* Tell autojoin the user did try to connect to that network */ 5516 mWifiAutoJoinController.updateConfigurationHistory(netId, true, true); 5517 } 5518 mWifiConfigStore.setLastSelectedConfiguration(netId); 5519 5520 if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID 5521 && mLastNetworkId != netId) { 5522 /** Supplicant will ignore the reconnect if we are currently associated, 5523 * hence trigger a disconnect 5524 */ 5525 mWifiNative.disconnect(); 5526 } 5527 5528 if (mWifiConfigStore.selectNetwork(netId) && 5529 mWifiNative.reconnect()) { 5530 lastConnectAttempt = System.currentTimeMillis(); 5531 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 5532 5533 /* The state tracker handles enabling networks upon completion/failure */ 5534 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 5535 replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 5536 /* Expect a disconnection from the old connection */ 5537 transitionTo(mDisconnectingState); 5538 } else { 5539 loge("Failed to connect config: " + config + " netId: " + netId); 5540 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 5541 WifiManager.ERROR); 5542 break; 5543 } 5544 break; 5545 case WifiManager.SAVE_NETWORK: 5546 config = (WifiConfiguration) message.obj; 5547 int nid = config.networkId; 5548 if (config == null) { 5549 loge("SAVE_NETWORK id=" + Integer.toString(nid) 5550 + " " + mSupplicantStateTracker.getSupplicantStateName() 5551 + " my state " + getCurrentState().getName()); 5552 } else { 5553 loge("SAVE_NETWORK id=" + Integer.toString(nid) 5554 + " config=" + config.SSID 5555 + " cnid=" + config.networkId 5556 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 5557 + " my state " + getCurrentState().getName()); 5558 } 5559 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 5560 5561 result = mWifiConfigStore.saveNetwork(config); 5562 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 5563 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 5564 if (VDBG) { 5565 loge("Success save network nid=" 5566 + Integer.toString(result.getNetworkId()) 5567 + " autojoin " + mFrameworkAutoJoin.get()); 5568 } 5569 if (mFrameworkAutoJoin.get()) { 5570 /* Tell autojoin the user did try to modify and save that network, 5571 * and interpret the SAVE_NETWORK as a request to connect */ 5572 mWifiAutoJoinController.updateConfigurationHistory(result.getNetworkId() 5573 ,true, true); 5574 mWifiAutoJoinController.attemptAutoJoin(); 5575 } 5576 } else { 5577 loge("Failed to save network"); 5578 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 5579 WifiManager.ERROR); 5580 } 5581 break; 5582 case WifiManager.FORGET_NETWORK: 5583 if (mWifiConfigStore.forgetNetwork(message.arg1)) { 5584 replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); 5585 } else { 5586 loge("Failed to forget network"); 5587 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 5588 WifiManager.ERROR); 5589 } 5590 break; 5591 case WifiManager.START_WPS: 5592 WpsInfo wpsInfo = (WpsInfo) message.obj; 5593 WpsResult wpsResult; 5594 switch (wpsInfo.setup) { 5595 case WpsInfo.PBC: 5596 wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo); 5597 break; 5598 case WpsInfo.KEYPAD: 5599 wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); 5600 break; 5601 case WpsInfo.DISPLAY: 5602 wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); 5603 break; 5604 default: 5605 wpsResult = new WpsResult(Status.FAILURE); 5606 loge("Invalid setup for WPS"); 5607 break; 5608 } 5609 mWifiConfigStore.setLastSelectedConfiguration 5610 (WifiConfiguration.INVALID_NETWORK_ID); 5611 if (wpsResult.status == Status.SUCCESS) { 5612 replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult); 5613 transitionTo(mWpsRunningState); 5614 } else { 5615 loge("Failed to start WPS with config " + wpsInfo.toString()); 5616 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR); 5617 } 5618 break; 5619 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5620 if (DBG) log("Network connection established"); 5621 mLastNetworkId = message.arg1; 5622 mLastBssid = (String) message.obj; 5623 5624 mWifiInfo.setBSSID(mLastBssid); 5625 mWifiInfo.setNetworkId(mLastNetworkId); 5626 // Send event to CM & network change broadcast 5627 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 5628 sendNetworkStateChangeBroadcast(mLastBssid); 5629 transitionTo(mObtainingIpState); 5630 break; 5631 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 5632 if (DBG) log("ConnectModeState: Network connection lost "); 5633 handleNetworkDisconnect(); 5634 transitionTo(mDisconnectedState); 5635 break; 5636 default: 5637 return NOT_HANDLED; 5638 } 5639 return HANDLED; 5640 } 5641 } 5642 5643 private class WifiNetworkAgent extends NetworkAgent { 5644 public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni, 5645 NetworkCapabilities nc, LinkProperties lp, int score) { 5646 super(l, c, TAG, ni, nc, lp, score); 5647 } 5648 protected void unwanted() { 5649 // Ignore if we're not the current networkAgent. 5650 if (this != mNetworkAgent) return; 5651 // TODO - don't want this network. What to do? 5652 if (DBG) log("WifiNetworkAgent -> Wifi unwanted score " 5653 + Integer.toString(mWifiInfo.score)); 5654 unwantedNetwork(); 5655 } 5656 } 5657 5658 void unwantedNetwork() { 5659 sendMessage(CMD_UNWANTED_NETWORK); 5660 } 5661 5662 boolean startScanForConfiguration(WifiConfiguration config, boolean restrictChannelList) { 5663 HashSet<Integer> channels 5664 = mWifiConfigStore.makeChannelList(config, 5665 ONE_HOUR_MILLI, restrictChannelList); 5666 if (channels != null && channels.size() != 0) { 5667 StringBuilder freqs = new StringBuilder(); 5668 boolean first = true; 5669 for (Integer channel : channels) { 5670 if (!first) 5671 freqs.append(","); 5672 freqs.append(channel.toString()); 5673 first = false; 5674 } 5675 if (DBG) { 5676 loge("WifiStateMachine starting scan with " + freqs); 5677 } 5678 // Call wifi native to start the scan 5679 if (startScanNative( 5680 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, 5681 freqs.toString())) { 5682 // Only count battery consumption if scan request is accepted 5683 noteScanStart(SCAN_ALARM_SOURCE, null); 5684 } 5685 return true; 5686 } else { 5687 return false; 5688 } 5689 } 5690 5691 private static final String TCP_BUFFER_SIZES_WIFI = 5692 "524288,1048576,2097152,262144,524288,1048576"; 5693 5694 class L2ConnectedState extends State { 5695 @Override 5696 public void enter() { 5697 mRssiPollToken++; 5698 if (mEnableRssiPolling) { 5699 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0); 5700 } 5701 if (mNetworkAgent != null) { 5702 loge("Have NetworkAgent when entering L2Connected"); 5703 setNetworkDetailedState(DetailedState.DISCONNECTED); 5704 } 5705 setNetworkDetailedState(DetailedState.CONNECTING); 5706 mLinkProperties.setTcpBufferSizes(TCP_BUFFER_SIZES_WIFI); 5707 5708 mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext, 5709 "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter, 5710 mLinkProperties, 60); 5711 } 5712 5713 @Override 5714 public void exit() { 5715 // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState 5716 // Bug: 15347363 5717 // For paranoia's sake, call handleNetworkDisconnect 5718 // only if BSSID is null or last networkId 5719 // is not invalid. 5720 if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 5721 handleNetworkDisconnect(); 5722 } 5723 } 5724 5725 @Override 5726 public boolean processMessage(Message message) { 5727 logStateAndMessage(message, getClass().getSimpleName()); 5728 5729 switch (message.what) { 5730 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 5731 handlePreDhcpSetup(); 5732 break; 5733 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 5734 handlePostDhcpSetup(); 5735 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 5736 if (DBG) log("WifiStateMachine DHCP successful"); 5737 handleIPv4Success((DhcpResults) message.obj, DhcpStateMachine.DHCP_SUCCESS); 5738 // We advance to mVerifyingLinkState because handleIPv4Success will call 5739 // updateLinkProperties, which then sends CMD_IP_CONFIGURATION_SUCCESSFUL. 5740 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { 5741 if (DBG) { 5742 int count = -1; 5743 WifiConfiguration config = getCurrentWifiConfiguration(); 5744 if (config != null) { 5745 count = config.numConnectionFailures; 5746 } 5747 log("WifiStateMachine DHCP failure count=" + count); 5748 } 5749 handleIPv4Failure(DhcpStateMachine.DHCP_FAILURE); 5750 // As above, we transition to mDisconnectingState via updateLinkProperties. 5751 } 5752 break; 5753 case CMD_IP_CONFIGURATION_SUCCESSFUL: 5754 handleSuccessfulIpConfiguration(); 5755 sendConnectedState(); 5756 transitionTo(mConnectedState); 5757 break; 5758 case CMD_IP_CONFIGURATION_LOST: 5759 handleIpConfigurationLost(); 5760 transitionTo(mDisconnectingState); 5761 break; 5762 case CMD_DISCONNECT: 5763 mWifiNative.disconnect(); 5764 transitionTo(mDisconnectingState); 5765 break; 5766 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 5767 if (message.arg1 == 1) { 5768 mWifiNative.disconnect(); 5769 mTemporarilyDisconnectWifi = true; 5770 transitionTo(mDisconnectingState); 5771 } 5772 break; 5773 case CMD_SET_OPERATIONAL_MODE: 5774 if (message.arg1 != CONNECT_MODE) { 5775 sendMessage(CMD_DISCONNECT); 5776 deferMessage(message); 5777 } 5778 break; 5779 case CMD_SET_COUNTRY_CODE: 5780 deferMessage(message); 5781 break; 5782 case CMD_START_SCAN: 5783 if (DBG) { 5784 loge("WifiStateMachine CMD_START_SCAN source " + message.arg1 5785 + " txSuccessRate="+String.format( "%.2f", mWifiInfo.txSuccessRate) 5786 + " rxSuccessRate="+String.format( "%.2f", mWifiInfo.rxSuccessRate) 5787 + " BSSID=" + mTargetRoamBSSID 5788 + " RSSI=" + mWifiInfo.getRssi()); 5789 } 5790 if (message.arg1 == SCAN_ALARM_SOURCE) { 5791 boolean tryFullBandScan = false; 5792 boolean restrictChannelList = false; 5793 long now_ms = System.currentTimeMillis(); 5794 if (mWifiInfo != null) { 5795 if ((now_ms - lastFullBandConnectedTimeMilli) 5796 > fullBandConnectedTimeIntervalMilli) { 5797 if (DBG) { 5798 loge("WifiStateMachine CMD_START_SCAN try full band scan age=" 5799 + Long.toString(now_ms - lastFullBandConnectedTimeMilli) 5800 + " interval=" + fullBandConnectedTimeIntervalMilli); 5801 } 5802 tryFullBandScan = true; 5803 } 5804 5805 if (mWifiInfo.txSuccessRate > 5 || mWifiInfo.rxSuccessRate > 30) { 5806 // Too much traffic at the interface, hence no full band scan 5807 if (DBG) { 5808 loge("WifiStateMachine CMD_START_SCAN " + 5809 "prevent full band scan due to pkt rate"); 5810 } 5811 tryFullBandScan = false; 5812 } 5813 5814 if (mWifiInfo.txSuccessRate > 5815 mWifiConfigStore.maxTxPacketForNetworkSwitching 5816 || mWifiInfo.rxSuccessRate > 5817 mWifiConfigStore.maxRxPacketForNetworkSwitching) { 5818 // Don't scan if lots of packets are being sent 5819 restrictChannelList = true; 5820 if (mAllowScansWithTraffic == 0) { 5821 if (DBG) { 5822 loge("WifiStateMachine CMD_START_SCAN source " + message.arg1 5823 + " ...and ignore scans" 5824 + " tx=" + String.format("%.2f", mWifiInfo.txSuccessRate) 5825 + " rx=" + String.format("%.2f", mWifiInfo.rxSuccessRate)); 5826 } 5827 return HANDLED; 5828 } 5829 } 5830 } 5831 5832 WifiConfiguration currentConfiguration = getCurrentWifiConfiguration(); 5833 if (currentConfiguration != null) { 5834 if (tryFullBandScan) { 5835 lastFullBandConnectedTimeMilli = now_ms; 5836 if (fullBandConnectedTimeIntervalMilli < 20 * 1000) { 5837 // Paranoia, make sure interval is not less than 20 seconds 5838 fullBandConnectedTimeIntervalMilli = 20 * 1000; 5839 } 5840 if (fullBandConnectedTimeIntervalMilli 5841 < maxFullBandConnectedTimeIntervalMilli) { 5842 // Increase the interval 5843 fullBandConnectedTimeIntervalMilli 5844 = fullBandConnectedTimeIntervalMilli * 3 / 2; 5845 } 5846 handleScanRequest( 5847 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 5848 } else { 5849 if (!startScanForConfiguration( 5850 currentConfiguration, restrictChannelList)) { 5851 if (DBG) { 5852 loge("WifiStateMachine starting scan, " + 5853 " did not find channels"); 5854 handleScanRequest( 5855 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 5856 } 5857 } 5858 } 5859 } 5860 } else { 5861 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 5862 } 5863 break; 5864 /* Ignore connection to same network */ 5865 case WifiManager.CONNECT_NETWORK: 5866 int netId = message.arg1; 5867 if (mWifiInfo.getNetworkId() == netId) { 5868 break; 5869 } 5870 return NOT_HANDLED; 5871 case WifiManager.SAVE_NETWORK: 5872 WifiConfiguration config = (WifiConfiguration) message.obj; 5873 int nid = config.networkId; 5874 if (config == null) { 5875 loge("SAVE_NETWORK-L2 id=" + Integer.toString(nid) 5876 + " " + mSupplicantStateTracker.getSupplicantStateName() 5877 + " my state " + getCurrentState().getName()); 5878 } else { 5879 loge("SAVE_NETWORK-L2 id=" + Integer.toString(nid) 5880 + " SSID=" + config.SSID 5881 + " cnid=" + config.networkId 5882 + " autojoin=" + Integer.toString(config.autoJoinStatus) 5883 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 5884 + " my state " + getCurrentState().getName() 5885 + " uid " + Integer.toString(config.creatorUid)); 5886 } 5887 5888 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 5889 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 5890 if (result.hasIpChanged()) { 5891 // We switched from DHCP to static or from static to DHCP, or the 5892 // static IP address has changed. 5893 log("Reconfiguring IP on connection"); 5894 // TODO: clear addresses and disable IPv6 to simplify obtainingIpState. 5895 transitionTo(mObtainingIpState); 5896 } 5897 if (result.hasProxyChanged()) { 5898 log("Reconfiguring proxy on connection"); 5899 updateLinkProperties(CMD_UPDATE_LINKPROPERTIES); 5900 } 5901 } 5902 5903 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 5904 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 5905 if (VDBG) { 5906 loge("Success save network l2 nid=" 5907 + Integer.toString(result.getNetworkId()) 5908 + " autojoin " + mFrameworkAutoJoin.get()); 5909 } 5910 if (mFrameworkAutoJoin.get()) { 5911 /** 5912 * Tell autojoin the user did try to modify and save that network. 5913 * and interpret the SAVE network 5914 * command as a manual request to connect 5915 * */ 5916 mWifiAutoJoinController.updateConfigurationHistory(config.networkId, 5917 true, true); 5918 mWifiAutoJoinController.attemptAutoJoin(); 5919 } 5920 } else { 5921 loge("Failed to save network"); 5922 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 5923 WifiManager.ERROR); 5924 } 5925 break; 5926 /* Ignore */ 5927 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5928 break; 5929 case CMD_RSSI_POLL: 5930 if (message.arg1 == mRssiPollToken) { 5931 WifiLinkLayerStats stats = null; 5932 // Try a reading L2 stats a couple of time, allow for a few failures 5933 // in case the HAL/drivers are not completely initialized once we get there 5934 if (mWifiLinkLayerStatsSupported > 0) { 5935 stats = mWifiNative.getWifiLinkLayerStats(); 5936 if (stats == null && mWifiLinkLayerStatsSupported > 0) { 5937 mWifiLinkLayerStatsSupported -= 1; 5938 } 5939 } 5940 // Get Info and continue polling 5941 fetchRssiLinkSpeedAndFrequencyNative(); 5942 calculateWifiScore(stats); 5943 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 5944 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 5945 } else { 5946 // Polling has completed 5947 } 5948 break; 5949 case CMD_ENABLE_RSSI_POLL: 5950 mEnableRssiPolling = (message.arg1 == 1); 5951 mRssiPollToken++; 5952 if (mEnableRssiPolling) { 5953 // First poll 5954 fetchRssiLinkSpeedAndFrequencyNative(); 5955 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 5956 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 5957 } 5958 break; 5959 case WifiManager.RSSI_PKTCNT_FETCH: 5960 RssiPacketCountInfo info = new RssiPacketCountInfo(); 5961 fetchRssiLinkSpeedAndFrequencyNative(); 5962 info.rssi = mWifiInfo.getRssi(); 5963 fetchPktcntNative(info); 5964 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info); 5965 break; 5966 case CMD_UNWANTED_NETWORK: 5967 // mWifiConfigStore.handleBadNetworkDisconnectReport(mLastNetworkId, mWifiInfo); 5968 // disconnecting is probably too rough and reduce the chance we recover quickly. 5969 // we should not have to disconnect, instead rely on network stack to send data 5970 // traffic somewhere else but remember that this network is roamable with a 5971 // low wifi score threshold 5972 sendMessage(CMD_DISCONNECT); 5973 break; 5974 case CMD_DELAYED_NETWORK_DISCONNECT: 5975 if (!linkDebouncing) { 5976 // Ignore if we are not debouncing 5977 loge("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore " 5978 + message.arg1); 5979 return HANDLED; 5980 } else { 5981 loge("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect " 5982 + message.arg1); 5983 5984 linkDebouncing = false; 5985 // If we are still debouncing while this message comes, 5986 // it means we were not able to reconnect within the alloted time 5987 // = LINK_FLAPPING_DEBOUNCE_MSEC 5988 // and thus, trigger a real disconnect 5989 handleNetworkDisconnect(); 5990 transitionTo(mDisconnectedState); 5991 } 5992 break; 5993 default: 5994 return NOT_HANDLED; 5995 } 5996 5997 return HANDLED; 5998 } 5999 } 6000 6001 class ObtainingIpState extends State { 6002 @Override 6003 public void enter() { 6004 if (DBG) { 6005 String key = ""; 6006 if (getCurrentWifiConfiguration() != null) { 6007 key = getCurrentWifiConfiguration().configKey(); 6008 } 6009 log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId) 6010 + " " + key + " " 6011 + " roam=" + mAutoRoaming 6012 + " static=" + mWifiConfigStore.isUsingStaticIp(mLastNetworkId) 6013 + " watchdog= " + obtainingIpWatchdogCount); 6014 } 6015 6016 // Reset link Debouncing, indicating we have successfully re-connected to the AP 6017 // We might still be roaming 6018 linkDebouncing = false; 6019 6020 try { 6021 mNwService.enableIpv6(mInterfaceName); 6022 } catch (RemoteException re) { 6023 loge("Failed to enable IPv6: " + re); 6024 } catch (IllegalStateException e) { 6025 loge("Failed to enable IPv6: " + e); 6026 } 6027 6028 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 6029 // TODO: If we're switching between static IP configuration and DHCP, remove the 6030 // static configuration first. 6031 if (isRoaming()) { 6032 renewDhcp(); 6033 } else { 6034 startDhcp(); 6035 } 6036 obtainingIpWatchdogCount++; 6037 loge("Start Dhcp Watchdog " + obtainingIpWatchdogCount); 6038 sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER, 6039 obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC); 6040 } else { 6041 // stop any running dhcp before assigning static IP 6042 stopDhcp(); 6043 DhcpResults dhcpResults = new DhcpResults( 6044 mWifiConfigStore.getLinkProperties(mLastNetworkId)); 6045 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 6046 Iterator<LinkAddress> addrs = 6047 dhcpResults.linkProperties.getLinkAddresses().iterator(); 6048 if (!addrs.hasNext()) { 6049 loge("Static IP lacks address"); 6050 sendMessage(CMD_STATIC_IP_FAILURE); 6051 } else { 6052 ifcg.setLinkAddress(addrs.next()); 6053 ifcg.setInterfaceUp(); 6054 try { 6055 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 6056 if (DBG) log("Static IP configuration succeeded"); 6057 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults); 6058 } catch (RemoteException re) { 6059 loge("Static IP configuration failed: " + re); 6060 sendMessage(CMD_STATIC_IP_FAILURE); 6061 } catch (IllegalStateException e) { 6062 loge("Static IP configuration failed: " + e); 6063 sendMessage(CMD_STATIC_IP_FAILURE); 6064 } 6065 } 6066 } 6067 } 6068 @Override 6069 public boolean processMessage(Message message) { 6070 logStateAndMessage(message, getClass().getSimpleName()); 6071 6072 switch(message.what) { 6073 case CMD_STATIC_IP_SUCCESS: 6074 handleIPv4Success((DhcpResults) message.obj, CMD_STATIC_IP_SUCCESS); 6075 break; 6076 case CMD_STATIC_IP_FAILURE: 6077 handleIPv4Failure(CMD_STATIC_IP_FAILURE); 6078 break; 6079 case CMD_AUTO_CONNECT: 6080 case CMD_AUTO_ROAM: 6081 break; 6082 case WifiManager.SAVE_NETWORK: 6083 deferMessage(message); 6084 break; 6085 /* Defer any power mode changes since we must keep active power mode at DHCP */ 6086 case CMD_SET_HIGH_PERF_MODE: 6087 deferMessage(message); 6088 break; 6089 /* Defer scan request since we should not switch to other channels at DHCP */ 6090 case CMD_START_SCAN: 6091 deferMessage(message); 6092 break; 6093 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: 6094 if (message.arg1 == obtainingIpWatchdogCount) { 6095 loge("ObtainingIpAddress: Watchdog Triggered, count=" 6096 + obtainingIpWatchdogCount); 6097 handleIpConfigurationLost(); 6098 transitionTo(mDisconnectingState); 6099 break; 6100 } 6101 default: 6102 return NOT_HANDLED; 6103 } 6104 return HANDLED; 6105 } 6106 } 6107 6108 class VerifyingLinkState extends State { 6109 @Override 6110 public void enter() { 6111 log(getName() + " enter"); 6112 setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); 6113 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); 6114 sendNetworkStateChangeBroadcast(mLastBssid); 6115 // End roaming 6116 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 6117 } 6118 @Override 6119 public boolean processMessage(Message message) { 6120 logStateAndMessage(message, getClass().getSimpleName()); 6121 6122 switch (message.what) { 6123 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 6124 // Stay here 6125 log(getName() + " POOR_LINK_DETECTED: no transition"); 6126 break; 6127 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 6128 log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); 6129 6130 log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED"); 6131 sendConnectedState(); 6132 transitionTo(mConnectedState); 6133 break; 6134 case CMD_START_SCAN: 6135 deferMessage(message); 6136 break; 6137 default: 6138 if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); 6139 return NOT_HANDLED; 6140 } 6141 return HANDLED; 6142 } 6143 } 6144 6145 private void sendConnectedState() { 6146 // Send out a broadcast with the CAPTIVE_PORTAL_CHECK to preserve 6147 // existing behaviour. The captive portal check really happens after we 6148 // transition into DetailedState.CONNECTED. 6149 setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); 6150 mWifiConfigStore.updateStatus(mLastNetworkId, 6151 DetailedState.CAPTIVE_PORTAL_CHECK); 6152 sendNetworkStateChangeBroadcast(mLastBssid); 6153 6154 setNetworkDetailedState(DetailedState.CONNECTED); 6155 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); 6156 sendNetworkStateChangeBroadcast(mLastBssid); 6157 } 6158 6159 class RoamingState extends State { 6160 @Override 6161 public void enter() { 6162 if (DBG) { 6163 log("RoamingState Enter" 6164 + " mScreenOn=" + mScreenOn ); 6165 } 6166 setScanAlarm(false); 6167 //TODO: actually implement an alarm, but so as to disconnect if roaming fails 6168 } 6169 @Override 6170 public boolean processMessage(Message message) { 6171 logStateAndMessage(message, getClass().getSimpleName()); 6172 6173 switch (message.what) { 6174 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 6175 if (DBG) log("Roaming and Watchdog reports poor link -> ignore"); 6176 return HANDLED; 6177 case CMD_UNWANTED_NETWORK: 6178 if (DBG) log("Roaming and CS doesnt want the network -> ignore"); 6179 return HANDLED; 6180 case CMD_SET_OPERATIONAL_MODE: 6181 if (message.arg1 != CONNECT_MODE) { 6182 deferMessage(message); 6183 } 6184 break; 6185 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6186 /** 6187 * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT 6188 * before NETWORK_DISCONNECTION_EVENT 6189 * And there is an associated BSSID corresponding to our target BSSID, then 6190 * we have missed the network disconnection, transition to mDisconnectedState 6191 * and handle the rest of the events there. 6192 */ 6193 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 6194 if (stateChangeResult.state == SupplicantState.DISCONNECTED 6195 || stateChangeResult.state == SupplicantState.INACTIVE 6196 || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) { 6197 if (DBG) { 6198 log("STATE_CHANGE_EVENT in roaming state " 6199 + stateChangeResult.toString() ); 6200 } 6201 if (stateChangeResult.BSSID != null 6202 && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) { 6203 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 6204 handleNetworkDisconnect(); 6205 } 6206 } 6207 break; 6208 case WifiMonitor.NETWORK_CONNECTION_EVENT: 6209 if (DBG) log("roaming and Network connection established"); 6210 mLastNetworkId = message.arg1; 6211 mLastBssid = (String) message.obj; 6212 mWifiInfo.setBSSID(mLastBssid); 6213 mWifiInfo.setNetworkId(mLastNetworkId); 6214 mWifiConfigStore.handleBSSIDBlackList(mLastNetworkId, mLastBssid, true); 6215 /** 6216 * We already have an IP address, we are going to the ObtainingIpAddress 6217 * state to renew it. Other parts of the system interpret an 6218 * ObtainingIpState change as not having IP address anymore, 6219 * hence, don't send the state change there. */ 6220 // setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 6221 // sendNetworkStateChangeBroadcast(mLastBssid); 6222 transitionTo(mObtainingIpState); 6223 break; 6224 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 6225 // Throw away but only if it correspond to the network we're roaming to 6226 String bssid = (String)message.obj; 6227 if (true) { 6228 String target = ""; 6229 if (mTargetRoamBSSID != null) target = mTargetRoamBSSID; 6230 log("NETWORK_DISCONNECTION_EVENT in roaming state" 6231 + " BSSID=" + bssid 6232 + " target=" + target); 6233 } 6234 if (bssid != null && bssid.equals(mTargetRoamBSSID)) { 6235 handleNetworkDisconnect(); 6236 transitionTo(mDisconnectedState); 6237 } 6238 break; 6239 case WifiMonitor.SSID_TEMP_DISABLED: 6240 // Auth error while roaming 6241 loge("SSID_TEMP_DISABLED nid=" + Integer.toString(mLastNetworkId) 6242 + " id=" + Integer.toString(message.arg1) 6243 + " isRoaming=" + isRoaming() 6244 + " roam=" + Integer.toString(mAutoRoaming)); 6245 if (message.arg1 == mLastNetworkId) { 6246 handleNetworkDisconnect(); 6247 transitionTo(mDisconnectingState); 6248 } 6249 return NOT_HANDLED; 6250 case CMD_START_SCAN: 6251 deferMessage(message); 6252 break; 6253 default: 6254 return NOT_HANDLED; 6255 } 6256 return HANDLED; 6257 } 6258 6259 @Override 6260 public void exit() { 6261 loge("WifiStateMachine: Leaving Roaming state"); 6262 } 6263 } 6264 6265 class ConnectedState extends State { 6266 @Override 6267 public void enter() { 6268 String address; 6269 updateDefaultRouteMacAddress(1000); 6270 if (DBG) { 6271 log("ConnectedState Enter autojoin=" + mFrameworkAutoJoin.get() 6272 + " mScreenOn=" + mScreenOn 6273 + " scanperiod=" + Integer.toString(mConnectedScanPeriodMs) ); 6274 } 6275 if (mFrameworkAutoJoin.get() && mScreenOn) { 6276 mCurrentScanAlarmMs = mConnectedScanPeriodMs; 6277 setScanAlarm(true); 6278 } else { 6279 mCurrentScanAlarmMs = 0; 6280 } 6281 registerConnected(); 6282 lastConnectAttempt = 0; 6283 targetWificonfiguration = null; 6284 // Paranoia 6285 linkDebouncing = false; 6286 6287 // Not roaming anymore 6288 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 6289 6290 if (testNetworkDisconnect) { 6291 testNetworkDisconnectCounter++; 6292 loge("ConnectedState Enter start disconnect test " + 6293 testNetworkDisconnectCounter); 6294 sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT, 6295 testNetworkDisconnectCounter, 0), 15000); 6296 } 6297 } 6298 @Override 6299 public boolean processMessage(Message message) { 6300 logStateAndMessage(message, getClass().getSimpleName()); 6301 6302 switch (message.what) { 6303 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 6304 if (DBG) log("Watchdog reports poor link"); 6305 transitionTo(mVerifyingLinkState); 6306 break; 6307 case CMD_UNWANTED_NETWORK: 6308 mWifiConfigStore.handleBadNetworkDisconnectReport(mLastNetworkId, mWifiInfo); 6309 mWifiNative.disconnect(); 6310 transitionTo(mDisconnectingState); 6311 return HANDLED; 6312 case CMD_TEST_NETWORK_DISCONNECT: 6313 // Force a disconnect 6314 if (message.arg1 == testNetworkDisconnectCounter) { 6315 mWifiNative.disconnect(); 6316 } 6317 break; 6318 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 6319 if (!linkDebouncing && ( 6320 (ScanResult.is24GHz(mWifiInfo.getFrequency()) 6321 && mWifiInfo.getRssi() > 6322 WifiConfiguration.BAD_RSSI_24) 6323 || (ScanResult.is5GHz(mWifiInfo.getFrequency()) 6324 && mWifiInfo.getRssi() > 6325 WifiConfiguration.BAD_RSSI_5))) { 6326 // Start de-bouncing the L2 disconnection: 6327 // this L2 disconnection might be spurious. 6328 // Hence we allow 7 seconds for the state machine to try 6329 // to reconnect, go thru the 6330 // roaming cycle and enter Obtaining IP address 6331 // before signalling the disconnect to ConnectivityService and L3 6332 startScanForConfiguration(getCurrentWifiConfiguration(), false); 6333 linkDebouncing = true; 6334 6335 sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT, 6336 0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC); 6337 if (DBG) { 6338 log("NETWORK_DISCONNECTION_EVENT in connected state" 6339 + " BSSID=" + mWifiInfo.getBSSID() 6340 + " RSSI=" + mWifiInfo.getRssi() 6341 + " freq=" + mWifiInfo.getFrequency() 6342 + " -> debounce"); 6343 } 6344 return HANDLED; 6345 } else { 6346 if (DBG) { 6347 log("NETWORK_DISCONNECTION_EVENT in connected state" 6348 + " BSSID=" + mWifiInfo.getBSSID() 6349 + " RSSI=" + mWifiInfo.getRssi() 6350 + " freq=" + mWifiInfo.getFrequency() 6351 + " was debouncing=" + linkDebouncing); 6352 } 6353 } 6354 break; 6355 case CMD_AUTO_ROAM: 6356 /* This will happen similarly to an Auto_CONNECT, except we specify the BSSID */ 6357 /* Work Around: wpa_supplicant can get in a bad state where it returns a non 6358 * associated status thus the STATUS command but somehow-someplace still thinks 6359 * it is associated and thus will ignore select/reconnect command with 6360 * following message: 6361 * "Already associated with the selected network - do nothing" 6362 * 6363 * Hence, sends a disconnect to supplicant first. 6364 */ 6365 //mWifiNative.disconnect(); 6366 6367 /* Connect command coming from auto-join */ 6368 ScanResult candidate = (ScanResult)message.obj; 6369 String bssid = "any"; 6370 if (candidate != null) { 6371 bssid = candidate.BSSID; 6372 } 6373 int netId = mLastNetworkId; 6374 WifiConfiguration config = getCurrentWifiConfiguration(); 6375 6376 loge("CMD_AUTO_ROAM sup state " 6377 + mSupplicantStateTracker.getSupplicantStateName() 6378 + " my state " + getCurrentState().getName() 6379 + " nid=" + Integer.toString(netId) 6380 + " roam=" + Integer.toString(message.arg2) 6381 + bssid); 6382 if (config == null) { 6383 loge("AUTO_ROAM and no config, bail out..."); 6384 break; 6385 } 6386 6387 /* Save the BSSID so as to lock it @ firmware */ 6388 autoRoamSetBSSID(config, bssid); 6389 6390 /* Save the network config */ 6391 loge("CMD_AUTO_ROAM will save config -> " + config.SSID 6392 + " nid=" + Integer.toString(netId)); 6393 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 6394 netId = result.getNetworkId(); 6395 loge("CMD_AUTO_ROAM did save config -> " 6396 + " nid=" + Integer.toString(netId)); 6397 6398 if (mWifiConfigStore.selectNetwork(netId) && 6399 mWifiNative.reassociate()) { 6400 lastConnectAttempt = System.currentTimeMillis(); 6401 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 6402 6403 // replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 6404 mAutoRoaming = message.arg2; 6405 transitionTo(mRoamingState); 6406 6407 } else { 6408 loge("Failed to connect config: " + config + " netId: " + netId); 6409 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 6410 WifiManager.ERROR); 6411 break; 6412 } 6413 break; 6414 default: 6415 return NOT_HANDLED; 6416 } 6417 return HANDLED; 6418 } 6419 6420 @Override 6421 public void exit() { 6422 loge("WifiStateMachine: Leaving Connected state"); 6423 setScanAlarm(false); 6424 } 6425 } 6426 6427 class DisconnectingState extends State { 6428 6429 @Override 6430 public void enter() { 6431 if (mFrameworkAutoJoin.get()) { 6432 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 6433 } else { 6434 6435 mCurrentScanAlarmMs = mFrameworkScanIntervalMs; 6436 } 6437 6438 if (PDBG) { 6439 loge(" Enter DisconnectingState State scan interval " + mFrameworkScanIntervalMs 6440 + " mEnableBackgroundScan= " + mEnableBackgroundScan 6441 + " screenOn=" + mScreenOn); 6442 } 6443 if (mScreenOn) 6444 setScanAlarm(true); 6445 } 6446 6447 @Override 6448 public boolean processMessage(Message message) { 6449 logStateAndMessage(message, getClass().getSimpleName()); 6450 switch (message.what) { 6451 case CMD_SET_OPERATIONAL_MODE: 6452 if (message.arg1 != CONNECT_MODE) { 6453 deferMessage(message); 6454 } 6455 break; 6456 case CMD_START_SCAN: 6457 // Ignore scans while disconnecting 6458 return HANDLED; 6459 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6460 /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT 6461 * we have missed the network disconnection, transition to mDisconnectedState 6462 * and handle the rest of the events there 6463 */ 6464 deferMessage(message); 6465 handleNetworkDisconnect(); 6466 transitionTo(mDisconnectedState); 6467 break; 6468 default: 6469 return NOT_HANDLED; 6470 } 6471 return HANDLED; 6472 } 6473 6474 @Override 6475 public void exit() { 6476 mCurrentScanAlarmMs = 0; 6477 } 6478 } 6479 6480 class DisconnectedState extends State { 6481 @Override 6482 public void enter() { 6483 // We dont scan frequently if this is a temporary disconnect 6484 // due to p2p 6485 if (mTemporarilyDisconnectWifi) { 6486 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 6487 return; 6488 } 6489 6490 // Loose the last selection choice 6491 // mWifiAutoJoinController.setLastSelectedConfiguration 6492 // (WifiConfiguration.INVALID_NETWORK_ID); 6493 6494 mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 6495 Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS, 6496 mDefaultFrameworkScanIntervalMs); 6497 6498 if (mFrameworkAutoJoin.get()) { 6499 if (mScreenOn) 6500 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 6501 } else { 6502 mCurrentScanAlarmMs = mFrameworkScanIntervalMs; 6503 } 6504 6505 if (PDBG) { 6506 loge(" Enter disconnected State scan interval " + mFrameworkScanIntervalMs 6507 + " mEnableBackgroundScan= " + mEnableBackgroundScan 6508 + " screenOn=" + mScreenOn); 6509 } 6510 6511 /** clear the roaming state, if we were roaming, we failed */ 6512 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 6513 6514 /** 6515 * mFrameworkAutoJoin is False: We initiate background scanning if it is enabled, 6516 * otherwise we initiate an infrequent scan that wakes up the device to ensure 6517 * a user connects to an access point on the move 6518 * 6519 * mFrameworkAutoJoin is True: 6520 * - screen dark and PNO supported => scan alarm disabled 6521 * - everything else => scan alarm enabled with mDefaultFrameworkScanIntervalMs period 6522 */ 6523 if ((mScreenOn == false) && mEnableBackgroundScan) { //mEnableBackgroundScan) { 6524 /* If a regular scan result is pending, do not initiate background 6525 * scan until the scan results are returned. This is needed because 6526 * initiating a background scan will cancel the regular scan and 6527 * scan results will not be returned until background scanning is 6528 * cleared 6529 */ 6530 if (!mIsScanOngoing) { 6531 mWifiNative.enableBackgroundScan(true); 6532 } 6533 } else { 6534 setScanAlarm(true); 6535 } 6536 6537 if (mFrameworkAutoJoin.get() && mScreenOn && isScanAllowed()) { 6538 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 6539 } 6540 6541 /** 6542 * If we have no networks saved, the supplicant stops doing the periodic scan. 6543 * The scans are useful to notify the user of the presence of an open network. 6544 * Note that these are not wake up scans. 6545 */ 6546 if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) { 6547 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 6548 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 6549 } 6550 } 6551 @Override 6552 public boolean processMessage(Message message) { 6553 boolean ret = HANDLED; 6554 6555 logStateAndMessage(message, getClass().getSimpleName()); 6556 6557 switch (message.what) { 6558 case CMD_NO_NETWORKS_PERIODIC_SCAN: 6559 if (mP2pConnected.get()) break; 6560 if (message.arg1 == mPeriodicScanToken && 6561 mWifiConfigStore.getConfiguredNetworks().size() == 0) { 6562 startScan(UNKNOWN_SCAN_SOURCE, null, null); 6563 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 6564 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 6565 } 6566 break; 6567 case WifiManager.FORGET_NETWORK: 6568 case CMD_REMOVE_NETWORK: 6569 // Set up a delayed message here. After the forget/remove is handled 6570 // the handled delayed message will determine if there is a need to 6571 // scan and continue 6572 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 6573 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 6574 ret = NOT_HANDLED; 6575 break; 6576 case CMD_SET_OPERATIONAL_MODE: 6577 if (message.arg1 != CONNECT_MODE) { 6578 mOperationalMode = message.arg1; 6579 6580 mWifiConfigStore.disableAllNetworks(); 6581 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 6582 mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); 6583 setWifiState(WIFI_STATE_DISABLED); 6584 } 6585 6586 transitionTo(mScanModeState); 6587 } 6588 break; 6589 case CMD_ENABLE_BACKGROUND_SCAN: 6590 mEnableBackgroundScan = (message.arg1 == 1); 6591 loge("enableBackgroundScanCommand enabled=" + mEnableBackgroundScan 6592 + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); 6593 6594 if (mEnableBackgroundScan) { 6595 mWifiNative.enableBackgroundScan(true); 6596 setScanAlarm(false); 6597 } else { 6598 if (mFrameworkAutoJoin.get()) { 6599 // Tell supplicant to disconnect so as it doesnt start scanning 6600 // for connection upon disabling background scan 6601 mWifiNative.disconnect(); 6602 } 6603 mWifiNative.enableBackgroundScan(false); 6604 setScanAlarm(true); 6605 } 6606 break; 6607 /* Ignore network disconnect */ 6608 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 6609 break; 6610 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6611 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 6612 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 6613 /* ConnectModeState does the rest of the handling */ 6614 ret = NOT_HANDLED; 6615 break; 6616 case CMD_START_SCAN: 6617 if (!isScanAllowed()) { 6618 // Ignore the scan request 6619 return HANDLED; 6620 } 6621 /* Disable background scan temporarily during a regular scan */ 6622 if (mEnableBackgroundScan) { 6623 mWifiNative.enableBackgroundScan(false); 6624 } 6625 /* Handled in parent state */ 6626 ret = NOT_HANDLED; 6627 break; 6628 case WifiMonitor.SCAN_RESULTS_EVENT: 6629 /* Re-enable background scan when a pending scan result is received */ 6630 if (mEnableBackgroundScan && mIsScanOngoing) { 6631 mWifiNative.enableBackgroundScan(true); 6632 } 6633 /* Handled in parent state */ 6634 ret = NOT_HANDLED; 6635 break; 6636 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 6637 NetworkInfo info = (NetworkInfo) message.obj; 6638 mP2pConnected.set(info.isConnected()); 6639 if (mP2pConnected.get()) { 6640 int defaultInterval = mContext.getResources().getInteger( 6641 R.integer.config_wifi_scan_interval_p2p_connected); 6642 long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 6643 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 6644 defaultInterval); 6645 mWifiNative.setScanInterval((int) scanIntervalMs/1000); 6646 } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { 6647 if (DBG) log("Turn on scanning after p2p disconnected"); 6648 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 6649 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 6650 } 6651 case CMD_RECONNECT: 6652 case CMD_REASSOCIATE: 6653 if (mTemporarilyDisconnectWifi) { 6654 // Drop a third party reconnect/reassociate if STA is 6655 // temporarily disconnected for p2p 6656 break; 6657 } else { 6658 // ConnectModeState handles it 6659 ret = NOT_HANDLED; 6660 } 6661 break; 6662 default: 6663 ret = NOT_HANDLED; 6664 } 6665 return ret; 6666 } 6667 6668 @Override 6669 public void exit() { 6670 /* No need for a background scan upon exit from a disconnected state */ 6671 if (mEnableBackgroundScan) { 6672 mWifiNative.enableBackgroundScan(false); 6673 } 6674 mCurrentScanAlarmMs = 0; 6675 setScanAlarm(false); 6676 } 6677 } 6678 6679 class WpsRunningState extends State { 6680 // Tracks the source to provide a reply 6681 private Message mSourceMessage; 6682 @Override 6683 public void enter() { 6684 mSourceMessage = Message.obtain(getCurrentMessage()); 6685 } 6686 @Override 6687 public boolean processMessage(Message message) { 6688 logStateAndMessage(message, getClass().getSimpleName()); 6689 6690 switch (message.what) { 6691 case WifiMonitor.WPS_SUCCESS_EVENT: 6692 // Ignore intermediate success, wait for full connection 6693 break; 6694 case WifiMonitor.NETWORK_CONNECTION_EVENT: 6695 replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED); 6696 mSourceMessage.recycle(); 6697 mSourceMessage = null; 6698 deferMessage(message); 6699 transitionTo(mDisconnectedState); 6700 break; 6701 case WifiMonitor.WPS_OVERLAP_EVENT: 6702 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 6703 WifiManager.WPS_OVERLAP_ERROR); 6704 mSourceMessage.recycle(); 6705 mSourceMessage = null; 6706 transitionTo(mDisconnectedState); 6707 break; 6708 case WifiMonitor.WPS_FAIL_EVENT: 6709 // Arg1 has the reason for the failure 6710 if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) { 6711 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1); 6712 mSourceMessage.recycle(); 6713 mSourceMessage = null; 6714 transitionTo(mDisconnectedState); 6715 } else { 6716 if (DBG) log("Ignore unspecified fail event during WPS connection"); 6717 } 6718 break; 6719 case WifiMonitor.WPS_TIMEOUT_EVENT: 6720 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 6721 WifiManager.WPS_TIMED_OUT); 6722 mSourceMessage.recycle(); 6723 mSourceMessage = null; 6724 transitionTo(mDisconnectedState); 6725 break; 6726 case WifiManager.START_WPS: 6727 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS); 6728 break; 6729 case WifiManager.CANCEL_WPS: 6730 if (mWifiNative.cancelWps()) { 6731 replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED); 6732 } else { 6733 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR); 6734 } 6735 transitionTo(mDisconnectedState); 6736 break; 6737 /** 6738 * Defer all commands that can cause connections to a different network 6739 * or put the state machine out of connect mode 6740 */ 6741 case CMD_STOP_DRIVER: 6742 case CMD_SET_OPERATIONAL_MODE: 6743 case WifiManager.CONNECT_NETWORK: 6744 case CMD_ENABLE_NETWORK: 6745 case CMD_RECONNECT: 6746 case CMD_REASSOCIATE: 6747 deferMessage(message); 6748 break; 6749 case CMD_AUTO_CONNECT: 6750 case CMD_AUTO_ROAM: 6751 case CMD_START_SCAN: 6752 return HANDLED; 6753 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 6754 if (DBG) log("Network connection lost"); 6755 handleNetworkDisconnect(); 6756 break; 6757 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 6758 if (DBG) log("Ignore Assoc reject event during WPS Connection"); 6759 break; 6760 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 6761 // Disregard auth failure events during WPS connection. The 6762 // EAP sequence is retried several times, and there might be 6763 // failures (especially for wps pin). We will get a WPS_XXX 6764 // event at the end of the sequence anyway. 6765 if (DBG) log("Ignore auth failure during WPS connection"); 6766 break; 6767 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6768 // Throw away supplicant state changes when WPS is running. 6769 // We will start getting supplicant state changes once we get 6770 // a WPS success or failure 6771 break; 6772 default: 6773 return NOT_HANDLED; 6774 } 6775 return HANDLED; 6776 } 6777 6778 @Override 6779 public void exit() { 6780 mWifiConfigStore.enableAllNetworks(); 6781 mWifiConfigStore.loadConfiguredNetworks(); 6782 } 6783 } 6784 6785 class SoftApStartingState extends State { 6786 @Override 6787 public void enter() { 6788 final Message message = getCurrentMessage(); 6789 if (message.what == CMD_START_AP) { 6790 final WifiConfiguration config = (WifiConfiguration) message.obj; 6791 6792 if (config == null) { 6793 mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); 6794 } else { 6795 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 6796 startSoftApWithConfig(config); 6797 } 6798 } else { 6799 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); 6800 } 6801 } 6802 @Override 6803 public boolean processMessage(Message message) { 6804 logStateAndMessage(message, getClass().getSimpleName()); 6805 6806 switch(message.what) { 6807 case CMD_START_SUPPLICANT: 6808 case CMD_STOP_SUPPLICANT: 6809 case CMD_START_AP: 6810 case CMD_STOP_AP: 6811 case CMD_START_DRIVER: 6812 case CMD_STOP_DRIVER: 6813 case CMD_SET_OPERATIONAL_MODE: 6814 case CMD_SET_COUNTRY_CODE: 6815 case CMD_SET_FREQUENCY_BAND: 6816 case CMD_START_PACKET_FILTERING: 6817 case CMD_STOP_PACKET_FILTERING: 6818 case CMD_TETHER_STATE_CHANGE: 6819 deferMessage(message); 6820 break; 6821 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: 6822 WifiConfiguration config = (WifiConfiguration) message.obj; 6823 if (config != null) { 6824 startSoftApWithConfig(config); 6825 } else { 6826 loge("Softap config is null!"); 6827 sendMessage(CMD_START_AP_FAILURE); 6828 } 6829 break; 6830 case CMD_START_AP_SUCCESS: 6831 setWifiApState(WIFI_AP_STATE_ENABLED); 6832 transitionTo(mSoftApStartedState); 6833 break; 6834 case CMD_START_AP_FAILURE: 6835 setWifiApState(WIFI_AP_STATE_FAILED); 6836 transitionTo(mInitialState); 6837 break; 6838 default: 6839 return NOT_HANDLED; 6840 } 6841 return HANDLED; 6842 } 6843 } 6844 6845 class SoftApStartedState extends State { 6846 @Override 6847 public boolean processMessage(Message message) { 6848 logStateAndMessage(message, getClass().getSimpleName()); 6849 6850 switch(message.what) { 6851 case CMD_STOP_AP: 6852 if (DBG) log("Stopping Soft AP"); 6853 /* We have not tethered at this point, so we just shutdown soft Ap */ 6854 try { 6855 mNwService.stopAccessPoint(mInterfaceName); 6856 } catch(Exception e) { 6857 loge("Exception in stopAccessPoint()"); 6858 } 6859 setWifiApState(WIFI_AP_STATE_DISABLED); 6860 transitionTo(mInitialState); 6861 break; 6862 case CMD_START_AP: 6863 // Ignore a start on a running access point 6864 break; 6865 // Fail client mode operation when soft AP is enabled 6866 case CMD_START_SUPPLICANT: 6867 loge("Cannot start supplicant with a running soft AP"); 6868 setWifiState(WIFI_STATE_UNKNOWN); 6869 break; 6870 case CMD_TETHER_STATE_CHANGE: 6871 TetherStateChange stateChange = (TetherStateChange) message.obj; 6872 if (startTethering(stateChange.available)) { 6873 transitionTo(mTetheringState); 6874 } 6875 break; 6876 default: 6877 return NOT_HANDLED; 6878 } 6879 return HANDLED; 6880 } 6881 } 6882 6883 class TetheringState extends State { 6884 @Override 6885 public void enter() { 6886 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 6887 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 6888 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 6889 } 6890 @Override 6891 public boolean processMessage(Message message) { 6892 logStateAndMessage(message, getClass().getSimpleName()); 6893 6894 switch(message.what) { 6895 case CMD_TETHER_STATE_CHANGE: 6896 TetherStateChange stateChange = (TetherStateChange) message.obj; 6897 if (isWifiTethered(stateChange.active)) { 6898 transitionTo(mTetheredState); 6899 } 6900 return HANDLED; 6901 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 6902 if (message.arg1 == mTetherToken) { 6903 loge("Failed to get tether update, shutdown soft access point"); 6904 transitionTo(mSoftApStartedState); 6905 // Needs to be first thing handled 6906 sendMessageAtFrontOfQueue(CMD_STOP_AP); 6907 } 6908 break; 6909 case CMD_START_SUPPLICANT: 6910 case CMD_STOP_SUPPLICANT: 6911 case CMD_START_AP: 6912 case CMD_STOP_AP: 6913 case CMD_START_DRIVER: 6914 case CMD_STOP_DRIVER: 6915 case CMD_SET_OPERATIONAL_MODE: 6916 case CMD_SET_COUNTRY_CODE: 6917 case CMD_SET_FREQUENCY_BAND: 6918 case CMD_START_PACKET_FILTERING: 6919 case CMD_STOP_PACKET_FILTERING: 6920 deferMessage(message); 6921 break; 6922 default: 6923 return NOT_HANDLED; 6924 } 6925 return HANDLED; 6926 } 6927 } 6928 6929 class TetheredState extends State { 6930 @Override 6931 public boolean processMessage(Message message) { 6932 logStateAndMessage(message, getClass().getSimpleName()); 6933 6934 switch(message.what) { 6935 case CMD_TETHER_STATE_CHANGE: 6936 TetherStateChange stateChange = (TetherStateChange) message.obj; 6937 if (!isWifiTethered(stateChange.active)) { 6938 loge("Tethering reports wifi as untethered!, shut down soft Ap"); 6939 setHostApRunning(null, false); 6940 setHostApRunning(null, true); 6941 } 6942 return HANDLED; 6943 case CMD_STOP_AP: 6944 if (DBG) log("Untethering before stopping AP"); 6945 setWifiApState(WIFI_AP_STATE_DISABLING); 6946 stopTethering(); 6947 transitionTo(mUntetheringState); 6948 // More work to do after untethering 6949 deferMessage(message); 6950 break; 6951 default: 6952 return NOT_HANDLED; 6953 } 6954 return HANDLED; 6955 } 6956 } 6957 6958 class UntetheringState extends State { 6959 @Override 6960 public void enter() { 6961 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 6962 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 6963 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 6964 6965 } 6966 @Override 6967 public boolean processMessage(Message message) { 6968 logStateAndMessage(message, getClass().getSimpleName()); 6969 6970 switch(message.what) { 6971 case CMD_TETHER_STATE_CHANGE: 6972 TetherStateChange stateChange = (TetherStateChange) message.obj; 6973 6974 /* Wait till wifi is untethered */ 6975 if (isWifiTethered(stateChange.active)) break; 6976 6977 transitionTo(mSoftApStartedState); 6978 break; 6979 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 6980 if (message.arg1 == mTetherToken) { 6981 loge("Failed to get tether update, force stop access point"); 6982 transitionTo(mSoftApStartedState); 6983 } 6984 break; 6985 case CMD_START_SUPPLICANT: 6986 case CMD_STOP_SUPPLICANT: 6987 case CMD_START_AP: 6988 case CMD_STOP_AP: 6989 case CMD_START_DRIVER: 6990 case CMD_STOP_DRIVER: 6991 case CMD_SET_OPERATIONAL_MODE: 6992 case CMD_SET_COUNTRY_CODE: 6993 case CMD_SET_FREQUENCY_BAND: 6994 case CMD_START_PACKET_FILTERING: 6995 case CMD_STOP_PACKET_FILTERING: 6996 deferMessage(message); 6997 break; 6998 default: 6999 return NOT_HANDLED; 7000 } 7001 return HANDLED; 7002 } 7003 } 7004 7005 //State machine initiated requests can have replyTo set to null indicating 7006 //there are no recepients, we ignore those reply actions 7007 private void replyToMessage(Message msg, int what) { 7008 if (msg.replyTo == null) return; 7009 Message dstMsg = obtainMessageWithArg2(msg); 7010 dstMsg.what = what; 7011 mReplyChannel.replyToMessage(msg, dstMsg); 7012 } 7013 7014 private void replyToMessage(Message msg, int what, int arg1) { 7015 if (msg.replyTo == null) return; 7016 Message dstMsg = obtainMessageWithArg2(msg); 7017 dstMsg.what = what; 7018 dstMsg.arg1 = arg1; 7019 mReplyChannel.replyToMessage(msg, dstMsg); 7020 } 7021 7022 private void replyToMessage(Message msg, int what, Object obj) { 7023 if (msg.replyTo == null) return; 7024 Message dstMsg = obtainMessageWithArg2(msg); 7025 dstMsg.what = what; 7026 dstMsg.obj = obj; 7027 mReplyChannel.replyToMessage(msg, dstMsg); 7028 } 7029 7030 /** 7031 * arg2 on the source message has a unique id that needs to be retained in replies 7032 * to match the request 7033 7034 * see WifiManager for details 7035 */ 7036 private Message obtainMessageWithArg2(Message srcMsg) { 7037 Message msg = Message.obtain(); 7038 msg.arg2 = srcMsg.arg2; 7039 return msg; 7040 } 7041 7042 private static int parseHex(char ch) { 7043 if ('0' <= ch && ch <= '9') { 7044 return ch - '0'; 7045 } else if ('a' <= ch && ch <= 'f') { 7046 return ch - 'a' + 10; 7047 } else if ('A' <= ch && ch <= 'F') { 7048 return ch - 'A' + 10; 7049 } else { 7050 throw new NumberFormatException("" + ch + " is not a valid hex digit"); 7051 } 7052 } 7053 7054 private byte[] parseHex(String hex) { 7055 /* This only works for good input; don't throw bad data at it */ 7056 if (hex == null) { 7057 return new byte[0]; 7058 } 7059 7060 if (hex.length() % 2 != 0) { 7061 throw new NumberFormatException(hex + " is not a valid hex string"); 7062 } 7063 7064 byte[] result = new byte[(hex.length())/2 + 1]; 7065 result[0] = (byte) ((hex.length())/2); 7066 for (int i = 0, j = 1; i < hex.length(); i += 2, j++) { 7067 int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i+1)); 7068 byte b = (byte) (val & 0xFF); 7069 result[j] = b; 7070 } 7071 7072 return result; 7073 } 7074 7075 private static String makeHex(byte[] bytes) { 7076 StringBuilder sb = new StringBuilder(); 7077 for (byte b : bytes) { 7078 sb.append(String.format("%02x", b)); 7079 } 7080 return sb.toString(); 7081 } 7082 7083 private static String makeHex(byte[] bytes, int from, int len) { 7084 StringBuilder sb = new StringBuilder(); 7085 for (int i = 0; i < len; i++) { 7086 sb.append(String.format("%02x", bytes[from+i])); 7087 } 7088 return sb.toString(); 7089 } 7090 7091 7092 private static byte[] concat(byte[] array1, byte[] array2, byte[] array3) { 7093 7094 int len = array1.length + array2.length + array3.length; 7095 7096 if (array1.length != 0) { 7097 len++; /* add another byte for size */ 7098 } 7099 7100 if (array2.length != 0) { 7101 len++; /* add another byte for size */ 7102 } 7103 7104 if (array3.length != 0) { 7105 len++; /* add another byte for size */ 7106 } 7107 7108 byte[] result = new byte[len]; 7109 7110 int index = 0; 7111 if (array1.length != 0) { 7112 result[index] = (byte) (array1.length & 0xFF); 7113 index++; 7114 for (byte b : array1) { 7115 result[index] = b; 7116 index++; 7117 } 7118 } 7119 7120 if (array2.length != 0) { 7121 result[index] = (byte) (array2.length & 0xFF); 7122 index++; 7123 for (byte b : array2) { 7124 result[index] = b; 7125 index++; 7126 } 7127 } 7128 7129 if (array3.length != 0) { 7130 result[index] = (byte) (array3.length & 0xFF); 7131 index++; 7132 for (byte b : array3) { 7133 result[index] = b; 7134 index++; 7135 } 7136 } 7137 return result; 7138 } 7139 7140 void handleGsmAuthRequest(SimAuthRequestData requestData) { 7141 if (targetWificonfiguration == null 7142 || targetWificonfiguration.networkId == requestData.networkId) { 7143 logd("id matches targetWifiConfiguration"); 7144 } else { 7145 logd("id does not match targetWifiConfiguration"); 7146 return; 7147 } 7148 7149 TelephonyManager tm = (TelephonyManager) 7150 mContext.getSystemService(Context.TELEPHONY_SERVICE); 7151 7152 if (tm != null) { 7153 StringBuilder sb = new StringBuilder(); 7154 for (String challenge : requestData.challenges) { 7155 7156 logd("RAND = " + challenge); 7157 7158 byte[] rand = null; 7159 try { 7160 rand = parseHex(challenge); 7161 } catch (NumberFormatException e) { 7162 loge("malformed challenge"); 7163 continue; 7164 } 7165 7166 String base64Challenge = android.util.Base64.encodeToString( 7167 rand, android.util.Base64.NO_WRAP); 7168 /* 7169 * appType = 1 => SIM, 2 => USIM according to 7170 * com.android.internal.telephony.PhoneConstants#APPTYPE_xxx 7171 */ 7172 int appType = 2; 7173 String tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge); 7174 logv("Raw Response - " + tmResponse); 7175 7176 if (tmResponse != null && tmResponse.length() > 4) { 7177 byte[] result = android.util.Base64.decode(tmResponse, 7178 android.util.Base64.DEFAULT); 7179 logv("Hex Response -" + makeHex(result)); 7180 int sres_len = result[0]; 7181 String sres = makeHex(result, 1, sres_len); 7182 int kc_offset = 1+sres_len; 7183 int kc_len = result[kc_offset]; 7184 String kc = makeHex(result, 1+kc_offset, kc_len); 7185 sb.append(":" + kc + ":" + sres); 7186 logv("kc:" + kc + " sres:" + sres); 7187 } else { 7188 loge("bad response - " + tmResponse); 7189 } 7190 } 7191 7192 String response = sb.toString(); 7193 logv("Supplicant Response -" + response); 7194 mWifiNative.simAuthResponse(requestData.networkId, response); 7195 } else { 7196 loge("could not get telephony manager"); 7197 } 7198 } 7199 7200 void handle3GAuthRequest(SimAuthRequestData requestData) { 7201 7202 } 7203} 7204