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