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