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