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