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