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