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