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