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