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