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