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