WifiStateMachine.java revision e693d9490d27bcd91bb1f012bb88ef4c95cdaee3
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 String ssid; 699 String rand1; 700 String rand2; 701 String rand3; 702 } 703 704 public static class SimAuthResponseData { 705 int id; 706 String Kc1; 707 String SRES1; 708 String Kc2; 709 String SRES2; 710 String Kc3; 711 String SRES3; 712 } 713 714 /** 715 * One of {@link WifiManager#WIFI_STATE_DISABLED}, 716 * {@link WifiManager#WIFI_STATE_DISABLING}, 717 * {@link WifiManager#WIFI_STATE_ENABLED}, 718 * {@link WifiManager#WIFI_STATE_ENABLING}, 719 * {@link WifiManager#WIFI_STATE_UNKNOWN} 720 * 721 */ 722 private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED); 723 724 /** 725 * One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 726 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 727 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 728 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 729 * {@link WifiManager#WIFI_AP_STATE_FAILED} 730 * 731 */ 732 private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED); 733 734 private static final int SCAN_REQUEST = 0; 735 private static final String ACTION_START_SCAN = 736 "com.android.server.WifiManager.action.START_SCAN"; 737 738 private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter"; 739 private static final int DRIVER_STOP_REQUEST = 0; 740 private static final String ACTION_DELAYED_DRIVER_STOP = 741 "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP"; 742 743 private static final String ACTION_REFRESH_BATCHED_SCAN = 744 "com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN"; 745 /** 746 * Keep track of whether WIFI is running. 747 */ 748 private boolean mIsRunning = false; 749 750 /** 751 * Keep track of whether we last told the battery stats we had started. 752 */ 753 private boolean mReportedRunning = false; 754 755 /** 756 * Most recently set source of starting WIFI. 757 */ 758 private final WorkSource mRunningWifiUids = new WorkSource(); 759 760 /** 761 * The last reported UIDs that were responsible for starting WIFI. 762 */ 763 private final WorkSource mLastRunningWifiUids = new WorkSource(); 764 765 private final IBatteryStats mBatteryStats; 766 767 private BatchedScanSettings mBatchedScanSettings = null; 768 769 /** 770 * Track the worksource/cost of the current settings and track what's been noted 771 * to the battery stats, so we can mark the end of the previous when changing. 772 */ 773 private WorkSource mBatchedScanWorkSource = null; 774 private int mBatchedScanCsph = 0; 775 private WorkSource mNotedBatchedScanWorkSource = null; 776 private int mNotedBatchedScanCsph = 0; 777 778 private AtomicBoolean mFrameworkAutoJoin = new AtomicBoolean(true); //enable by default 779 780 public WifiStateMachine(Context context, String wlanInterface, 781 WifiTrafficPoller trafficPoller){ 782 super("WifiStateMachine"); 783 mContext = context; 784 mInterfaceName = wlanInterface; 785 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); 786 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 787 BatteryStats.SERVICE_NAME)); 788 789 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 790 mNwService = INetworkManagementService.Stub.asInterface(b); 791 792 mP2pSupported = mContext.getPackageManager().hasSystemFeature( 793 PackageManager.FEATURE_WIFI_DIRECT); 794 795 mWifiNative = new WifiNative(mInterfaceName); 796 mWifiConfigStore = new WifiConfigStore(context, mWifiNative); 797 mWifiAutoJoinController = new WifiAutoJoinController(context, this, 798 mWifiConfigStore, mWifiConnectionStatistics, mWifiNative); 799 mWifiMonitor = new WifiMonitor(this, mWifiNative); 800 mWifiInfo = new WifiInfo(); 801 mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, 802 getHandler()); 803 mLinkProperties = new LinkProperties(); 804 805 IBinder s1 = ServiceManager.getService(Context.WIFI_P2P_SERVICE); 806 mWifiP2pServiceImpl = (WifiP2pServiceImpl)IWifiP2pManager.Stub.asInterface(s1); 807 808 IBinder s2 = ServiceManager.getService(Context.WIFI_PASSPOINT_SERVICE); 809 mPasspointServiceImpl = (WifiPasspointServiceImpl)IWifiPasspointManager.Stub.asInterface(s2); 810 811 mNetworkInfo.setIsAvailable(false); 812 mLastBssid = null; 813 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 814 mLastSignalLevel = -1; 815 816 mNetlinkTracker = new NetlinkTracker(mInterfaceName, new NetlinkTracker.Callback() { 817 public void update() { 818 sendMessage(CMD_UPDATE_LINKPROPERTIES); 819 } 820 }); 821 try { 822 mNwService.registerObserver(mNetlinkTracker); 823 } catch (RemoteException e) { 824 loge("Couldn't register netlink tracker: " + e.toString()); 825 } 826 827 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 828 Intent scanIntent = new Intent(ACTION_START_SCAN, null); 829 mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0); 830 831 Intent batchedIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null); 832 mBatchedScanIntervalIntent = PendingIntent.getBroadcast(mContext, 0, batchedIntent, 0); 833 834 mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger( 835 R.integer.config_wifi_framework_scan_interval); 836 837 mDriverStopDelayMs = mContext.getResources().getInteger( 838 R.integer.config_wifi_driver_stop_delay); 839 840 mBackgroundScanSupported = mContext.getResources().getBoolean( 841 R.bool.config_wifi_background_scan_support); 842 843 mPrimaryDeviceType = mContext.getResources().getString( 844 R.string.config_wifi_p2p_device_type); 845 846 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 847 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 848 849 mFrameworkAutoJoin.set(Settings.Global.getInt(mContext.getContentResolver(), 850 Settings.Global.WIFI_ENHANCED_AUTO_JOIN, 1) == 1); 851 852 mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); 853 mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 854 mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 855 mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024); 856 mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024); 857 // TODO - needs to be a bit more dynamic 858 mNetworkCapabilities = new NetworkCapabilities(mNetworkCapabilitiesFilter); 859 860 mContext.registerReceiver( 861 new BroadcastReceiver() { 862 @Override 863 public void onReceive(Context context, Intent intent) { 864 ArrayList<String> available = intent.getStringArrayListExtra( 865 ConnectivityManager.EXTRA_AVAILABLE_TETHER); 866 ArrayList<String> active = intent.getStringArrayListExtra( 867 ConnectivityManager.EXTRA_ACTIVE_TETHER); 868 sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active)); 869 } 870 },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); 871 872 mContext.registerReceiver( 873 new BroadcastReceiver() { 874 @Override 875 public void onReceive(Context context, Intent intent) { 876 startScan(SCAN_ALARM_SOURCE, null, null); 877 if (VDBG) 878 loge("WiFiStateMachine SCAN ALARM"); 879 } 880 }, 881 new IntentFilter(ACTION_START_SCAN)); 882 883 IntentFilter filter = new IntentFilter(); 884 filter.addAction(Intent.ACTION_SCREEN_ON); 885 filter.addAction(Intent.ACTION_SCREEN_OFF); 886 filter.addAction(ACTION_REFRESH_BATCHED_SCAN); 887 mContext.registerReceiver( 888 new BroadcastReceiver() { 889 @Override 890 public void onReceive(Context context, Intent intent) { 891 String action = intent.getAction(); 892 893 if (action.equals(Intent.ACTION_SCREEN_ON)) { 894 handleScreenStateChanged(true); 895 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 896 handleScreenStateChanged(false); 897 } else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) { 898 startNextBatchedScanAsync(); 899 } 900 } 901 }, filter); 902 903 mContext.registerReceiver( 904 new BroadcastReceiver() { 905 @Override 906 public void onReceive(Context context, Intent intent) { 907 int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0); 908 sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0); 909 } 910 }, 911 new IntentFilter(ACTION_DELAYED_DRIVER_STOP)); 912 913 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 914 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false, 915 new ContentObserver(getHandler()) { 916 @Override 917 public void onChange(boolean selfChange) { 918 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 919 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 920 } 921 }); 922 923 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 924 Settings.Global.WIFI_ENHANCED_AUTO_JOIN), false, 925 new ContentObserver(getHandler()) { 926 @Override 927 public void onChange(boolean selfChange) { 928 mFrameworkAutoJoin.set(Settings.Global.getInt(mContext.getContentResolver(), 929 Settings.Global.WIFI_ENHANCED_AUTO_JOIN, 0) == 1); 930 } 931 }); 932 933 mContext.registerReceiver( 934 new BroadcastReceiver() { 935 @Override 936 public void onReceive(Context context, Intent intent) { 937 sendMessage(CMD_BOOT_COMPLETED); 938 } 939 }, 940 new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); 941 942 mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE); 943 944 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 945 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName()); 946 947 mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend"); 948 mSuspendWakeLock.setReferenceCounted(false); 949 950 addState(mDefaultState); 951 addState(mInitialState, mDefaultState); 952 addState(mSupplicantStartingState, mDefaultState); 953 addState(mSupplicantStartedState, mDefaultState); 954 addState(mDriverStartingState, mSupplicantStartedState); 955 addState(mDriverStartedState, mSupplicantStartedState); 956 addState(mScanModeState, mDriverStartedState); 957 addState(mConnectModeState, mDriverStartedState); 958 addState(mL2ConnectedState, mConnectModeState); 959 addState(mObtainingIpState, mL2ConnectedState); 960 addState(mVerifyingLinkState, mL2ConnectedState); 961 addState(mConnectedState, mL2ConnectedState); 962 addState(mRoamingState, mL2ConnectedState); 963 addState(mDisconnectingState, mConnectModeState); 964 addState(mDisconnectedState, mConnectModeState); 965 addState(mWpsRunningState, mConnectModeState); 966 addState(mWaitForP2pDisableState, mSupplicantStartedState); 967 addState(mDriverStoppingState, mSupplicantStartedState); 968 addState(mDriverStoppedState, mSupplicantStartedState); 969 addState(mSupplicantStoppingState, mDefaultState); 970 addState(mSoftApStartingState, mDefaultState); 971 addState(mSoftApStartedState, mDefaultState); 972 addState(mTetheringState, mSoftApStartedState); 973 addState(mTetheredState, mSoftApStartedState); 974 addState(mUntetheringState, mSoftApStartedState); 975 976 setInitialState(mInitialState); 977 978 setLogRecSize(5000); 979 setLogOnlyTransitions(false); 980 if (VDBG) setDbg(true); 981 982 //start the state machine 983 start(); 984 985 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 986 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 987 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 988 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 989 } 990 991 private int mVerboseLoggingLevel = 0; 992 993 int getVerboseLoggingLevel() { 994 return mVerboseLoggingLevel; 995 } 996 997 void enableVerboseLogging(int verbose) { 998 mVerboseLoggingLevel = verbose; 999 if (verbose > 0) { 1000 DBG = true; 1001 VDBG = true; 1002 PDBG = true; 1003 mLogMessages = true; 1004 mWifiNative.setSupplicantLogLevel("DEBUG"); 1005 } else { 1006 DBG = false; 1007 VDBG = false; 1008 PDBG = false; 1009 mLogMessages = false; 1010 mWifiNative.setSupplicantLogLevel("INFO"); 1011 } 1012 mWifiAutoJoinController.enableVerboseLogging(verbose); 1013 mWifiMonitor.enableVerboseLogging(verbose); 1014 mWifiNative.enableVerboseLogging(verbose); 1015 mWifiConfigStore.enableVerboseLogging(verbose); 1016 mSupplicantStateTracker.enableVerboseLogging(verbose); 1017 } 1018 1019 private int mAggressiveHandover = 0; 1020 1021 int getAggressiveHandover() { 1022 return mAggressiveHandover; 1023 } 1024 1025 void enableAggressiveHandover(int enabled) { 1026 mAggressiveHandover = enabled; 1027 } 1028 1029 private int mAllowScansWithTraffic = 0; 1030 1031 public void setAllowScansWithTraffic(int enabled) { 1032 mAllowScansWithTraffic = enabled; 1033 } 1034 1035 public int getAllowScansWithTraffic() { 1036 return mAllowScansWithTraffic; 1037 } 1038 1039 /* 1040 * 1041 * Framework scan control 1042 */ 1043 1044 private boolean mAlarmEnabled = false; 1045 /* This is set from the overlay config file or from a secure setting. 1046 * A value of 0 disables scanning in the framework. 1047 */ 1048 private long mFrameworkScanIntervalMs = 10000; 1049 1050 private long mCurrentScanAlarmMs = 10000; 1051 private void setScanAlarm(boolean enabled) { 1052 if (PDBG) { 1053 loge("setScanAlarm " + enabled + " period " + mCurrentScanAlarmMs); 1054 } 1055 if (mCurrentScanAlarmMs <= 0) enabled = false; 1056 if (enabled == mAlarmEnabled) return; 1057 if (enabled) { 1058 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 1059 System.currentTimeMillis() + mCurrentScanAlarmMs, 1060 mCurrentScanAlarmMs, 1061 mScanIntent); 1062 mAlarmEnabled = true; 1063 } else { 1064 mAlarmManager.cancel(mScanIntent); 1065 mAlarmEnabled = false; 1066 } 1067 } 1068 1069 /********************************************************* 1070 * Methods exposed for public use 1071 ********************************************************/ 1072 1073 public Messenger getMessenger() { 1074 return new Messenger(getHandler()); 1075 } 1076 1077 public WifiMonitor getWifiMonitor() { 1078 return mWifiMonitor; 1079 } 1080 1081 /** 1082 * TODO: doc 1083 */ 1084 public boolean syncPingSupplicant(AsyncChannel channel) { 1085 Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT); 1086 boolean result = (resultMsg.arg1 != FAILURE); 1087 resultMsg.recycle(); 1088 return result; 1089 } 1090 1091 public List<WifiChannel> syncGetChannelList(AsyncChannel channel) { 1092 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CAPABILITY_FREQ); 1093 List<WifiChannel> list = null; 1094 if (resultMsg.obj != null) { 1095 list = new ArrayList<WifiChannel>(); 1096 String freqs = (String) resultMsg.obj; 1097 String[] lines = freqs.split("\n"); 1098 for (String line : lines) 1099 if (line.contains("MHz")) { 1100 // line format: " 52 = 5260 MHz (NO_IBSS) (DFS)" 1101 WifiChannel c = new WifiChannel(); 1102 String[] prop = line.split(" "); 1103 if (prop.length < 5) continue; 1104 try { 1105 c.channelNum = Integer.parseInt(prop[1]); 1106 c.freqMHz = Integer.parseInt(prop[3]); 1107 } catch (NumberFormatException e) { } 1108 c.isDFS = line.contains("(DFS)"); 1109 list.add(c); 1110 } else if (line.contains("Mode[B] Channels:")) { 1111 // B channels are the same as G channels, skipped 1112 break; 1113 } 1114 } 1115 resultMsg.recycle(); 1116 return (list != null && list.size() > 0) ? list : null; 1117 } 1118 1119 1120 /** 1121 * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is 1122 * given to callingUid. 1123 * 1124 * @param callingUid The uid initiating the wifi scan. Blame will be given here unless 1125 * workSource is specified. 1126 * @param workSource If not null, blame is given to workSource. 1127 * @param settings Scan settings, see {@link ScanSettings}. 1128 */ 1129 public void startScan(int callingUid, ScanSettings settings, WorkSource workSource) { 1130 Bundle bundle = new Bundle(); 1131 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings); 1132 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1133 sendMessage(CMD_START_SCAN, callingUid, 0, bundle); 1134 } 1135 1136 /** 1137 * start or stop batched scanning using the given settings 1138 */ 1139 public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph, 1140 WorkSource workSource) { 1141 Bundle bundle = new Bundle(); 1142 bundle.putParcelable(BATCHED_SETTING, settings); 1143 bundle.putParcelable(BATCHED_WORKSOURCE, workSource); 1144 sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle); 1145 } 1146 1147 public List<BatchedScanResult> syncGetBatchedScanResultsList() { 1148 synchronized (mBatchedScanResults) { 1149 List<BatchedScanResult> batchedScanList = 1150 new ArrayList<BatchedScanResult>(mBatchedScanResults.size()); 1151 for(BatchedScanResult result: mBatchedScanResults) { 1152 batchedScanList.add(new BatchedScanResult(result)); 1153 } 1154 return batchedScanList; 1155 } 1156 } 1157 1158 public void requestBatchedScanPoll() { 1159 sendMessage(CMD_POLL_BATCHED_SCAN); 1160 } 1161 1162 private void startBatchedScan() { 1163 if (mBatchedScanSettings == null) return; 1164 1165 if (mDhcpActive) { 1166 if (DBG) log("not starting Batched Scans due to DHCP"); 1167 return; 1168 } 1169 1170 // first grab any existing data 1171 retrieveBatchedScanData(); 1172 1173 if (PDBG) loge("try starting Batched Scans due to DHCP"); 1174 1175 1176 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1177 1178 String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings); 1179 try { 1180 mExpectedBatchedScans = Integer.parseInt(scansExpected); 1181 setNextBatchedAlarm(mExpectedBatchedScans); 1182 if (mExpectedBatchedScans > 0) noteBatchedScanStart(); 1183 } catch (NumberFormatException e) { 1184 stopBatchedScan(); 1185 loge("Exception parsing WifiNative.setBatchedScanSettings response " + e); 1186 } 1187 } 1188 1189 // called from BroadcastListener 1190 private void startNextBatchedScanAsync() { 1191 sendMessage(CMD_START_NEXT_BATCHED_SCAN); 1192 } 1193 1194 private void startNextBatchedScan() { 1195 // first grab any existing data 1196 retrieveBatchedScanData(); 1197 1198 setNextBatchedAlarm(mExpectedBatchedScans); 1199 } 1200 1201 private void handleBatchedScanPollRequest() { 1202 if (DBG) { 1203 log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" + 1204 mBatchedScanMinPollTime + " , mBatchedScanSettings=" + 1205 mBatchedScanSettings); 1206 } 1207 // if there is no appropriate PollTime that's because we either aren't 1208 // batching or we've already set a time for a poll request 1209 if (mBatchedScanMinPollTime == 0) return; 1210 if (mBatchedScanSettings == null) return; 1211 1212 long now = System.currentTimeMillis(); 1213 1214 if (now > mBatchedScanMinPollTime) { 1215 // do the poll and reset our timers 1216 startNextBatchedScan(); 1217 } else { 1218 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime, 1219 mBatchedScanIntervalIntent); 1220 mBatchedScanMinPollTime = 0; 1221 } 1222 } 1223 1224 // return true if new/different 1225 private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) { 1226 BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING); 1227 WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE); 1228 1229 if (DBG) { 1230 log("set batched scan to " + settings + " for uid=" + responsibleUid + 1231 ", worksource=" + responsibleWorkSource); 1232 } 1233 if (settings != null) { 1234 if (settings.equals(mBatchedScanSettings)) return false; 1235 } else { 1236 if (mBatchedScanSettings == null) return false; 1237 } 1238 mBatchedScanSettings = settings; 1239 if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid); 1240 mBatchedScanWorkSource = responsibleWorkSource; 1241 mBatchedScanCsph = csph; 1242 return true; 1243 } 1244 1245 private void stopBatchedScan() { 1246 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1247 retrieveBatchedScanData(); 1248 mWifiNative.setBatchedScanSettings(null); 1249 noteBatchedScanStop(); 1250 } 1251 1252 private void setNextBatchedAlarm(int scansExpected) { 1253 1254 if (mBatchedScanSettings == null || scansExpected < 1) return; 1255 1256 mBatchedScanMinPollTime = System.currentTimeMillis() + 1257 mBatchedScanSettings.scanIntervalSec * 1000; 1258 1259 if (mBatchedScanSettings.maxScansPerBatch < scansExpected) { 1260 scansExpected = mBatchedScanSettings.maxScansPerBatch; 1261 } 1262 1263 int secToFull = mBatchedScanSettings.scanIntervalSec; 1264 secToFull *= scansExpected; 1265 1266 int debugPeriod = SystemProperties.getInt("wifi.batchedScan.pollPeriod", 0); 1267 if (debugPeriod > 0) secToFull = debugPeriod; 1268 1269 // set the alarm to do the next poll. We set it a little short as we'd rather 1270 // wake up wearly than miss a scan due to buffer overflow 1271 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 1272 + ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000), 1273 mBatchedScanIntervalIntent); 1274 } 1275 1276 /** 1277 * Start reading new scan data 1278 * Data comes in as: 1279 * "scancount=5\n" 1280 * "nextcount=5\n" 1281 * "apcount=3\n" 1282 * "trunc\n" (optional) 1283 * "bssid=...\n" 1284 * "ssid=...\n" 1285 * "freq=...\n" (in Mhz) 1286 * "level=...\n" 1287 * "dist=...\n" (in cm) 1288 * "distsd=...\n" (standard deviation, in cm) 1289 * "====" 1290 * "bssid=...\n" 1291 * etc 1292 * "====" 1293 * "bssid=...\n" 1294 * etc 1295 * "%%%%" 1296 * "apcount=2\n" 1297 * "bssid=...\n" 1298 * etc 1299 * "%%%% 1300 * etc 1301 * "----" 1302 */ 1303 private final static boolean DEBUG_PARSE = false; 1304 private void retrieveBatchedScanData() { 1305 String rawData = mWifiNative.getBatchedScanResults(); 1306 if (DEBUG_PARSE) log("rawData = " + rawData); 1307 mBatchedScanMinPollTime = 0; 1308 if (rawData == null || rawData.equalsIgnoreCase("OK")) { 1309 loge("Unexpected BatchedScanResults :" + rawData); 1310 return; 1311 } 1312 1313 int scanCount = 0; 1314 final String END_OF_BATCHES = "----"; 1315 final String SCANCOUNT = "scancount="; 1316 final String TRUNCATED = "trunc"; 1317 final String AGE = "age="; 1318 final String DIST = "dist="; 1319 final String DISTSD = "distSd="; 1320 1321 String splitData[] = rawData.split("\n"); 1322 int n = 0; 1323 if (splitData[n].startsWith(SCANCOUNT)) { 1324 try { 1325 scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length())); 1326 } catch (NumberFormatException e) { 1327 loge("scancount parseInt Exception from " + splitData[n]); 1328 } 1329 } else log("scancount not found"); 1330 if (scanCount == 0) { 1331 loge("scanCount==0 - aborting"); 1332 return; 1333 } 1334 1335 final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION); 1336 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1337 1338 synchronized (mBatchedScanResults) { 1339 mBatchedScanResults.clear(); 1340 BatchedScanResult batchedScanResult = new BatchedScanResult(); 1341 1342 String bssid = null; 1343 WifiSsid wifiSsid = null; 1344 int level = 0; 1345 int freq = 0; 1346 int dist, distSd; 1347 long tsf = 0; 1348 dist = distSd = ScanResult.UNSPECIFIED; 1349 final long now = SystemClock.elapsedRealtime(); 1350 final int bssidStrLen = BSSID_STR.length(); 1351 1352 while (true) { 1353 while (n < splitData.length) { 1354 if (DEBUG_PARSE) logd("parsing " + splitData[n]); 1355 if (splitData[n].equals(END_OF_BATCHES)) { 1356 if (n+1 != splitData.length) { 1357 loge("didn't consume " + (splitData.length-n)); 1358 } 1359 if (mBatchedScanResults.size() > 0) { 1360 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1361 } 1362 logd("retrieveBatchedScanResults X"); 1363 return; 1364 } 1365 if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) { 1366 if (bssid != null) { 1367 batchedScanResult.scanResults.add(new ScanResult( 1368 wifiSsid, bssid, "", level, freq, tsf, dist, distSd)); 1369 wifiSsid = null; 1370 bssid = null; 1371 level = 0; 1372 freq = 0; 1373 tsf = 0; 1374 dist = distSd = ScanResult.UNSPECIFIED; 1375 } 1376 if (splitData[n].equals(END_STR)) { 1377 if (batchedScanResult.scanResults.size() != 0) { 1378 mBatchedScanResults.add(batchedScanResult); 1379 batchedScanResult = new BatchedScanResult(); 1380 } else { 1381 logd("Found empty batch"); 1382 } 1383 } 1384 } else if (splitData[n].equals(TRUNCATED)) { 1385 batchedScanResult.truncated = true; 1386 } else if (splitData[n].startsWith(BSSID_STR)) { 1387 bssid = new String(splitData[n].getBytes(), bssidStrLen, 1388 splitData[n].length() - bssidStrLen); 1389 } else if (splitData[n].startsWith(FREQ_STR)) { 1390 try { 1391 freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length())); 1392 } catch (NumberFormatException e) { 1393 loge("Invalid freqency: " + splitData[n]); 1394 freq = 0; 1395 } 1396 } else if (splitData[n].startsWith(AGE)) { 1397 try { 1398 tsf = now - Long.parseLong(splitData[n].substring(AGE.length())); 1399 tsf *= 1000; // convert mS -> uS 1400 } catch (NumberFormatException e) { 1401 loge("Invalid timestamp: " + splitData[n]); 1402 tsf = 0; 1403 } 1404 } else if (splitData[n].startsWith(SSID_STR)) { 1405 wifiSsid = WifiSsid.createFromAsciiEncoded( 1406 splitData[n].substring(SSID_STR.length())); 1407 } else if (splitData[n].startsWith(LEVEL_STR)) { 1408 try { 1409 level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length())); 1410 if (level > 0) level -= 256; 1411 } catch (NumberFormatException e) { 1412 loge("Invalid level: " + splitData[n]); 1413 level = 0; 1414 } 1415 } else if (splitData[n].startsWith(DIST)) { 1416 try { 1417 dist = Integer.parseInt(splitData[n].substring(DIST.length())); 1418 } catch (NumberFormatException e) { 1419 loge("Invalid distance: " + splitData[n]); 1420 dist = ScanResult.UNSPECIFIED; 1421 } 1422 } else if (splitData[n].startsWith(DISTSD)) { 1423 try { 1424 distSd = Integer.parseInt(splitData[n].substring(DISTSD.length())); 1425 } catch (NumberFormatException e) { 1426 loge("Invalid distanceSd: " + splitData[n]); 1427 distSd = ScanResult.UNSPECIFIED; 1428 } 1429 } else { 1430 loge("Unable to parse batched scan result line: " + splitData[n]); 1431 } 1432 n++; 1433 } 1434 rawData = mWifiNative.getBatchedScanResults(); 1435 if (DEBUG_PARSE) log("reading more data:\n" + rawData); 1436 if (rawData == null) { 1437 loge("Unexpected null BatchedScanResults"); 1438 return; 1439 } 1440 splitData = rawData.split("\n"); 1441 if (splitData.length == 0 || splitData[0].equals("ok")) { 1442 loge("batch scan results just ended!"); 1443 if (mBatchedScanResults.size() > 0) { 1444 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1445 } 1446 return; 1447 } 1448 n = 0; 1449 } 1450 } 1451 } 1452 1453 //keeping track of scan requests 1454 private long lastStartScanTimeStamp = 0; 1455 private long lastScanDuration = 0; 1456 //last connect attempt is used to prevent scan requests: 1457 // - for a period of 10 seconds after attempting to connect 1458 private long lastConnectAttempt = 0; 1459 private String lastScanFreqs = null; 1460 1461 //TODO: this is used only to track connection attempts, however the link state and packet per 1462 //TODO: second logic should be folded into that 1463 private boolean isScanAllowed() { 1464 long now = System.currentTimeMillis(); 1465 if (lastConnectAttempt != 0 && (now - lastConnectAttempt) < 10000) { 1466 return false; 1467 } 1468 return true; 1469 } 1470 1471 // If workSource is not null, blame is given to it, otherwise blame is given to callingUid. 1472 private void noteScanStart(int callingUid, WorkSource workSource) { 1473 long now = System.currentTimeMillis(); 1474 lastStartScanTimeStamp = now; 1475 lastScanDuration = 0; 1476 if (DBG) { 1477 String ts = String.format("[%,d ms]", now); 1478 if (workSource != null) { 1479 loge(ts + " noteScanStart" + workSource.toString() 1480 + " uid " + Integer.toString(callingUid)); 1481 } else { 1482 loge(ts + " noteScanstart no scan source"); 1483 } 1484 } 1485 if (mScanWorkSource == null && ((callingUid != UNKNOWN_SCAN_SOURCE 1486 && callingUid != SCAN_ALARM_SOURCE) 1487 || workSource != null)) { 1488 mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid); 1489 try { 1490 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource); 1491 } catch (RemoteException e) { 1492 log(e.toString()); 1493 } 1494 } 1495 } 1496 1497 private void noteScanEnd() { 1498 long now = System.currentTimeMillis(); 1499 if (lastStartScanTimeStamp != 0) { 1500 lastScanDuration = now - lastStartScanTimeStamp; 1501 } 1502 lastStartScanTimeStamp = 0; 1503 if (DBG) { 1504 String ts = String.format("[%,d ms]", now); 1505 1506 if (mScanWorkSource != null) 1507 loge(ts + " noteScanEnd " + mScanWorkSource.toString()); 1508 else 1509 loge(ts + " noteScanEnd no scan source"); 1510 } 1511 if (mScanWorkSource != null) { 1512 try { 1513 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource); 1514 } catch (RemoteException e) { 1515 log(e.toString()); 1516 } finally { 1517 mScanWorkSource = null; 1518 } 1519 } 1520 } 1521 1522 private void noteBatchedScanStart() { 1523 if (PDBG) loge("noteBatchedScanstart()"); 1524 // note the end of a previous scan set 1525 if (mNotedBatchedScanWorkSource != null && 1526 (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false || 1527 mNotedBatchedScanCsph != mBatchedScanCsph)) { 1528 try { 1529 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1530 } catch (RemoteException e) { 1531 log(e.toString()); 1532 } finally { 1533 mNotedBatchedScanWorkSource = null; 1534 mNotedBatchedScanCsph = 0; 1535 } 1536 } 1537 // note the start of the new 1538 try { 1539 mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource, 1540 mBatchedScanCsph); 1541 mNotedBatchedScanWorkSource = mBatchedScanWorkSource; 1542 mNotedBatchedScanCsph = mBatchedScanCsph; 1543 } catch (RemoteException e) { 1544 log(e.toString()); 1545 } 1546 } 1547 1548 private void noteBatchedScanStop() { 1549 if (PDBG) loge("noteBatchedScanstop()"); 1550 1551 if (mNotedBatchedScanWorkSource != null) { 1552 try { 1553 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1554 } catch (RemoteException e) { 1555 log(e.toString()); 1556 } finally { 1557 mNotedBatchedScanWorkSource = null; 1558 mNotedBatchedScanCsph = 0; 1559 } 1560 } 1561 } 1562 1563 private void handleScanRequest(int type, Message message) { 1564 // unbundle parameters 1565 Bundle bundle = (Bundle) message.obj; 1566 ScanSettings settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING); 1567 WorkSource workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE); 1568 1569 // parse scan settings 1570 String freqs = null; 1571 if (settings != null && settings.channelSet != null) { 1572 StringBuilder sb = new StringBuilder(); 1573 boolean first = true; 1574 for (WifiChannel channel : settings.channelSet) { 1575 if (!first) sb.append(','); else first = false; 1576 sb.append(channel.freqMHz); 1577 } 1578 freqs = sb.toString(); 1579 } 1580 1581 // call wifi native to start the scan 1582 if (startScanNative(type, freqs)) { 1583 // only count battery consumption if scan request is accepted 1584 noteScanStart(message.arg1, workSource); 1585 // a full scan covers everything, clearing scan request buffer 1586 if (freqs == null) 1587 mBufferedScanMsg.clear(); 1588 return; 1589 } 1590 1591 // if reach here, scan request is rejected 1592 1593 if (!mIsScanOngoing) { 1594 // if rejection is NOT due to ongoing scan (e.g. bad scan parameters), 1595 // discard this request and pop up the next one 1596 if (mBufferedScanMsg.size() > 0) 1597 sendMessage(mBufferedScanMsg.remove()); 1598 } else if (!mIsFullScanOngoing) { 1599 // if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan, 1600 // buffer the scan request to make sure specified channels will be scanned eventually 1601 if (freqs == null) 1602 mBufferedScanMsg.clear(); 1603 if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) { 1604 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, 0, bundle); 1605 mBufferedScanMsg.add(msg); 1606 } else { 1607 // if too many requests in buffer, combine them into a single full scan 1608 bundle = new Bundle(); 1609 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null); 1610 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1611 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, 0, bundle); 1612 mBufferedScanMsg.clear(); 1613 mBufferedScanMsg.add(msg); 1614 } 1615 } 1616 } 1617 1618 1619 /** return true iff scan request is accepted */ 1620 private boolean startScanNative(int type, String freqs) { 1621 if (mWifiNative.scan(type, freqs)) { 1622 mIsScanOngoing = true; 1623 mIsFullScanOngoing = (freqs == null); 1624 lastScanFreqs = freqs; 1625 return true; 1626 } 1627 return false; 1628 } 1629 1630 /** 1631 * TODO: doc 1632 */ 1633 public void setSupplicantRunning(boolean enable) { 1634 if (enable) { 1635 sendMessage(CMD_START_SUPPLICANT); 1636 } else { 1637 sendMessage(CMD_STOP_SUPPLICANT); 1638 } 1639 } 1640 1641 /** 1642 * TODO: doc 1643 */ 1644 public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) { 1645 if (enable) { 1646 sendMessage(CMD_START_AP, wifiConfig); 1647 } else { 1648 sendMessage(CMD_STOP_AP); 1649 } 1650 } 1651 1652 public void setWifiApConfiguration(WifiConfiguration config) { 1653 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 1654 } 1655 1656 public WifiConfiguration syncGetWifiApConfiguration() { 1657 Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG); 1658 WifiConfiguration ret = (WifiConfiguration) resultMsg.obj; 1659 resultMsg.recycle(); 1660 return ret; 1661 } 1662 1663 /** 1664 * TODO: doc 1665 */ 1666 public int syncGetWifiState() { 1667 return mWifiState.get(); 1668 } 1669 1670 /** 1671 * TODO: doc 1672 */ 1673 public String syncGetWifiStateByName() { 1674 switch (mWifiState.get()) { 1675 case WIFI_STATE_DISABLING: 1676 return "disabling"; 1677 case WIFI_STATE_DISABLED: 1678 return "disabled"; 1679 case WIFI_STATE_ENABLING: 1680 return "enabling"; 1681 case WIFI_STATE_ENABLED: 1682 return "enabled"; 1683 case WIFI_STATE_UNKNOWN: 1684 return "unknown state"; 1685 default: 1686 return "[invalid state]"; 1687 } 1688 } 1689 1690 /** 1691 * TODO: doc 1692 */ 1693 public int syncGetWifiApState() { 1694 return mWifiApState.get(); 1695 } 1696 1697 /** 1698 * TODO: doc 1699 */ 1700 public String syncGetWifiApStateByName() { 1701 switch (mWifiApState.get()) { 1702 case WIFI_AP_STATE_DISABLING: 1703 return "disabling"; 1704 case WIFI_AP_STATE_DISABLED: 1705 return "disabled"; 1706 case WIFI_AP_STATE_ENABLING: 1707 return "enabling"; 1708 case WIFI_AP_STATE_ENABLED: 1709 return "enabled"; 1710 case WIFI_AP_STATE_FAILED: 1711 return "failed"; 1712 default: 1713 return "[invalid state]"; 1714 } 1715 } 1716 1717 /** 1718 * Get status information for the current connection, if any. 1719 * @return a {@link WifiInfo} object containing information about the current connection 1720 * 1721 */ 1722 public WifiInfo syncRequestConnectionInfo() { 1723 return mWifiInfo; 1724 } 1725 1726 public DhcpResults syncGetDhcpResults() { 1727 synchronized (mDhcpResultsLock) { 1728 return new DhcpResults(mDhcpResults); 1729 } 1730 } 1731 1732 /** 1733 * TODO: doc 1734 */ 1735 public void setDriverStart(boolean enable) { 1736 if (enable) { 1737 sendMessage(CMD_START_DRIVER); 1738 } else { 1739 sendMessage(CMD_STOP_DRIVER); 1740 } 1741 } 1742 1743 /** 1744 * TODO: doc 1745 */ 1746 public void setOperationalMode(int mode) { 1747 if (DBG) log("setting operational mode to " + String.valueOf(mode)); 1748 sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0); 1749 } 1750 1751 /** 1752 * TODO: doc 1753 */ 1754 public List<ScanResult> syncGetScanResultsList() { 1755 synchronized (mScanResultCache) { 1756 List<ScanResult> scanList = new ArrayList<ScanResult>(); 1757 for(ScanResult result: mScanResults) { 1758 scanList.add(new ScanResult(result)); 1759 } 1760 return scanList; 1761 } 1762 } 1763 1764 /** 1765 * Disconnect from Access Point 1766 */ 1767 public void disconnectCommand() { 1768 sendMessage(CMD_DISCONNECT); 1769 } 1770 1771 /** 1772 * Initiate a reconnection to AP 1773 */ 1774 public void reconnectCommand() { 1775 sendMessage(CMD_RECONNECT); 1776 } 1777 1778 /** 1779 * Initiate a re-association to AP 1780 */ 1781 public void reassociateCommand() { 1782 sendMessage(CMD_REASSOCIATE); 1783 } 1784 1785 /** 1786 * Reload networks and then reconnect; helps load correct data for TLS networks 1787 */ 1788 1789 public void reloadTlsNetworksAndReconnect() { 1790 sendMessage(CMD_RELOAD_TLS_AND_RECONNECT); 1791 } 1792 1793 /** 1794 * Add a network synchronously 1795 * 1796 * @return network id of the new network 1797 */ 1798 public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) { 1799 Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config); 1800 int result = resultMsg.arg1; 1801 resultMsg.recycle(); 1802 return result; 1803 } 1804 1805 /** 1806 * Get configured networks synchronously 1807 * @param channel 1808 * @return 1809 */ 1810 1811 public List<WifiConfiguration> syncGetConfiguredNetworks(AsyncChannel channel) { 1812 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS); 1813 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 1814 resultMsg.recycle(); 1815 return result; 1816 } 1817 1818 public List<WifiConfiguration> syncGetPrivilegedConfiguredNetwork(AsyncChannel channel) { 1819 Message resultMsg = channel.sendMessageSynchronously( 1820 CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS); 1821 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 1822 resultMsg.recycle(); 1823 return result; 1824 } 1825 1826 1827 /** 1828 * Get connection statistics synchronously 1829 * @param channel 1830 * @return 1831 */ 1832 1833 public WifiConnectionStatistics syncGetConnectionStatistics(AsyncChannel channel) { 1834 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONNECTION_STATISTICS); 1835 WifiConnectionStatistics result = (WifiConnectionStatistics) resultMsg.obj; 1836 resultMsg.recycle(); 1837 return result; 1838 } 1839 1840 /** 1841 * Get adaptors synchronously 1842 */ 1843 1844 public List<WifiAdapter> syncGetAdaptors(AsyncChannel channel) { 1845 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_ADAPTORS); 1846 List<WifiAdapter> result = (List<WifiAdapter>) resultMsg.obj; 1847 resultMsg.recycle(); 1848 return result; 1849 } 1850 1851 /** 1852 * Delete a network 1853 * 1854 * @param networkId id of the network to be removed 1855 */ 1856 public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) { 1857 Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId); 1858 boolean result = (resultMsg.arg1 != FAILURE); 1859 resultMsg.recycle(); 1860 return result; 1861 } 1862 1863 /** 1864 * Enable a network 1865 * 1866 * @param netId network id of the network 1867 * @param disableOthers true, if all other networks have to be disabled 1868 * @return {@code true} if the operation succeeds, {@code false} otherwise 1869 */ 1870 public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) { 1871 Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId, 1872 disableOthers ? 1 : 0); 1873 boolean result = (resultMsg.arg1 != FAILURE); 1874 resultMsg.recycle(); 1875 return result; 1876 } 1877 1878 /** 1879 * Disable a network 1880 * 1881 * @param netId network id of the network 1882 * @return {@code true} if the operation succeeds, {@code false} otherwise 1883 */ 1884 public boolean syncDisableNetwork(AsyncChannel channel, int netId) { 1885 Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId); 1886 boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED); 1887 resultMsg.recycle(); 1888 return result; 1889 } 1890 1891 /** 1892 * Retrieves a WPS-NFC configuration token for the specified network 1893 * @return a hex string representation of the WPS-NFC configuration token 1894 */ 1895 public String syncGetWpsNfcConfigurationToken(int netId) { 1896 return mWifiNative.getNfcWpsConfigurationToken(netId); 1897 } 1898 1899 /** 1900 * Blacklist a BSSID. This will avoid the AP if there are 1901 * alternate APs to connect 1902 * 1903 * @param bssid BSSID of the network 1904 */ 1905 public void addToBlacklist(String bssid) { 1906 sendMessage(CMD_BLACKLIST_NETWORK, bssid); 1907 } 1908 1909 /** 1910 * Clear the blacklist list 1911 * 1912 */ 1913 public void clearBlacklist() { 1914 sendMessage(CMD_CLEAR_BLACKLIST); 1915 } 1916 1917 public void enableRssiPolling(boolean enabled) { 1918 sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0); 1919 } 1920 1921 public void enableBackgroundScanCommand(boolean enabled) { 1922 sendMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0); 1923 } 1924 1925 public void enableAllNetworks() { 1926 sendMessage(CMD_ENABLE_ALL_NETWORKS); 1927 } 1928 1929 /** 1930 * Start filtering Multicast v4 packets 1931 */ 1932 public void startFilteringMulticastV4Packets() { 1933 mFilteringMulticastV4Packets.set(true); 1934 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0); 1935 } 1936 1937 /** 1938 * Stop filtering Multicast v4 packets 1939 */ 1940 public void stopFilteringMulticastV4Packets() { 1941 mFilteringMulticastV4Packets.set(false); 1942 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0); 1943 } 1944 1945 /** 1946 * Start filtering Multicast v4 packets 1947 */ 1948 public void startFilteringMulticastV6Packets() { 1949 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0); 1950 } 1951 1952 /** 1953 * Stop filtering Multicast v4 packets 1954 */ 1955 public void stopFilteringMulticastV6Packets() { 1956 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0); 1957 } 1958 1959 /** 1960 * Set high performance mode of operation. 1961 * Enabling would set active power mode and disable suspend optimizations; 1962 * disabling would set auto power mode and enable suspend optimizations 1963 * @param enable true if enable, false otherwise 1964 */ 1965 public void setHighPerfModeEnabled(boolean enable) { 1966 sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0); 1967 } 1968 1969 /** 1970 * Set the country code 1971 * @param countryCode following ISO 3166 format 1972 * @param persist {@code true} if the setting should be remembered. 1973 */ 1974 public void setCountryCode(String countryCode, boolean persist) { 1975 // If it's a good country code, apply after the current 1976 // wifi connection is terminated; ignore resetting of code 1977 // for now (it is unclear what the chipset should do when 1978 // country code is reset) 1979 int countryCodeSequence = mCountryCodeSequence.incrementAndGet(); 1980 if (TextUtils.isEmpty(countryCode)) { 1981 log("Ignoring resetting of country code"); 1982 } else { 1983 sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, countryCode); 1984 } 1985 } 1986 1987 /** 1988 * Set the operational frequency band 1989 * @param band 1990 * @param persist {@code true} if the setting should be remembered. 1991 */ 1992 public void setFrequencyBand(int band, boolean persist) { 1993 if (persist) { 1994 Settings.Global.putInt(mContext.getContentResolver(), 1995 Settings.Global.WIFI_FREQUENCY_BAND, 1996 band); 1997 } 1998 sendMessage(CMD_SET_FREQUENCY_BAND, band, 0); 1999 } 2000 2001 /** 2002 * Enable TDLS for a specific MAC address 2003 */ 2004 public void enableTdls(String remoteMacAddress, boolean enable) { 2005 int enabler = enable ? 1 : 0; 2006 sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress); 2007 } 2008 2009 /** 2010 * Returns the operational frequency band 2011 */ 2012 public int getFrequencyBand() { 2013 return mFrequencyBand.get(); 2014 } 2015 2016 /** 2017 * Returns the wifi configuration file 2018 */ 2019 public String getConfigFile() { 2020 return mWifiConfigStore.getConfigFile(); 2021 } 2022 2023 /** 2024 * Send a message indicating bluetooth adapter connection state changed 2025 */ 2026 public void sendBluetoothAdapterStateChange(int state) { 2027 sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0); 2028 } 2029 2030 /** 2031 * Save configuration on supplicant 2032 * 2033 * @return {@code true} if the operation succeeds, {@code false} otherwise 2034 * 2035 * TODO: deprecate this 2036 */ 2037 public boolean syncSaveConfig(AsyncChannel channel) { 2038 Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG); 2039 boolean result = (resultMsg.arg1 != FAILURE); 2040 resultMsg.recycle(); 2041 return result; 2042 } 2043 2044 public void updateBatteryWorkSource(WorkSource newSource) { 2045 synchronized (mRunningWifiUids) { 2046 try { 2047 if (newSource != null) { 2048 mRunningWifiUids.set(newSource); 2049 } 2050 if (mIsRunning) { 2051 if (mReportedRunning) { 2052 // If the work source has changed since last time, need 2053 // to remove old work from battery stats. 2054 if (mLastRunningWifiUids.diff(mRunningWifiUids)) { 2055 mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids, 2056 mRunningWifiUids); 2057 mLastRunningWifiUids.set(mRunningWifiUids); 2058 } 2059 } else { 2060 // Now being started, report it. 2061 mBatteryStats.noteWifiRunning(mRunningWifiUids); 2062 mLastRunningWifiUids.set(mRunningWifiUids); 2063 mReportedRunning = true; 2064 } 2065 } else { 2066 if (mReportedRunning) { 2067 // Last reported we were running, time to stop. 2068 mBatteryStats.noteWifiStopped(mLastRunningWifiUids); 2069 mLastRunningWifiUids.clear(); 2070 mReportedRunning = false; 2071 } 2072 } 2073 mWakeLock.setWorkSource(newSource); 2074 } catch (RemoteException ignore) { 2075 } 2076 } 2077 } 2078 2079 @Override 2080 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2081 super.dump(fd, pw, args); 2082 mSupplicantStateTracker.dump(fd, pw, args); 2083 pw.println("mLinkProperties " + mLinkProperties); 2084 pw.println("mWifiInfo " + mWifiInfo); 2085 pw.println("mDhcpResults " + mDhcpResults); 2086 pw.println("mNetworkInfo " + mNetworkInfo); 2087 pw.println("mLastSignalLevel " + mLastSignalLevel); 2088 pw.println("mLastBssid " + mLastBssid); 2089 pw.println("mLastNetworkId " + mLastNetworkId); 2090 pw.println("mOperationalMode " + mOperationalMode); 2091 pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt); 2092 pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 2093 pw.println("Supplicant status " + mWifiNative.status()); 2094 pw.println("mEnableBackgroundScan " + mEnableBackgroundScan); 2095 pw.println("mLastSetCountryCode " + mLastSetCountryCode); 2096 pw.println("mPersistedCountryCode " + mPersistedCountryCode); 2097 pw.println(); 2098 mWifiConfigStore.dump(fd, pw, args); 2099 } 2100 2101 /********************************************************* 2102 * Internal private functions 2103 ********************************************************/ 2104 2105 private void logStateAndMessage(Message message, String state) { 2106 if (mLogMessages) { 2107 //long now = SystemClock.elapsedRealtimeNanos(); 2108 //String ts = String.format("[%,d us]", now/1000); 2109 2110 loge( " " + state + " " + getLogRecString(message)); 2111 } 2112 } 2113 2114 /** 2115 * Return the additional string to be logged by LogRec, default 2116 * 2117 * @param msg that was processed 2118 * @return information to be logged as a String 2119 */ 2120 protected String getLogRecString(Message msg) { 2121 WifiConfiguration config; 2122 StringBuilder sb = new StringBuilder(); 2123 if (mScreenOn) { 2124 sb.append("!"); 2125 } 2126 sb.append(smToString(msg)); 2127 2128 switch (msg.what) { 2129 case CMD_START_SCAN: 2130 sb.append(" "); 2131 sb.append(Integer.toString(msg.arg1)); 2132 sb.append(" "); 2133 sb.append(Integer.toString(msg.arg2)); 2134 if (mIsScanOngoing) sb.append(" onGoing"); 2135 if (mIsFullScanOngoing) sb.append(" full"); 2136 if (lastStartScanTimeStamp != 0) { 2137 sb.append(" started:").append(lastStartScanTimeStamp); 2138 } 2139 if (lastScanDuration != 0) { 2140 sb.append(" dur:").append(lastScanDuration); 2141 } 2142 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2143 sb.append(" f=").append(mWifiInfo.getFrequency()); 2144 sb.append(" sc=").append(mWifiInfo.score); 2145 sb.append(" link=").append(mWifiInfo.getLinkSpeed()); 2146 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate)); 2147 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate)); 2148 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate)); 2149 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate)); 2150 if (lastScanFreqs != null) sb.append(" ").append(lastScanFreqs); 2151 break; 2152 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2153 sb.append(" "); 2154 sb.append(Integer.toString(msg.arg1)); 2155 sb.append(" "); 2156 sb.append(Integer.toString(msg.arg2)); 2157 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj; 2158 if (stateChangeResult != null) { 2159 sb.append(stateChangeResult.toString()); 2160 } 2161 break; 2162 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 2163 sb.append(" "); 2164 sb.append(Integer.toString(msg.arg1)); 2165 sb.append(" "); 2166 sb.append(Integer.toString(msg.arg2)); 2167 String bssid = (String)msg.obj; 2168 if (bssid != null && bssid.length()>0) { 2169 sb.append(" "); 2170 sb.append(bssid); 2171 } 2172 sb.append(" blacklist=" + Boolean.toString(didBlackListBSSID)); 2173 break; 2174 case WifiMonitor.SCAN_RESULTS_EVENT: 2175 sb.append(" "); 2176 sb.append(Integer.toString(msg.arg1)); 2177 sb.append(" "); 2178 sb.append(Integer.toString(msg.arg2)); 2179 if (mScanResults != null) { 2180 sb.append(mScanResults.size()); 2181 } 2182 if (lastScanDuration != 0) { 2183 sb.append(" dur:").append(lastScanDuration); 2184 } 2185 break; 2186 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2187 sb.append(" "); 2188 sb.append(Integer.toString(msg.arg1)); 2189 sb.append(" "); 2190 sb.append(Integer.toString(msg.arg2)); 2191 sb.append(" ").append(mLastBssid); 2192 sb.append(" nid=").append(mLastNetworkId); 2193 config = getCurrentWifiConfiguration(); 2194 if (config != null) { 2195 sb.append(" ").append(config.configKey()); 2196 } 2197 break; 2198 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2199 if (msg.obj != null) { 2200 sb.append(" ").append((String)msg.obj); 2201 } 2202 sb.append(" nid=").append(msg.arg1); 2203 sb.append(" reason=").append(msg.arg2); 2204 if (mLastBssid != null) { 2205 sb.append(" lastbssid=").append(mLastBssid); 2206 } 2207 if (mWifiInfo.getFrequency() != -1) { 2208 sb.append(" freq=").append(mWifiInfo.getFrequency()); 2209 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2210 } 2211 if (linkDebouncing) { 2212 sb.append(" debounce"); 2213 } 2214 break; 2215 case WifiMonitor.SSID_TEMP_DISABLED: 2216 case WifiMonitor.SSID_REENABLED: 2217 sb.append(" nid=").append(msg.arg1); 2218 if (msg.obj != null) { 2219 sb.append(" ").append((String)msg.obj); 2220 } 2221 break; 2222 case CMD_RSSI_POLL: 2223 case CMD_UNWANTED_NETWORK: 2224 case WifiManager.RSSI_PKTCNT_FETCH: 2225 sb.append(" "); 2226 sb.append(Integer.toString(msg.arg1)); 2227 sb.append(" "); 2228 sb.append(Integer.toString(msg.arg2)); 2229 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2230 sb.append(" f=").append(mWifiInfo.getFrequency()); 2231 sb.append(" sc=").append(mWifiInfo.score); 2232 sb.append(" link=").append(mWifiInfo.getLinkSpeed()); 2233 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate)); 2234 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate)); 2235 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate)); 2236 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate)); 2237 break; 2238 case CMD_AUTO_CONNECT: 2239 case WifiManager.CONNECT_NETWORK: 2240 sb.append(" "); 2241 sb.append(Integer.toString(msg.arg1)); 2242 sb.append(" "); 2243 sb.append(Integer.toString(msg.arg2)); 2244 config = (WifiConfiguration) msg.obj; 2245 if (config != null) { 2246 sb.append(" ").append(config.configKey()); 2247 if (config.visibility != null) { 2248 sb.append(" [").append(config.visibility.num24); 2249 sb.append(" ,").append(config.visibility.rssi24); 2250 sb.append(" ;").append(config.visibility.num5); 2251 sb.append(" ,").append(config.visibility.rssi5).append("]"); 2252 } 2253 } 2254 break; 2255 case CMD_AUTO_ROAM: 2256 sb.append(" "); 2257 sb.append(Integer.toString(msg.arg1)); 2258 sb.append(" "); 2259 sb.append(Integer.toString(msg.arg2)); 2260 ScanResult result = (ScanResult)msg.obj; 2261 if (result != null) { 2262 sb.append(" rssi=").append(result.level); 2263 sb.append(" freq=").append(result.frequency); 2264 sb.append(" ").append(result.BSSID); 2265 } 2266 break; 2267 case CMD_ENABLE_NETWORK: 2268 sb.append(" "); 2269 sb.append(Integer.toString(msg.arg1)); 2270 sb.append(" "); 2271 sb.append(Integer.toString(msg.arg2)); 2272 String key = mWifiConfigStore.getLastSelectedConfiguration(); 2273 if (key != null) { 2274 sb.append(" ").append(key); 2275 } 2276 break; 2277 case CMD_GET_CONFIGURED_NETWORKS: 2278 sb.append(" "); 2279 sb.append(Integer.toString(msg.arg1)); 2280 sb.append(" "); 2281 sb.append(Integer.toString(msg.arg2)); 2282 sb.append(" num=").append(mWifiConfigStore.getConfiguredNetworksSize()); 2283 break; 2284 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 2285 sb.append(" "); 2286 sb.append(Integer.toString(msg.arg1)); 2287 sb.append(" "); 2288 sb.append(Integer.toString(msg.arg2)); 2289 if (msg.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 2290 sb.append(" OK "); 2291 } else if (msg.arg1 == DhcpStateMachine.DHCP_FAILURE) { 2292 sb.append(" FAIL "); 2293 } 2294 if (mLinkProperties != null) { 2295 if (mLinkProperties.hasIPv4Address()) { 2296 sb.append(" v4"); 2297 } 2298 if (mLinkProperties.hasGlobalIPv6Address()) { 2299 sb.append(" v6"); 2300 } 2301 if (mLinkProperties.hasIPv4DefaultRoute()) { 2302 sb.append(" v4r"); 2303 } 2304 if (mLinkProperties.hasIPv6DefaultRoute()) { 2305 sb.append(" v6r"); 2306 } 2307 if (mLinkProperties.hasIPv4DnsServer()) { 2308 sb.append(" v4dns"); 2309 } 2310 if (mLinkProperties.hasIPv6DnsServer()) { 2311 sb.append(" v6dns"); 2312 } 2313 } 2314 break; 2315 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 2316 sb.append(" "); 2317 sb.append(Integer.toString(msg.arg1)); 2318 sb.append(" "); 2319 sb.append(Integer.toString(msg.arg2)); 2320 if (msg.obj != null) { 2321 NetworkInfo info = (NetworkInfo)msg.obj; 2322 NetworkInfo.State state = info.getState(); 2323 NetworkInfo.DetailedState detailedState = info.getDetailedState(); 2324 if (state != null) { 2325 sb.append(" st=").append(state); 2326 } 2327 if (detailedState != null) { 2328 sb.append("/").append(detailedState); 2329 } 2330 } 2331 break; 2332 case CMD_IP_CONFIGURATION_LOST: 2333 int count = -1; 2334 WifiConfiguration c = getCurrentWifiConfiguration(); 2335 if (c != null) count = c.numConnectionFailures; 2336 sb.append(" "); 2337 sb.append(Integer.toString(msg.arg1)); 2338 sb.append(" "); 2339 sb.append(Integer.toString(msg.arg2)); 2340 sb.append(" failures: "); 2341 sb.append(Integer.toString(count)); 2342 sb.append("/"); 2343 sb.append(Integer.toString(mWifiConfigStore.getMaxDhcpRetries())); 2344 break; 2345 case CMD_UPDATE_LINKPROPERTIES: 2346 sb.append(" "); 2347 sb.append(Integer.toString(msg.arg1)); 2348 sb.append(" "); 2349 sb.append(Integer.toString(msg.arg2)); 2350 if (mLinkProperties != null) { 2351 if (mLinkProperties.hasIPv4Address()) { 2352 sb.append(" v4"); 2353 } 2354 if (mLinkProperties.hasGlobalIPv6Address()) { 2355 sb.append(" v6"); 2356 } 2357 if (mLinkProperties.hasIPv4DefaultRoute()) { 2358 sb.append(" v4r"); 2359 } 2360 if (mLinkProperties.hasIPv6DefaultRoute()) { 2361 sb.append(" v6r"); 2362 } 2363 if (mLinkProperties.hasIPv4DnsServer()) { 2364 sb.append(" v4dns"); 2365 } 2366 if (mLinkProperties.hasIPv6DnsServer()) { 2367 sb.append(" v6dns"); 2368 } 2369 } 2370 break; 2371 default: 2372 sb.append(" "); 2373 sb.append(Integer.toString(msg.arg1)); 2374 sb.append(" "); 2375 sb.append(Integer.toString(msg.arg2)); 2376 break; 2377 } 2378 2379 return sb.toString(); 2380 } 2381 2382 private void handleScreenStateChanged(boolean screenOn) { 2383 mScreenOn = screenOn; 2384 if (PDBG) { 2385 loge(" handleScreenStateChanged Enter: screenOn=" + screenOn 2386 + "mCurrentScanAlarmMs = " + Long.toString(mCurrentScanAlarmMs) 2387 + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt 2388 + " autojoin " + mFrameworkAutoJoin 2389 + " state " + getCurrentState().getName() 2390 + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); 2391 } 2392 enableRssiPolling(screenOn); 2393 if (mBackgroundScanSupported) { 2394 enableBackgroundScanCommand(screenOn == false); 2395 } 2396 2397 if (screenOn) enableAllNetworks(); 2398 if (mUserWantsSuspendOpt.get()) { 2399 if (screenOn) { 2400 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0); 2401 } else { 2402 //Allow 2s for suspend optimizations to be set 2403 mSuspendWakeLock.acquire(2000); 2404 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0); 2405 } 2406 } 2407 mScreenBroadcastReceived.set(true); 2408 2409 if (screenOn) { 2410 fullBandConnectedTimeIntervalMilli = 20 * 1000; //start at 20 seconds interval 2411 if (mFrameworkAutoJoin.get()) { 2412 //start the scan alarm so as to enable autojoin 2413 if (getCurrentState() == mConnectedState) { 2414 mCurrentScanAlarmMs = mConnectedScanPeriodMs; 2415 } else if (getCurrentState() == mDisconnectedState) { 2416 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 2417 //kick a scan right now 2418 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 2419 } else if (getCurrentState() == mDisconnectingState) { 2420 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 2421 //kick a scan right now 2422 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 2423 } 2424 } 2425 setScanAlarm(true); 2426 2427 } else { 2428 setScanAlarm(false); 2429 } 2430 2431 if (DBG) log("handleScreenStateChanged Exit: " + screenOn); 2432 } 2433 2434 private void checkAndSetConnectivityInstance() { 2435 if (mCm == null) { 2436 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 2437 } 2438 } 2439 2440 private boolean startTethering(ArrayList<String> available) { 2441 2442 boolean wifiAvailable = false; 2443 2444 checkAndSetConnectivityInstance(); 2445 2446 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 2447 2448 for (String intf : available) { 2449 for (String regex : wifiRegexs) { 2450 if (intf.matches(regex)) { 2451 2452 InterfaceConfiguration ifcg = null; 2453 try { 2454 ifcg = mNwService.getInterfaceConfig(intf); 2455 if (ifcg != null) { 2456 /* IP/netmask: 192.168.43.1/255.255.255.0 */ 2457 ifcg.setLinkAddress(new LinkAddress( 2458 NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); 2459 ifcg.setInterfaceUp(); 2460 2461 mNwService.setInterfaceConfig(intf, ifcg); 2462 } 2463 } catch (Exception e) { 2464 loge("Error configuring interface " + intf + ", :" + e); 2465 return false; 2466 } 2467 2468 if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 2469 loge("Error tethering on " + intf); 2470 return false; 2471 } 2472 mTetherInterfaceName = intf; 2473 return true; 2474 } 2475 } 2476 } 2477 // We found no interfaces to tether 2478 return false; 2479 } 2480 2481 private void stopTethering() { 2482 2483 checkAndSetConnectivityInstance(); 2484 2485 /* Clear the interface config to allow dhcp correctly configure new 2486 ip settings */ 2487 InterfaceConfiguration ifcg = null; 2488 try { 2489 ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName); 2490 if (ifcg != null) { 2491 ifcg.setLinkAddress( 2492 new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); 2493 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg); 2494 } 2495 } catch (Exception e) { 2496 loge("Error resetting interface " + mTetherInterfaceName + ", :" + e); 2497 } 2498 2499 if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 2500 loge("Untether initiate failed!"); 2501 } 2502 } 2503 2504 private boolean isWifiTethered(ArrayList<String> active) { 2505 2506 checkAndSetConnectivityInstance(); 2507 2508 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 2509 for (String intf : active) { 2510 for (String regex : wifiRegexs) { 2511 if (intf.matches(regex)) { 2512 return true; 2513 } 2514 } 2515 } 2516 // We found no interfaces that are tethered 2517 return false; 2518 } 2519 2520 /** 2521 * Set the country code from the system setting value, if any. 2522 */ 2523 private void setCountryCode() { 2524 String countryCode = Settings.Global.getString(mContext.getContentResolver(), 2525 Settings.Global.WIFI_COUNTRY_CODE); 2526 if (countryCode != null && !countryCode.isEmpty()) { 2527 setCountryCode(countryCode, false); 2528 } else { 2529 //use driver default 2530 } 2531 } 2532 2533 /** 2534 * Set the frequency band from the system setting value, if any. 2535 */ 2536 private void setFrequencyBand() { 2537 int band = Settings.Global.getInt(mContext.getContentResolver(), 2538 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO); 2539 setFrequencyBand(band, false); 2540 } 2541 2542 private void setSuspendOptimizationsNative(int reason, boolean enabled) { 2543 if (DBG) { 2544 log("setSuspendOptimizationsNative: " + reason + " " + enabled 2545 + " -want " + mUserWantsSuspendOpt.get() 2546 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2547 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 2548 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 2549 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 2550 } 2551 //mWifiNative.setSuspendOptimizations(enabled); 2552 2553 if (enabled) { 2554 mSuspendOptNeedsDisabled &= ~reason; 2555 /* None of dhcp, screen or highperf need it disabled and user wants it enabled */ 2556 if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) { 2557 if (DBG) { 2558 log("setSuspendOptimizationsNative do it " + reason + " " + enabled 2559 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2560 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 2561 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 2562 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 2563 } 2564 mWifiNative.setSuspendOptimizations(true); 2565 } 2566 } else { 2567 mSuspendOptNeedsDisabled |= reason; 2568 mWifiNative.setSuspendOptimizations(false); 2569 } 2570 } 2571 2572 private void setSuspendOptimizations(int reason, boolean enabled) { 2573 if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled); 2574 if (enabled) { 2575 mSuspendOptNeedsDisabled &= ~reason; 2576 } else { 2577 mSuspendOptNeedsDisabled |= reason; 2578 } 2579 if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 2580 } 2581 2582 private void setWifiState(int wifiState) { 2583 final int previousWifiState = mWifiState.get(); 2584 2585 try { 2586 if (wifiState == WIFI_STATE_ENABLED) { 2587 mBatteryStats.noteWifiOn(); 2588 } else if (wifiState == WIFI_STATE_DISABLED) { 2589 mBatteryStats.noteWifiOff(); 2590 } 2591 } catch (RemoteException e) { 2592 loge("Failed to note battery stats in wifi"); 2593 } 2594 2595 mWifiState.set(wifiState); 2596 2597 if (DBG) log("setWifiState: " + syncGetWifiStateByName()); 2598 2599 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 2600 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2601 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 2602 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 2603 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2604 } 2605 2606 private void setWifiApState(int wifiApState) { 2607 final int previousWifiApState = mWifiApState.get(); 2608 2609 try { 2610 if (wifiApState == WIFI_AP_STATE_ENABLED) { 2611 mBatteryStats.noteWifiOn(); 2612 } else if (wifiApState == WIFI_AP_STATE_DISABLED) { 2613 mBatteryStats.noteWifiOff(); 2614 } 2615 } catch (RemoteException e) { 2616 loge("Failed to note battery stats in wifi"); 2617 } 2618 2619 // Update state 2620 mWifiApState.set(wifiApState); 2621 2622 if (DBG) log("setWifiApState: " + syncGetWifiApStateByName()); 2623 2624 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 2625 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2626 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); 2627 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); 2628 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2629 } 2630 2631 private static final String ID_STR = "id="; 2632 private static final String BSSID_STR = "bssid="; 2633 private static final String FREQ_STR = "freq="; 2634 private static final String LEVEL_STR = "level="; 2635 private static final String TSF_STR = "tsf="; 2636 private static final String FLAGS_STR = "flags="; 2637 private static final String SSID_STR = "ssid="; 2638 private static final String DELIMITER_STR = "===="; 2639 private static final String END_STR = "####"; 2640 2641 /** 2642 * Format: 2643 * 2644 * id=1 2645 * bssid=68:7f:76:d7:1a:6e 2646 * freq=2412 2647 * level=-44 2648 * tsf=1344626243700342 2649 * flags=[WPA2-PSK-CCMP][WPS][ESS] 2650 * ssid=zfdy 2651 * ==== 2652 * id=2 2653 * bssid=68:5f:74:d7:1a:6f 2654 * freq=5180 2655 * level=-73 2656 * tsf=1344626243700373 2657 * flags=[WPA2-PSK-CCMP][WPS][ESS] 2658 * ssid=zuby 2659 * ==== 2660 */ 2661 private void setScanResults() { 2662 String bssid = ""; 2663 int level = 0; 2664 int freq = 0; 2665 long tsf = 0; 2666 String flags = ""; 2667 WifiSsid wifiSsid = null; 2668 String scanResults; 2669 String tmpResults; 2670 StringBuffer scanResultsBuf = new StringBuffer(); 2671 int sid = 0; 2672 2673 while (true) { 2674 tmpResults = mWifiNative.scanResults(sid); 2675 if (TextUtils.isEmpty(tmpResults)) break; 2676 scanResultsBuf.append(tmpResults); 2677 scanResultsBuf.append("\n"); 2678 String[] lines = tmpResults.split("\n"); 2679 sid = -1; 2680 for (int i=lines.length - 1; i >= 0; i--) { 2681 if (lines[i].startsWith(END_STR)) { 2682 break; 2683 } else if (lines[i].startsWith(ID_STR)) { 2684 try { 2685 sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1; 2686 } catch (NumberFormatException e) { 2687 // Nothing to do 2688 } 2689 break; 2690 } 2691 } 2692 if (sid == -1) break; 2693 } 2694 2695 scanResults = scanResultsBuf.toString(); 2696 if (TextUtils.isEmpty(scanResults)) { 2697 return; 2698 } 2699 2700 // note that all these splits and substrings keep references to the original 2701 // huge string buffer while the amount we really want is generally pretty small 2702 // so make copies instead (one example b/11087956 wasted 400k of heap here). 2703 synchronized(mScanResultCache) { 2704 mScanResults = new ArrayList<ScanResult>(); 2705 String[] lines = scanResults.split("\n"); 2706 final int bssidStrLen = BSSID_STR.length(); 2707 final int flagLen = FLAGS_STR.length(); 2708 2709 for (String line : lines) { 2710 if (line.startsWith(BSSID_STR)) { 2711 bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen); 2712 } else if (line.startsWith(FREQ_STR)) { 2713 try { 2714 freq = Integer.parseInt(line.substring(FREQ_STR.length())); 2715 } catch (NumberFormatException e) { 2716 freq = 0; 2717 } 2718 } else if (line.startsWith(LEVEL_STR)) { 2719 try { 2720 level = Integer.parseInt(line.substring(LEVEL_STR.length())); 2721 /* some implementations avoid negative values by adding 256 2722 * so we need to adjust for that here. 2723 */ 2724 if (level > 0) level -= 256; 2725 } catch(NumberFormatException e) { 2726 level = 0; 2727 } 2728 } else if (line.startsWith(TSF_STR)) { 2729 try { 2730 tsf = Long.parseLong(line.substring(TSF_STR.length())); 2731 } catch (NumberFormatException e) { 2732 tsf = 0; 2733 } 2734 } else if (line.startsWith(FLAGS_STR)) { 2735 flags = new String(line.getBytes(), flagLen, line.length() - flagLen); 2736 } else if (line.startsWith(SSID_STR)) { 2737 wifiSsid = WifiSsid.createFromAsciiEncoded( 2738 line.substring(SSID_STR.length())); 2739 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) { 2740 if (bssid != null) { 2741 String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 2742 String key = bssid + ssid; 2743 ScanResult scanResult = mScanResultCache.get(key); 2744 if (scanResult != null) { 2745 scanResult.level = level; 2746 scanResult.wifiSsid = wifiSsid; 2747 // Keep existing API 2748 scanResult.SSID = (wifiSsid != null) ? wifiSsid.toString() : 2749 WifiSsid.NONE; 2750 scanResult.capabilities = flags; 2751 scanResult.frequency = freq; 2752 scanResult.timestamp = tsf; 2753 scanResult.seen = System.currentTimeMillis(); 2754 } else { 2755 scanResult = 2756 new ScanResult( 2757 wifiSsid, bssid, flags, level, freq, tsf); 2758 mScanResultCache.put(key, scanResult); 2759 } 2760 mScanResults.add(scanResult); 2761 } 2762 bssid = null; 2763 level = 0; 2764 freq = 0; 2765 tsf = 0; 2766 flags = ""; 2767 wifiSsid = null; 2768 } 2769 } 2770 } 2771 boolean attemptAutoJoin = true; 2772 if (getCurrentState() == mRoamingState 2773 || getCurrentState() == mObtainingIpState 2774 || linkDebouncing) { 2775 // Dont attempt auto-joining again while we are already attempting to join 2776 // and/or obtaining Ip address 2777 attemptAutoJoin = false; 2778 } 2779 mWifiAutoJoinController.newSupplicantResults(attemptAutoJoin); 2780 if (linkDebouncing) { 2781 // If debouncing, we dont re-select a SSID or BSSID hence 2782 // there is no need to call the network selection code 2783 // in WifiAutoJoinController, instead, 2784 // just try to reconnect to the same SSID by triggering a roam 2785 sendMessage(CMD_AUTO_ROAM, mLastNetworkId, 1, null); 2786 } 2787 } 2788 2789 /* 2790 * Fetch RSSI, linkspeed, and frequency on current connection 2791 */ 2792 private void fetchRssiLinkSpeedAndFrequencyNative() { 2793 int newRssi = -1; 2794 int newLinkSpeed = -1; 2795 int newFrequency = -1; 2796 2797 String signalPoll = mWifiNative.signalPoll(); 2798 2799 if (signalPoll != null) { 2800 String[] lines = signalPoll.split("\n"); 2801 for (String line : lines) { 2802 String[] prop = line.split("="); 2803 if (prop.length < 2) continue; 2804 try { 2805 if (prop[0].equals("RSSI")) { 2806 newRssi = Integer.parseInt(prop[1]); 2807 } else if (prop[0].equals("LINKSPEED")) { 2808 newLinkSpeed = Integer.parseInt(prop[1]); 2809 } else if (prop[0].equals("FREQUENCY")) { 2810 newFrequency = Integer.parseInt(prop[1]); 2811 } 2812 } catch (NumberFormatException e) { 2813 //Ignore, defaults on rssi and linkspeed are assigned 2814 } 2815 } 2816 } 2817 2818 if (PDBG) { 2819 loge("fetchRssiLinkSpeedAndFrequencyNative rssi=" 2820 + Integer.toString(newRssi) + " linkspeed=" 2821 + Integer.toString(newLinkSpeed)); 2822 } 2823 2824 if (newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) { 2825 // screen out invalid values 2826 /* some implementations avoid negative values by adding 256 2827 * so we need to adjust for that here. 2828 */ 2829 if (newRssi > 0) newRssi -= 256; 2830 mWifiInfo.setRssi(newRssi); 2831 /* 2832 * Rather then sending the raw RSSI out every time it 2833 * changes, we precalculate the signal level that would 2834 * be displayed in the status bar, and only send the 2835 * broadcast if that much more coarse-grained number 2836 * changes. This cuts down greatly on the number of 2837 * broadcasts, at the cost of not informing others 2838 * interested in RSSI of all the changes in signal 2839 * level. 2840 */ 2841 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); 2842 if (newSignalLevel != mLastSignalLevel) { 2843 sendRssiChangeBroadcast(newRssi); 2844 } 2845 mLastSignalLevel = newSignalLevel; 2846 } else { 2847 mWifiInfo.setRssi(WifiInfo.INVALID_RSSI); 2848 } 2849 2850 if (newLinkSpeed != -1) { 2851 mWifiInfo.setLinkSpeed(newLinkSpeed); 2852 } 2853 if (newFrequency > 0) { 2854 if (ScanResult.is24GHz(newFrequency)) { 2855 mWifiConnectionStatistics.num5GhzConnected++; 2856 } 2857 if (ScanResult.is24GHz(newFrequency)) { 2858 mWifiConnectionStatistics.num24GhzConnected++; 2859 } 2860 mWifiInfo.setFrequency(newFrequency); 2861 } 2862 mWifiConfigStore.updateConfiguration(mWifiInfo); 2863 } 2864 2865 /** 2866 * Determine if we need to switch network: 2867 * - the delta determine the urgency to switch and/or or the expected evilness of the disruption 2868 * - match the uregncy of the switch versus the packet usage at the interface 2869 */ 2870 boolean shouldSwitchNetwork(int networkDelta) { 2871 int delta; 2872 if (networkDelta <= 0) { 2873 return false; 2874 } 2875 delta = networkDelta; 2876 if (mWifiInfo != null) { 2877 // TODO: Look at per AC packet count, do not switch if VO/VI traffic is present 2878 // TODO: at the interface. We should also discriminate between ucast and mcast, 2879 // TODO: since the rxSuccessRate include all the bonjour and Ipv6 2880 // TODO: broadcasts 2881 if ((mWifiInfo.txSuccessRate > 20) || (mWifiInfo.rxSuccessRate > 80)) { 2882 delta -= 999; 2883 } else if ((mWifiInfo.txSuccessRate > 5) || (mWifiInfo.rxSuccessRate > 30)) { 2884 delta -= 6; 2885 } 2886 loge("WifiStateMachine shouldSwitchNetwork " 2887 + " txSuccessRate=" + String.format( "%.2f", mWifiInfo.txSuccessRate) 2888 + " rxSuccessRate=" +String.format( "%.2f", mWifiInfo.rxSuccessRate) 2889 + " delta " + networkDelta + " -> " + delta); 2890 } else { 2891 loge("WifiStateMachine shouldSwitchNetwork " 2892 + " delta " + networkDelta + " -> " + delta); 2893 } 2894 if (delta > 0) { 2895 return true; 2896 } 2897 return false; 2898 } 2899 2900 private void calculateWifiScore(WifiLinkLayerStats stats) { 2901 2902 if (stats == null || mWifiLinkLayerStatsSupported <= 0) { 2903 long mTxPkts = TrafficStats.getTxPackets(mInterfaceName); 2904 long mRxPkts = TrafficStats.getRxPackets(mInterfaceName); 2905 mWifiInfo.updatePacketRates(mTxPkts, mRxPkts); 2906 2907 } else { 2908 mWifiInfo.updatePacketRates(stats); 2909 } 2910 int score = 56; //starting score, temporarily hardcoded in between 50 and 60 2911 boolean isBadLinkspeed = (mWifiInfo.is24GHz() 2912 && mWifiInfo.getLinkSpeed() < 6) 2913 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed() < 12); 2914 boolean isGoodLinkspeed = (mWifiInfo.is24GHz() 2915 && mWifiInfo.getLinkSpeed() >= 24) 2916 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed() >= 48); 2917 2918 2919 /** 2920 * We want to make sure that we use the 24GHz RSSI thresholds is 2921 * there are 2.4GHz scan results 2922 * otherwise we end up lowering the score based on 5GHz values 2923 * which may cause a switch to LTE before roaming has a chance to try 2.4GHz 2924 * We also might unblacklist the configuation based on 2.4GHz 2925 * thresholds but joining 5GHz anyhow, and failing over to 2.4GHz because 5GHz is not good 2926 */ 2927 boolean use24Thresholds = false; 2928 boolean homeNetworkBoost = false; 2929 WifiConfiguration currentConfiguration = getCurrentWifiConfiguration(); 2930 if (currentConfiguration != null 2931 && currentConfiguration.scanResultCache != null) { 2932 currentConfiguration.setVisibility(12000); 2933 if (currentConfiguration.visibility != null) { 2934 if (currentConfiguration.visibility.rssi24 != WifiConfiguration.INVALID_RSSI 2935 && currentConfiguration.visibility.rssi24 2936 >= (currentConfiguration.visibility.rssi5-2)) { 2937 use24Thresholds = true; 2938 } 2939 } 2940 if (currentConfiguration.scanResultCache.size() <= 4 2941 && currentConfiguration.allowedKeyManagement.cardinality() == 1 2942 && currentConfiguration.allowedKeyManagement. 2943 get(WifiConfiguration.KeyMgmt.WPA_PSK) == true) { 2944 // A PSK network with less than 4 known BSSIDs 2945 // This is most likely a home network and thus we want to stick to wifi more 2946 homeNetworkBoost = true; 2947 } 2948 } 2949 2950 int rssi = mWifiInfo.getRssi() - 6 * mAggressiveHandover 2951 + (homeNetworkBoost ? WifiConfiguration.HOME_NETWORK_RSSI_BOOST : 0); 2952 boolean is24GHz = use24Thresholds || mWifiInfo.is24GHz(); 2953 2954 boolean isBadRSSI = (is24GHz && rssi < WifiConfiguration.BAD_RSSI_24 ) 2955 || (!is24GHz && rssi < WifiConfiguration.BAD_RSSI_5); 2956 boolean isLowRSSI = (is24GHz && rssi < WifiConfiguration.LOW_RSSI_24) 2957 || (!is24GHz && mWifiInfo.getRssi() < WifiConfiguration.LOW_RSSI_5); 2958 boolean isHighRSSI = (is24GHz && rssi >= WifiConfiguration.GOOD_RSSI_24) 2959 || (!is24GHz && mWifiInfo.getRssi() >= WifiConfiguration.GOOD_RSSI_5); 2960 2961 if (PDBG) { 2962 String rssiStatus = ""; 2963 if (isBadRSSI) rssiStatus += " badRSSI "; 2964 else if (isHighRSSI) rssiStatus += " highRSSI "; 2965 else if (isLowRSSI) rssiStatus += " lowRSSI "; 2966 if (isBadLinkspeed) rssiStatus += " lowSpeed "; 2967 loge("calculateWifiScore freq=" + Integer.toString(mWifiInfo.getFrequency()) 2968 + " speed=" + Integer.toString(mWifiInfo.getLinkSpeed()) 2969 + " score=" + Integer.toString(mWifiInfo.score) 2970 + rssiStatus 2971 + " -> txbadrate=" + String.format( "%.2f", mWifiInfo.txBadRate ) 2972 + " txgoodrate=" + String.format("%.2f", mWifiInfo.txSuccessRate) 2973 + " txretriesrate=" + String.format("%.2f", mWifiInfo.txRetriesRate) 2974 + " rxrate=" + String.format("%.2f", mWifiInfo.rxSuccessRate) 2975 ); 2976 } 2977 2978 if ((mWifiInfo.txBadRate >= 1) && (mWifiInfo.txSuccessRate < 3) 2979 && (isBadRSSI || isLowRSSI)) { 2980 // Link is stuck 2981 if (mWifiInfo.linkStuckCount < 5) 2982 mWifiInfo.linkStuckCount += 1; 2983 if (PDBG) loge(" bad link -> stuck count =" 2984 + Integer.toString(mWifiInfo.linkStuckCount)); 2985 } else if (mWifiInfo.txSuccessRate > 2 || mWifiInfo.txBadRate < 0.1) { 2986 if (mWifiInfo.linkStuckCount > 0) 2987 mWifiInfo.linkStuckCount -= 1; 2988 if (PDBG) loge(" good link -> stuck count =" 2989 + Integer.toString(mWifiInfo.linkStuckCount)); 2990 } 2991 2992 if (mWifiInfo.linkStuckCount > 1) { 2993 // Once link gets stuck for more than 3 seconds, start reducing the score 2994 score = score - 2 * (mWifiInfo.linkStuckCount - 1); 2995 } 2996 2997 if (isBadLinkspeed) { 2998 score -= 4; 2999 if (PDBG) loge(" isBadLinkspeed ---> score=" + Integer.toString(score)); 3000 } else if ((isGoodLinkspeed) && (mWifiInfo.txSuccessRate > 5)) { 3001 score += 4; // So as bad rssi alone dont kill us 3002 } 3003 3004 if (isBadRSSI) { 3005 if (mWifiInfo.badRssiCount < 7) 3006 mWifiInfo.badRssiCount += 1; 3007 } else if (isLowRSSI) { 3008 mWifiInfo.lowRssiCount = 1; // Dont increment 3009 if (mWifiInfo.badRssiCount > 0) { 3010 mWifiInfo.badRssiCount -= 1; 3011 } 3012 } else { 3013 mWifiInfo.badRssiCount = 0; 3014 mWifiInfo.lowRssiCount = 0; 3015 } 3016 3017 score -= mWifiInfo.badRssiCount * 2 + mWifiInfo.lowRssiCount ; 3018 3019 if (PDBG) loge(" badRSSI count" + Integer.toString(mWifiInfo.badRssiCount) 3020 + " lowRSSI count" + Integer.toString(mWifiInfo.lowRssiCount) 3021 + " --> score " + Integer.toString(score)); 3022 3023 3024 if (isHighRSSI) { 3025 score += 5; 3026 if (PDBG) loge(" isHighRSSI ---> score=" + Integer.toString(score)); 3027 } 3028 3029 //sanitize boundaries 3030 if (score > NetworkAgent.WIFI_BASE_SCORE) 3031 score = NetworkAgent.WIFI_BASE_SCORE; 3032 if (score < 0) 3033 score = 0; 3034 3035 //report score 3036 if (score != mWifiInfo.score) { 3037 if (DBG) { 3038 loge("calculateWifiScore() report new score " + Integer.toString(score)); 3039 } 3040 mWifiInfo.score = score; 3041 if (mNetworkAgent != null) { 3042 mNetworkAgent.sendNetworkScore(score); 3043 } 3044 } 3045 } 3046 3047 public double getTxPacketRate() { 3048 if (mWifiInfo != null) { 3049 return mWifiInfo.txSuccessRate; 3050 } 3051 return -1; 3052 } 3053 3054 public double getRxPacketRate() { 3055 if (mWifiInfo != null) { 3056 return mWifiInfo.rxSuccessRate; 3057 } 3058 return -1; 3059 } 3060 3061 /** 3062 * Fetch TX packet counters on current connection 3063 */ 3064 private void fetchPktcntNative(RssiPacketCountInfo info) { 3065 String pktcntPoll = mWifiNative.pktcntPoll(); 3066 3067 if (pktcntPoll != null) { 3068 String[] lines = pktcntPoll.split("\n"); 3069 for (String line : lines) { 3070 String[] prop = line.split("="); 3071 if (prop.length < 2) continue; 3072 try { 3073 if (prop[0].equals("TXGOOD")) { 3074 info.txgood = Integer.parseInt(prop[1]); 3075 } else if (prop[0].equals("TXBAD")) { 3076 info.txbad = Integer.parseInt(prop[1]); 3077 } 3078 } catch (NumberFormatException e) { 3079 // Ignore 3080 } 3081 } 3082 } 3083 } 3084 3085 private boolean isProvisioned(LinkProperties lp) { 3086 // LinkProperties#isProvisioned returns true even if all we have is an IPv4 address and no 3087 // connectivity. This turns out not to be very useful, because we can't distinguish it from 3088 // a state where we have an IPv4 address assigned to the interface but are still running 3089 // DHCP. 3090 // TODO: Fix LinkProperties and remove this function. 3091 if (mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 3092 return lp.hasIPv4Address(); 3093 } else { 3094 return (lp.hasIPv4Address() && lp.hasIPv4DefaultRoute() && lp.hasIPv4DnsServer()) || 3095 (lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute() && lp.hasIPv6DnsServer()); 3096 } 3097 } 3098 3099 /** 3100 * Updates mLinkProperties by merging information from various sources. 3101 * 3102 * This is needed because the information in mLinkProperties comes from multiple sources (DHCP, 3103 * netlink, static configuration, ...). When one of these sources of information has updated 3104 * link properties, we can't just assign them to mLinkProperties or we'd lose track of the 3105 * information that came from other sources. Instead, when one of those sources has new 3106 * information, we update the object that tracks the information from that source and then 3107 * call this method to apply the change to mLinkProperties. 3108 * 3109 * The information in mLinkProperties is currently obtained as follows: 3110 * - Interface name: set in the constructor. 3111 * - IPv4 and IPv6 addresses: netlink, passed in by mNetlinkTracker. 3112 * - IPv4 routes, DNS servers, and domains: DHCP. 3113 * - IPv6 routes and DNS servers: netlink, passed in by mNetlinkTracker. 3114 * - HTTP proxy: the wifi config store. 3115 */ 3116 private void updateLinkProperties(int reason) { 3117 LinkProperties newLp = new LinkProperties(); 3118 3119 // Interface name and proxy are locally configured. 3120 newLp.setInterfaceName(mInterfaceName); 3121 newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); 3122 3123 // IPv4/v6 addresses, IPv6 routes and IPv6 DNS servers come from netlink. 3124 LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties(); 3125 newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses()); 3126 for (RouteInfo route : netlinkLinkProperties.getRoutes()) { 3127 newLp.addRoute(route); 3128 } 3129 for (InetAddress dns : netlinkLinkProperties.getDnsServers()) { 3130 newLp.addDnsServer(dns); 3131 } 3132 3133 // IPv4 routes, DNS servers and domains come from mDhcpResults. 3134 synchronized (mDhcpResultsLock) { 3135 // Even when we're using static configuration, we don't need to look at the config 3136 // store, because static IP configuration also populates mDhcpResults. 3137 if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) { 3138 LinkProperties lp = mDhcpResults.linkProperties; 3139 for (RouteInfo route : lp.getRoutes()) { 3140 newLp.addRoute(route); 3141 } 3142 for (InetAddress dns : lp.getDnsServers()) { 3143 newLp.addDnsServer(dns); 3144 } 3145 newLp.setDomains(lp.getDomains()); 3146 } 3147 } 3148 3149 final boolean linkChanged = !newLp.equals(mLinkProperties); 3150 final boolean wasProvisioned = isProvisioned(mLinkProperties); 3151 final boolean isProvisioned = isProvisioned(newLp); 3152 final DetailedState detailedState = getNetworkDetailedState(); 3153 3154 if (linkChanged) { 3155 if (DBG) { 3156 log("Link configuration changed for netId: " + mLastNetworkId 3157 + " old: " + mLinkProperties + " new: " + newLp); 3158 } 3159 mLinkProperties = newLp; 3160 mLinkProperties.setTcpBufferSizes(TCP_BUFFER_SIZES_WIFI); 3161 if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); 3162 } 3163 3164 if (DBG) { 3165 StringBuilder sb = new StringBuilder(); 3166 sb.append("updateLinkProperties nid: " + mLastNetworkId); 3167 sb.append(" state: " + detailedState); 3168 sb.append(" reason: " + smToString(reason)); 3169 3170 if (mLinkProperties != null) { 3171 if (mLinkProperties.hasIPv4Address()) { 3172 sb.append(" v4"); 3173 } 3174 if (mLinkProperties.hasGlobalIPv6Address()) { 3175 sb.append(" v6"); 3176 } 3177 if (mLinkProperties.hasIPv4DefaultRoute()) { 3178 sb.append(" v4r"); 3179 } 3180 if (mLinkProperties.hasIPv6DefaultRoute()) { 3181 sb.append(" v6r"); 3182 } 3183 if (mLinkProperties.hasIPv4DnsServer()) { 3184 sb.append(" v4dns"); 3185 } 3186 if (mLinkProperties.hasIPv6DnsServer()) { 3187 sb.append(" v6dns"); 3188 } 3189 if (isProvisioned) { 3190 sb.append(" isprov"); 3191 } 3192 } 3193 loge(sb.toString()); 3194 } 3195 3196 // If we just configured or lost IP configuration, do the needful. 3197 // We don't just call handleSuccessfulIpConfiguration() or handleIpConfigurationLost() 3198 // here because those should only be called if we're attempting to connect or already 3199 // connected, whereas updateLinkProperties can be called at any time. 3200 switch (reason) { 3201 case DhcpStateMachine.DHCP_SUCCESS: 3202 case CMD_STATIC_IP_SUCCESS: 3203 // IPv4 provisioning succeded. Advance to connected state. 3204 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 3205 if (!isProvisioned) { 3206 // Can never happen unless DHCP reports success but isProvisioned thinks the 3207 // resulting configuration is invalid (e.g., no IPv4 address, or the state in 3208 // mLinkProperties is out of sync with reality, or there's a bug in this code). 3209 // TODO: disconnect here instead. If our configuration is not usable, there's no 3210 // point in staying connected, and if mLinkProperties is out of sync with 3211 // reality, that will cause problems in the future. 3212 loge("IPv4 config succeeded, but not provisioned"); 3213 } 3214 break; 3215 3216 case DhcpStateMachine.DHCP_FAILURE: 3217 // DHCP failed. If we're not already provisioned, give up and disconnect. 3218 // If we're already provisioned (e.g., IPv6-only network), stay connected. 3219 if (!isProvisioned) { 3220 sendMessage(CMD_IP_CONFIGURATION_LOST); 3221 } else { 3222 // DHCP failed, but we're provisioned (e.g., if we're on an IPv6-only network). 3223 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 3224 3225 // To be sure we don't get stuck with a non-working network if all we had is 3226 // IPv4, remove the IPv4 address from the interface (since we're using DHCP, 3227 // and DHCP failed). If we had an IPv4 address before, the deletion of the 3228 // address will cause a CMD_UPDATE_LINKPROPERTIES. If the IPv4 address was 3229 // necessary for provisioning, its deletion will cause us to disconnect. 3230 // 3231 // This should never happen, because a DHCP failure will have empty DhcpResults 3232 // and thus empty LinkProperties, and isProvisioned will not return true if 3233 // we're using DHCP and don't have an IPv4 default route. So for now it's only 3234 // here for extra redundancy. However, it will increase robustness if we move 3235 // to getting IPv4 routes from netlink as well. 3236 loge("DHCP failure: provisioned, should not happen! Clearing IPv4 address."); 3237 try { 3238 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 3239 ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0")); 3240 ifcg.setInterfaceUp(); 3241 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 3242 } catch (RemoteException e) { 3243 sendMessage(CMD_IP_CONFIGURATION_LOST); 3244 } 3245 } 3246 break; 3247 3248 case CMD_STATIC_IP_FAILURE: 3249 // Static configuration was invalid, or an error occurred in applying it. Give up. 3250 sendMessage(CMD_IP_CONFIGURATION_LOST); 3251 break; 3252 3253 case CMD_UPDATE_LINKPROPERTIES: 3254 // IP addresses, DNS servers, etc. changed. Act accordingly. 3255 if (wasProvisioned && !isProvisioned) { 3256 // We no longer have a usable network configuration. Disconnect. 3257 sendMessage(CMD_IP_CONFIGURATION_LOST); 3258 } else if (!wasProvisioned && isProvisioned) { 3259 // We have a usable IPv6-only config. Advance to connected state. 3260 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 3261 } 3262 if (linkChanged && getNetworkDetailedState() == DetailedState.CONNECTED) { 3263 // If anything has changed and we're already connected, send out a notification. 3264 sendLinkConfigurationChangedBroadcast(); 3265 } 3266 break; 3267 } 3268 } 3269 3270 /** 3271 * Clears all our link properties. 3272 */ 3273 private void clearLinkProperties() { 3274 // If the network used DHCP, clear the LinkProperties we stored in the config store. 3275 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 3276 mWifiConfigStore.clearLinkProperties(mLastNetworkId); 3277 } 3278 3279 // Clear the link properties obtained from DHCP and netlink. 3280 synchronized (mDhcpResultsLock) { 3281 if (mDhcpResults != null && mDhcpResults.linkProperties != null) { 3282 mDhcpResults.linkProperties.clear(); 3283 } 3284 } 3285 mNetlinkTracker.clearLinkProperties(); 3286 3287 // Now clear the merged link properties. 3288 mLinkProperties.clear(); 3289 if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); 3290 } 3291 3292 /** 3293 * try to update default route MAC address. 3294 */ 3295 private String updateDefaultRouteMacAddress(int timeout) { 3296 String address = null; 3297 for (RouteInfo route : mLinkProperties.getRoutes()) { 3298 if (route.isDefaultRoute() && route.hasGateway()) { 3299 InetAddress gateway = route.getGateway(); 3300 if (gateway instanceof Inet4Address) { 3301 if (PDBG) { 3302 loge("updateDefaultRouteMacAddress found Ipv4 default :" 3303 + gateway.getHostAddress()); 3304 } 3305 address = macAddressFromRoute(gateway.getHostAddress()); 3306 /* The gateway's MAC address is known */ 3307 if ((address == null) && (timeout > 0)) { 3308 boolean reachable = false; 3309 try { 3310 reachable = gateway.isReachable(timeout); 3311 } catch (Exception e) { 3312 loge("updateDefaultRouteMacAddress exception reaching :" 3313 + gateway.getHostAddress()); 3314 3315 } finally { 3316 if (reachable == true) { 3317 3318 address = macAddressFromRoute(gateway.getHostAddress()); 3319 if (PDBG) { 3320 loge("updateDefaultRouteMacAddress reachable (tried again) :" 3321 + gateway.getHostAddress() + " found " + address); 3322 } 3323 } 3324 } 3325 } 3326 if (address != null) { 3327 mWifiConfigStore.setLinkProperties(mLastNetworkId, 3328 new LinkProperties(mLinkProperties)); 3329 mWifiConfigStore.setDefaultGwMacAddress(mLastNetworkId, address); 3330 3331 } 3332 } 3333 } 3334 } 3335 return address; 3336 } 3337 3338 private void sendScanResultsAvailableBroadcast() { 3339 noteScanEnd(); 3340 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 3341 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3342 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 3343 } 3344 3345 private void sendRssiChangeBroadcast(final int newRssi) { 3346 try { 3347 mBatteryStats.noteWifiRssiChanged(newRssi); 3348 } catch (RemoteException e) { 3349 // Won't happen. 3350 } 3351 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); 3352 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3353 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); 3354 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3355 } 3356 3357 private void sendNetworkStateChangeBroadcast(String bssid) { 3358 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); 3359 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3360 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 3361 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties)); 3362 if (bssid != null) 3363 intent.putExtra(WifiManager.EXTRA_BSSID, bssid); 3364 if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK || 3365 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { 3366 intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo)); 3367 } 3368 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3369 } 3370 3371 private void sendLinkConfigurationChangedBroadcast() { 3372 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); 3373 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3374 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); 3375 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 3376 } 3377 3378 private void sendSupplicantConnectionChangedBroadcast(boolean connected) { 3379 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 3380 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3381 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); 3382 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 3383 } 3384 3385 /** 3386 * Record the detailed state of a network. 3387 * @param state the new {@code DetailedState} 3388 */ 3389 private void setNetworkDetailedState(NetworkInfo.DetailedState state) { 3390 boolean hidden = false; 3391 3392 if (linkDebouncing || isRoaming()) { 3393 // There is generally a confusion in the system about colluding 3394 // WiFi Layer 2 state (as reported by supplicant) and the Network state 3395 // which leads to multiple confusion. 3396 // 3397 // If link is de-bouncing or roaming, we already have an IP address 3398 // as well we were connected and are doing L2 cycles of 3399 // reconnecting or renewing IP address to check that we still have it 3400 // This L2 link flapping should ne be reflected into the Network state 3401 // which is the state of the WiFi Network visible to Layer 3 and applications 3402 // Note that once debouncing and roaming are completed, we will 3403 // set the Network state to where it should be, or leave it as unchanged 3404 // 3405 hidden = true; 3406 } 3407 if (DBG) { 3408 log("setDetailed state, old =" 3409 + mNetworkInfo.getDetailedState() + " and new state=" + state 3410 + " hidden=" + hidden); 3411 } 3412 if (hidden == true) return; 3413 3414 if (state != mNetworkInfo.getDetailedState()) { 3415 mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); 3416 if (mNetworkAgent != null) { 3417 mNetworkAgent.sendNetworkInfo(mNetworkInfo); 3418 } 3419 } 3420 } 3421 3422 private DetailedState getNetworkDetailedState() { 3423 return mNetworkInfo.getDetailedState(); 3424 } 3425 3426 3427 private SupplicantState handleSupplicantStateChange(Message message) { 3428 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 3429 SupplicantState state = stateChangeResult.state; 3430 // Supplicant state change 3431 // [31-13] Reserved for future use 3432 // [8 - 0] Supplicant state (as defined in SupplicantState.java) 3433 // 50023 supplicant_state_changed (custom|1|5) 3434 mWifiInfo.setSupplicantState(state); 3435 // Network id is only valid when we start connecting 3436 if (SupplicantState.isConnecting(state)) { 3437 mWifiInfo.setNetworkId(stateChangeResult.networkId); 3438 } else { 3439 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 3440 } 3441 3442 mWifiInfo.setBSSID(stateChangeResult.BSSID); 3443 mWifiInfo.setSSID(stateChangeResult.wifiSsid); 3444 3445 mSupplicantStateTracker.sendMessage(Message.obtain(message)); 3446 3447 return state; 3448 } 3449 3450 /** 3451 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 3452 * using the interface, stopping DHCP & disabling interface 3453 */ 3454 private void handleNetworkDisconnect() { 3455 if (DBG) log("handleNetworkDisconnect: Stopping DHCP and clearing IP" 3456 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 3457 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 3458 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 3459 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 3460 3461 stopDhcp(); 3462 3463 try { 3464 mNwService.clearInterfaceAddresses(mInterfaceName); 3465 mNwService.disableIpv6(mInterfaceName); 3466 } catch (Exception e) { 3467 loge("Failed to clear addresses or disable ipv6" + e); 3468 } 3469 3470 /* Reset data structures */ 3471 mWifiInfo.reset(); 3472 linkDebouncing = false; 3473 /* Reset roaming parameters */ 3474 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 3475 fullBandConnectedTimeIntervalMilli = 20 * 1000; // Start scans at 20 seconds interval 3476 3477 setNetworkDetailedState(DetailedState.DISCONNECTED); 3478 if (mNetworkAgent != null) { 3479 mNetworkAgent.sendNetworkInfo(mNetworkInfo); 3480 mNetworkAgent = null; 3481 } 3482 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 3483 3484 /* Clear network properties */ 3485 clearLinkProperties(); 3486 3487 /* Cend event to CM & network change broadcast */ 3488 sendNetworkStateChangeBroadcast(mLastBssid); 3489 3490 /* Cancel auto roam requests */ 3491 autoRoamSetBSSID(mLastNetworkId, "any"); 3492 3493 mLastBssid= null; 3494 registerDisconnected(); 3495 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 3496 } 3497 3498 private void handleSupplicantConnectionLoss() { 3499 /* Socket connection can be lost when we do a graceful shutdown 3500 * or when the driver is hung. Ensure supplicant is stopped here. 3501 */ 3502 mWifiMonitor.killSupplicant(mP2pSupported); 3503 mWifiNative.closeSupplicantConnection(); 3504 sendSupplicantConnectionChangedBroadcast(false); 3505 setWifiState(WIFI_STATE_DISABLED); 3506 } 3507 3508 void handlePreDhcpSetup() { 3509 mDhcpActive = true; 3510 if (!mBluetoothConnectionActive) { 3511 /* 3512 * There are problems setting the Wi-Fi driver's power 3513 * mode to active when bluetooth coexistence mode is 3514 * enabled or sense. 3515 * <p> 3516 * We set Wi-Fi to active mode when 3517 * obtaining an IP address because we've found 3518 * compatibility issues with some routers with low power 3519 * mode. 3520 * <p> 3521 * In order for this active power mode to properly be set, 3522 * we disable coexistence mode until we're done with 3523 * obtaining an IP address. One exception is if we 3524 * are currently connected to a headset, since disabling 3525 * coexistence would interrupt that connection. 3526 */ 3527 // Disable the coexistence mode 3528 mWifiNative.setBluetoothCoexistenceMode( 3529 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); 3530 } 3531 3532 // Disable power save and suspend optimizations during DHCP 3533 // Note: The order here is important for now. Brcm driver changes 3534 // power settings when we control suspend mode optimizations. 3535 // TODO: Remove this comment when the driver is fixed. 3536 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false); 3537 mWifiNative.setPowerSave(false); 3538 3539 stopBatchedScan(); 3540 WifiNative.pauseScan(); 3541 3542 /* P2p discovery breaks dhcp, shut it down in order to get through this */ 3543 Message msg = new Message(); 3544 msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY; 3545 msg.arg1 = WifiP2pServiceImpl.ENABLED; 3546 msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE; 3547 msg.obj = mDhcpStateMachine; 3548 mWifiP2pChannel.sendMessage(msg); 3549 } 3550 3551 3552 void startDhcp() { 3553 if (mDhcpStateMachine == null) { 3554 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 3555 mContext, WifiStateMachine.this, mInterfaceName); 3556 3557 } 3558 mDhcpStateMachine.registerForPreDhcpNotification(); 3559 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); 3560 } 3561 3562 void renewDhcp() { 3563 if (mDhcpStateMachine == null) { 3564 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 3565 mContext, WifiStateMachine.this, mInterfaceName); 3566 3567 } 3568 mDhcpStateMachine.registerForPreDhcpNotification(); 3569 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_RENEW_DHCP); 3570 } 3571 3572 void stopDhcp() { 3573 if (mDhcpStateMachine != null) { 3574 /* In case we were in middle of DHCP operation restore back powermode */ 3575 handlePostDhcpSetup(); 3576 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); 3577 } 3578 } 3579 3580 void handlePostDhcpSetup() { 3581 /* Restore power save and suspend optimizations */ 3582 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true); 3583 mWifiNative.setPowerSave(true); 3584 3585 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED); 3586 3587 // Set the coexistence mode back to its default value 3588 mWifiNative.setBluetoothCoexistenceMode( 3589 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); 3590 3591 mDhcpActive = false; 3592 3593 startBatchedScan(); 3594 WifiNative.restartScan(); 3595 } 3596 3597 private void handleIPv4Success(DhcpResults dhcpResults, int reason) { 3598 3599 if (PDBG) { 3600 loge("wifistatemachine handleIPv4Success <" + dhcpResults.toString() 3601 + "> linkaddress num " + dhcpResults.linkProperties.getLinkAddresses().size()); 3602 for (LinkAddress linkAddress : dhcpResults.linkProperties.getLinkAddresses()) { 3603 loge("link address " + linkAddress.toString()); 3604 } 3605 } 3606 3607 synchronized (mDhcpResultsLock) { 3608 mDhcpResults = dhcpResults; 3609 } 3610 LinkProperties linkProperties = dhcpResults.linkProperties; 3611 mWifiConfigStore.setLinkProperties(mLastNetworkId, new LinkProperties(linkProperties)); 3612 InetAddress addr = null; 3613 Iterator<InetAddress> addrs = linkProperties.getAddresses().iterator(); 3614 if (addrs.hasNext()) { 3615 addr = addrs.next(); 3616 } 3617 3618 if (isRoaming()) { 3619 if (addr instanceof Inet4Address) { 3620 int previousAddress = mWifiInfo.getIpAddress(); 3621 int newAddress = NetworkUtils.inetAddressToInt((Inet4Address)addr); 3622 if (previousAddress != newAddress) { 3623 loge("handleIPv4Success, roaming and address changed" + 3624 mWifiInfo + " got: " + addr); 3625 } else { 3626 3627 } 3628 } else { 3629 loge("handleIPv4Success, roaming and didnt get an IPv4 address" + 3630 addr.toString()); 3631 3632 3633 } 3634 } 3635 mWifiInfo.setInetAddress(addr); 3636 mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint()); 3637 updateLinkProperties(reason); 3638 } 3639 3640 private void handleSuccessfulIpConfiguration() { 3641 mLastSignalLevel = -1; // Force update of signal strength 3642 WifiConfiguration c = getCurrentWifiConfiguration(); 3643 // Reset IP failure tracking 3644 if (c != null) { 3645 c.numConnectionFailures = 0; 3646 } 3647 } 3648 3649 private void handleIPv4Failure(int reason) { 3650 synchronized(mDhcpResultsLock) { 3651 if (mDhcpResults != null && mDhcpResults.linkProperties != null) { 3652 mDhcpResults.linkProperties.clear(); 3653 } 3654 } 3655 if (PDBG) { 3656 loge("wifistatemachine handleIPv4Failure"); 3657 } 3658 updateLinkProperties(reason); 3659 } 3660 3661 private void handleIpConfigurationLost() { 3662 mWifiInfo.setInetAddress(null); 3663 mWifiInfo.setMeteredHint(false); 3664 3665 mWifiConfigStore.handleSSIDStateChange(mLastNetworkId, false, "DHCP FAILURE"); 3666 3667 /* DHCP times out after about 30 seconds, we do a 3668 * disconnect thru supplicant, we will let autojoin retry connecting to the network 3669 */ 3670 mWifiNative.disconnect(); 3671 } 3672 3673 /* Current design is to not set the config on a running hostapd but instead 3674 * stop and start tethering when user changes config on a running access point 3675 * 3676 * TODO: Add control channel setup through hostapd that allows changing config 3677 * on a running daemon 3678 */ 3679 private void startSoftApWithConfig(final WifiConfiguration config) { 3680 // Start hostapd on a separate thread 3681 new Thread(new Runnable() { 3682 public void run() { 3683 try { 3684 mNwService.startAccessPoint(config, mInterfaceName); 3685 } catch (Exception e) { 3686 loge("Exception in softap start " + e); 3687 try { 3688 mNwService.stopAccessPoint(mInterfaceName); 3689 mNwService.startAccessPoint(config, mInterfaceName); 3690 } catch (Exception e1) { 3691 loge("Exception in softap re-start " + e1); 3692 sendMessage(CMD_START_AP_FAILURE); 3693 return; 3694 } 3695 } 3696 if (DBG) log("Soft AP start successful"); 3697 sendMessage(CMD_START_AP_SUCCESS); 3698 } 3699 }).start(); 3700 } 3701 3702 3703 /* 3704 * Read a MAC address in /proc/arp/table, used by WifistateMachine 3705 * so as to record MAC address of default gateway. 3706 **/ 3707 private String macAddressFromRoute(String ipAddress) { 3708 String macAddress = null; 3709 BufferedReader reader = null; 3710 try { 3711 reader = new BufferedReader(new FileReader("/proc/net/arp")); 3712 3713 // Skip over the line bearing colum titles 3714 String line = reader.readLine(); 3715 3716 while ((line = reader.readLine()) != null) { 3717 String[] tokens = line.split("[ ]+"); 3718 if (tokens.length < 6) { 3719 continue; 3720 } 3721 3722 // ARP column format is 3723 // Address HWType HWAddress Flags Mask IFace 3724 String ip = tokens[0]; 3725 String mac = tokens[3]; 3726 3727 if (ipAddress.equals(ip)) { 3728 macAddress = mac; 3729 break; 3730 } 3731 } 3732 3733 if (macAddress == null) { 3734 loge("Did not find remoteAddress {" + ipAddress + "} in " + 3735 "/proc/net/arp"); 3736 } 3737 3738 } catch (FileNotFoundException e) { 3739 loge("Could not open /proc/net/arp to lookup mac address"); 3740 } catch (IOException e) { 3741 loge("Could not read /proc/net/arp to lookup mac address"); 3742 } finally { 3743 try { 3744 if (reader != null) { 3745 reader.close(); 3746 } 3747 } catch (IOException e) { 3748 // Do nothing 3749 } 3750 } 3751 return macAddress; 3752 3753 } 3754 3755 private class WifiNetworkFactory extends NetworkFactory { 3756 public WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f) { 3757 super(l, c, TAG, f); 3758 } 3759 protected void startNetwork() { 3760 // TODO 3761 // Enter association mode. 3762 } 3763 protected void stopNetwork() { 3764 // TODO 3765 // Stop associating. 3766 } 3767 } 3768 /******************************************************** 3769 * HSM states 3770 *******************************************************/ 3771 3772 class DefaultState extends State { 3773 @Override 3774 public boolean processMessage(Message message) { 3775 logStateAndMessage(message, getClass().getSimpleName()); 3776 3777 switch (message.what) { 3778 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 3779 AsyncChannel ac = (AsyncChannel) message.obj; 3780 if (ac == mWifiP2pChannel) { 3781 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 3782 mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 3783 } else { 3784 loge("WifiP2pService connection failure, error=" + message.arg1); 3785 } 3786 } else { 3787 loge("got HALF_CONNECTED for unknown channel"); 3788 } 3789 break; 3790 } 3791 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 3792 AsyncChannel ac = (AsyncChannel) message.obj; 3793 if (ac == mWifiP2pChannel) { 3794 loge("WifiP2pService channel lost, message.arg1 =" + message.arg1); 3795 //TODO: Re-establish connection to state machine after a delay 3796 // mWifiP2pChannel.connect(mContext, getHandler(), 3797 // mWifiP2pManager.getMessenger()); 3798 } 3799 break; 3800 } 3801 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 3802 mBluetoothConnectionActive = (message.arg1 != 3803 BluetoothAdapter.STATE_DISCONNECTED); 3804 break; 3805 /* Synchronous call returns */ 3806 case CMD_PING_SUPPLICANT: 3807 case CMD_ENABLE_NETWORK: 3808 case CMD_ADD_OR_UPDATE_NETWORK: 3809 case CMD_REMOVE_NETWORK: 3810 case CMD_SAVE_CONFIG: 3811 replyToMessage(message, message.what, FAILURE); 3812 break; 3813 case CMD_GET_CAPABILITY_FREQ: 3814 replyToMessage(message, message.what, null); 3815 break; 3816 case CMD_GET_CONFIGURED_NETWORKS: 3817 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 3818 break; 3819 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS: 3820 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 3821 break; 3822 case CMD_ENABLE_RSSI_POLL: 3823 mEnableRssiPolling = (message.arg1 == 1); 3824 break; 3825 case CMD_ENABLE_BACKGROUND_SCAN: 3826 mEnableBackgroundScan = (message.arg1 == 1); 3827 break; 3828 case CMD_SET_HIGH_PERF_MODE: 3829 if (message.arg1 == 1) { 3830 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false); 3831 } else { 3832 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true); 3833 } 3834 break; 3835 case CMD_BOOT_COMPLETED: 3836 String countryCode = mPersistedCountryCode; 3837 if (TextUtils.isEmpty(countryCode) == false) { 3838 Settings.Global.putString(mContext.getContentResolver(), 3839 Settings.Global.WIFI_COUNTRY_CODE, 3840 countryCode); 3841 // It may be that the state transition that should send this info 3842 // to the driver happened between mPersistedCountryCode getting set 3843 // and now, so simply persisting it here would mean we have sent 3844 // nothing to the driver. Send the cmd so it might be set now. 3845 int sequenceNum = mCountryCodeSequence.incrementAndGet(); 3846 sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE, 3847 sequenceNum, 0, countryCode); 3848 } 3849 3850 checkAndSetConnectivityInstance(); 3851 mNetworkFactory = new WifiNetworkFactory(getHandler().getLooper(), mContext, 3852 NETWORKTYPE, mNetworkCapabilitiesFilter); 3853 mNetworkFactory.setScoreFilter(60); 3854 mCm.registerNetworkFactory(new Messenger(mNetworkFactory), NETWORKTYPE); 3855 break; 3856 case CMD_SET_BATCHED_SCAN: 3857 recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj); 3858 break; 3859 case CMD_POLL_BATCHED_SCAN: 3860 handleBatchedScanPollRequest(); 3861 break; 3862 case CMD_START_NEXT_BATCHED_SCAN: 3863 startNextBatchedScan(); 3864 break; 3865 /* Discard */ 3866 case CMD_START_SCAN: 3867 case CMD_START_SUPPLICANT: 3868 case CMD_STOP_SUPPLICANT: 3869 case CMD_STOP_SUPPLICANT_FAILED: 3870 case CMD_START_DRIVER: 3871 case CMD_STOP_DRIVER: 3872 case CMD_DELAYED_STOP_DRIVER: 3873 case CMD_DRIVER_START_TIMED_OUT: 3874 case CMD_START_AP: 3875 case CMD_START_AP_SUCCESS: 3876 case CMD_START_AP_FAILURE: 3877 case CMD_STOP_AP: 3878 case CMD_TETHER_STATE_CHANGE: 3879 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 3880 case CMD_DISCONNECT: 3881 case CMD_RECONNECT: 3882 case CMD_REASSOCIATE: 3883 case CMD_RELOAD_TLS_AND_RECONNECT: 3884 case WifiMonitor.SUP_CONNECTION_EVENT: 3885 case WifiMonitor.SUP_DISCONNECTION_EVENT: 3886 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3887 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 3888 case WifiMonitor.SCAN_RESULTS_EVENT: 3889 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3890 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 3891 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 3892 case WifiMonitor.WPS_OVERLAP_EVENT: 3893 case CMD_BLACKLIST_NETWORK: 3894 case CMD_CLEAR_BLACKLIST: 3895 case CMD_SET_OPERATIONAL_MODE: 3896 case CMD_SET_COUNTRY_CODE: 3897 case CMD_SET_FREQUENCY_BAND: 3898 case CMD_RSSI_POLL: 3899 case CMD_ENABLE_ALL_NETWORKS: 3900 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 3901 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 3902 /* Handled by WifiApConfigStore */ 3903 case CMD_SET_AP_CONFIG: 3904 case CMD_SET_AP_CONFIG_COMPLETED: 3905 case CMD_REQUEST_AP_CONFIG: 3906 case CMD_RESPONSE_AP_CONFIG: 3907 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 3908 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 3909 case CMD_NO_NETWORKS_PERIODIC_SCAN: 3910 case CMD_DISABLE_P2P_RSP: 3911 case WifiMonitor.SUP_REQUEST_IDENTITY: 3912 case CMD_TEST_NETWORK_DISCONNECT: 3913 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: 3914 case WifiMonitor.SUP_REQUEST_SIM_AUTH: 3915 break; 3916 case DhcpStateMachine.CMD_ON_QUIT: 3917 mDhcpStateMachine = null; 3918 break; 3919 case CMD_SET_SUSPEND_OPT_ENABLED: 3920 if (message.arg1 == 1) { 3921 mSuspendWakeLock.release(); 3922 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true); 3923 } else { 3924 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false); 3925 } 3926 break; 3927 case WifiMonitor.DRIVER_HUNG_EVENT: 3928 setSupplicantRunning(false); 3929 setSupplicantRunning(true); 3930 break; 3931 case WifiManager.CONNECT_NETWORK: 3932 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 3933 WifiManager.BUSY); 3934 break; 3935 case WifiManager.FORGET_NETWORK: 3936 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 3937 WifiManager.BUSY); 3938 break; 3939 case WifiManager.SAVE_NETWORK: 3940 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 3941 WifiManager.BUSY); 3942 break; 3943 case WifiManager.START_WPS: 3944 replyToMessage(message, WifiManager.WPS_FAILED, 3945 WifiManager.BUSY); 3946 break; 3947 case WifiManager.CANCEL_WPS: 3948 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, 3949 WifiManager.BUSY); 3950 break; 3951 case WifiManager.DISABLE_NETWORK: 3952 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 3953 WifiManager.BUSY); 3954 break; 3955 case WifiManager.RSSI_PKTCNT_FETCH: 3956 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED, 3957 WifiManager.BUSY); 3958 break; 3959 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 3960 NetworkInfo info = (NetworkInfo) message.obj; 3961 mP2pConnected.set(info.isConnected()); 3962 break; 3963 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 3964 mTemporarilyDisconnectWifi = (message.arg1 == 1); 3965 replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 3966 break; 3967 /* Link configuration (IP address, DNS, ...) changes notified via netlink */ 3968 case CMD_UPDATE_LINKPROPERTIES: 3969 updateLinkProperties(CMD_UPDATE_LINKPROPERTIES); 3970 break; 3971 case CMD_IP_CONFIGURATION_SUCCESSFUL: 3972 case CMD_IP_CONFIGURATION_LOST: 3973 break; 3974 case CMD_GET_CONNECTION_STATISTICS: 3975 replyToMessage(message, message.what, mWifiConnectionStatistics); 3976 break; 3977 default: 3978 loge("Error! unhandled message" + message); 3979 break; 3980 } 3981 return HANDLED; 3982 } 3983 } 3984 3985 class InitialState extends State { 3986 @Override 3987 public void enter() { 3988 mWifiNative.unloadDriver(); 3989 3990 if (mWifiP2pChannel == null) { 3991 mWifiP2pChannel = new AsyncChannel(); 3992 mWifiP2pChannel.connect(mContext, getHandler(), 3993 mWifiP2pServiceImpl.getP2pStateMachineMessenger()); 3994 } 3995 3996 if (mWifiApConfigChannel == null) { 3997 mWifiApConfigChannel = new AsyncChannel(); 3998 WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore( 3999 mContext, getHandler()); 4000 wifiApConfigStore.loadApConfiguration(); 4001 mWifiApConfigChannel.connectSync(mContext, getHandler(), 4002 wifiApConfigStore.getMessenger()); 4003 } 4004 } 4005 @Override 4006 public boolean processMessage(Message message) { 4007 logStateAndMessage(message, getClass().getSimpleName()); 4008 switch (message.what) { 4009 case CMD_START_SUPPLICANT: 4010 if (mWifiNative.loadDriver()) { 4011 try { 4012 mNwService.wifiFirmwareReload(mInterfaceName, "STA"); 4013 } catch (Exception e) { 4014 loge("Failed to reload STA firmware " + e); 4015 // Continue 4016 } 4017 4018 try { 4019 // A runtime crash can leave the interface up and 4020 // IP addresses configured, and this affects 4021 // connectivity when supplicant starts up. 4022 // Ensure interface is down and we have no IP 4023 // addresses before a supplicant start. 4024 mNwService.setInterfaceDown(mInterfaceName); 4025 mNwService.clearInterfaceAddresses(mInterfaceName); 4026 4027 // Set privacy extensions 4028 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); 4029 4030 // IPv6 is enabled only as long as access point is connected since: 4031 // - IPv6 addresses and routes stick around after disconnection 4032 // - kernel is unaware when connected and fails to start IPv6 negotiation 4033 // - kernel can start autoconfiguration when 802.1x is not complete 4034 mNwService.disableIpv6(mInterfaceName); 4035 } catch (RemoteException re) { 4036 loge("Unable to change interface settings: " + re); 4037 } catch (IllegalStateException ie) { 4038 loge("Unable to change interface settings: " + ie); 4039 } 4040 4041 /* Stop a running supplicant after a runtime restart 4042 * Avoids issues with drivers that do not handle interface down 4043 * on a running supplicant properly. 4044 */ 4045 mWifiMonitor.killSupplicant(mP2pSupported); 4046 if(mWifiNative.startSupplicant(mP2pSupported)) { 4047 setWifiState(WIFI_STATE_ENABLING); 4048 if (DBG) log("Supplicant start successful"); 4049 mWifiMonitor.startMonitoring(); 4050 transitionTo(mSupplicantStartingState); 4051 } else { 4052 loge("Failed to start supplicant!"); 4053 } 4054 } else { 4055 loge("Failed to load driver"); 4056 } 4057 break; 4058 case CMD_START_AP: 4059 if (mWifiNative.loadDriver()) { 4060 setWifiApState(WIFI_AP_STATE_ENABLING); 4061 transitionTo(mSoftApStartingState); 4062 } else { 4063 loge("Failed to load driver for softap"); 4064 } 4065 default: 4066 return NOT_HANDLED; 4067 } 4068 return HANDLED; 4069 } 4070 } 4071 4072 class SupplicantStartingState extends State { 4073 private void initializeWpsDetails() { 4074 String detail; 4075 detail = SystemProperties.get("ro.product.name", ""); 4076 if (!mWifiNative.setDeviceName(detail)) { 4077 loge("Failed to set device name " + detail); 4078 } 4079 detail = SystemProperties.get("ro.product.manufacturer", ""); 4080 if (!mWifiNative.setManufacturer(detail)) { 4081 loge("Failed to set manufacturer " + detail); 4082 } 4083 detail = SystemProperties.get("ro.product.model", ""); 4084 if (!mWifiNative.setModelName(detail)) { 4085 loge("Failed to set model name " + detail); 4086 } 4087 detail = SystemProperties.get("ro.product.model", ""); 4088 if (!mWifiNative.setModelNumber(detail)) { 4089 loge("Failed to set model number " + detail); 4090 } 4091 detail = SystemProperties.get("ro.serialno", ""); 4092 if (!mWifiNative.setSerialNumber(detail)) { 4093 loge("Failed to set serial number " + detail); 4094 } 4095 if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) { 4096 loge("Failed to set WPS config methods"); 4097 } 4098 if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) { 4099 loge("Failed to set primary device type " + mPrimaryDeviceType); 4100 } 4101 } 4102 4103 @Override 4104 public boolean processMessage(Message message) { 4105 logStateAndMessage(message, getClass().getSimpleName()); 4106 4107 switch(message.what) { 4108 case WifiMonitor.SUP_CONNECTION_EVENT: 4109 if (DBG) log("Supplicant connection established"); 4110 setWifiState(WIFI_STATE_ENABLED); 4111 mSupplicantRestartCount = 0; 4112 /* Reset the supplicant state to indicate the supplicant 4113 * state is not known at this time */ 4114 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 4115 /* Initialize data structures */ 4116 mLastBssid = null; 4117 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 4118 mLastSignalLevel = -1; 4119 4120 mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); 4121 mWifiNative.enableSaveConfig(); 4122 mWifiConfigStore.loadAndEnableAllNetworks(); 4123 initializeWpsDetails(); 4124 4125 sendSupplicantConnectionChangedBroadcast(true); 4126 transitionTo(mDriverStartedState); 4127 break; 4128 case WifiMonitor.SUP_DISCONNECTION_EVENT: 4129 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { 4130 loge("Failed to setup control channel, restart supplicant"); 4131 mWifiMonitor.killSupplicant(mP2pSupported); 4132 transitionTo(mInitialState); 4133 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 4134 } else { 4135 loge("Failed " + mSupplicantRestartCount + 4136 " times to start supplicant, unload driver"); 4137 mSupplicantRestartCount = 0; 4138 setWifiState(WIFI_STATE_UNKNOWN); 4139 transitionTo(mInitialState); 4140 } 4141 break; 4142 case CMD_START_SUPPLICANT: 4143 case CMD_STOP_SUPPLICANT: 4144 case CMD_START_AP: 4145 case CMD_STOP_AP: 4146 case CMD_START_DRIVER: 4147 case CMD_STOP_DRIVER: 4148 case CMD_SET_OPERATIONAL_MODE: 4149 case CMD_SET_COUNTRY_CODE: 4150 case CMD_SET_FREQUENCY_BAND: 4151 case CMD_START_PACKET_FILTERING: 4152 case CMD_STOP_PACKET_FILTERING: 4153 deferMessage(message); 4154 break; 4155 default: 4156 return NOT_HANDLED; 4157 } 4158 return HANDLED; 4159 } 4160 } 4161 4162 class SupplicantStartedState extends State { 4163 @Override 4164 public void enter() { 4165 /* Wifi is available as long as we have a connection to supplicant */ 4166 mNetworkInfo.setIsAvailable(true); 4167 if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo); 4168 4169 int defaultInterval = mContext.getResources().getInteger( 4170 R.integer.config_wifi_supplicant_scan_interval); 4171 4172 mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 4173 Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, 4174 defaultInterval); 4175 4176 mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000); 4177 mWifiNative.setExternalSim(true); 4178 4179 if (mFrameworkAutoJoin.get()) { 4180 mWifiNative.enableAutoConnect(false); 4181 } 4182 4183 } 4184 @Override 4185 public boolean processMessage(Message message) { 4186 logStateAndMessage(message, getClass().getSimpleName()); 4187 4188 switch(message.what) { 4189 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ 4190 if (mP2pSupported) { 4191 transitionTo(mWaitForP2pDisableState); 4192 } else { 4193 transitionTo(mSupplicantStoppingState); 4194 } 4195 break; 4196 case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ 4197 loge("Connection lost, restart supplicant"); 4198 handleSupplicantConnectionLoss(); 4199 handleNetworkDisconnect(); 4200 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 4201 if (mP2pSupported) { 4202 transitionTo(mWaitForP2pDisableState); 4203 } else { 4204 transitionTo(mInitialState); 4205 } 4206 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 4207 break; 4208 case WifiMonitor.SCAN_RESULTS_EVENT: 4209 setScanResults(); 4210 sendScanResultsAvailableBroadcast(); 4211 mIsScanOngoing = false; 4212 mIsFullScanOngoing = false; 4213 if (mBufferedScanMsg.size() > 0) 4214 sendMessage(mBufferedScanMsg.remove()); 4215 break; 4216 case CMD_PING_SUPPLICANT: 4217 boolean ok = mWifiNative.ping(); 4218 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 4219 break; 4220 case CMD_GET_CAPABILITY_FREQ: 4221 String freqs = mWifiNative.getFreqCapability(); 4222 replyToMessage(message, message.what, freqs); 4223 break; 4224 case CMD_START_AP: 4225 /* Cannot start soft AP while in client mode */ 4226 loge("Failed to start soft AP with a running supplicant"); 4227 setWifiApState(WIFI_AP_STATE_FAILED); 4228 break; 4229 case CMD_SET_OPERATIONAL_MODE: 4230 mOperationalMode = message.arg1; 4231 break; 4232 case CMD_GET_ADAPTORS: 4233 if (WifiNative.startHal()) { 4234 List<WifiAdapter> adaptors = new ArrayList<WifiAdapter>(); 4235 int featureSet = WifiNative.getSupportedFeatureSet(); 4236 /* TODO: Get capabilities from adaptors themselves */ 4237 for (int i = 0; i < WifiNative.getInterfaces(); i++) { 4238 String name = WifiNative.getInterfaceName(i); 4239 WifiAdapter adaptor; 4240 if (name.startsWith("wlan")) { 4241 adaptor = new WifiAdapter( 4242 name, featureSet & ~WifiAdapter.WIFI_FEATURE_P2P); 4243 } else if (name.startsWith("p2p")) { 4244 adaptor = new WifiAdapter( 4245 name, featureSet & WifiAdapter.WIFI_FEATURE_P2P); 4246 } else { 4247 logd("Ignoring adaptor with name" + name); 4248 continue; 4249 } 4250 adaptors.add(adaptor); 4251 } 4252 replyToMessage(message, message.what, adaptors); 4253 } else { 4254 List<WifiAdapter> adaptors = new ArrayList<WifiAdapter>(); 4255 replyToMessage(message, message.what, adaptors); 4256 } 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 handleSimAuthRequest(requestData); 5343 } else { 5344 loge("Invalid sim auth request"); 5345 } 5346 break; 5347 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS: 5348 replyToMessage(message, message.what, 5349 mWifiConfigStore.getPrivilegedConfiguredNetworks()); 5350 break; 5351 /* Do a redundant disconnect without transition */ 5352 case CMD_DISCONNECT: 5353 mWifiConfigStore.setLastSelectedConfiguration 5354 (WifiConfiguration.INVALID_NETWORK_ID); 5355 mWifiNative.disconnect(); 5356 break; 5357 case CMD_RECONNECT: 5358 lastConnectAttempt = System.currentTimeMillis(); 5359 mWifiNative.reconnect(); 5360 break; 5361 case CMD_REASSOCIATE: 5362 lastConnectAttempt = System.currentTimeMillis(); 5363 mWifiNative.reassociate(); 5364 break; 5365 case CMD_RELOAD_TLS_AND_RECONNECT: 5366 if (mWifiConfigStore.needsUnlockedKeyStore()) { 5367 logd("Reconnecting to give a chance to un-connected TLS networks"); 5368 mWifiNative.disconnect(); 5369 lastConnectAttempt = System.currentTimeMillis(); 5370 mWifiNative.reconnect(); 5371 } 5372 break; 5373 case CMD_AUTO_ROAM: 5374 return HANDLED; 5375 case CMD_AUTO_CONNECT: 5376 /* Work Around: wpa_supplicant can get in a bad state where it returns a non 5377 * associated status to the STATUS command but somehow-someplace still thinks 5378 * it is associated and thus will ignore select/reconnect command with 5379 * following message: 5380 * "Already associated with the selected network - do nothing" 5381 * 5382 * Hence, sends a disconnect to supplicant first. 5383 */ 5384 mWifiNative.disconnect(); 5385 5386 /* connect command coming from auto-join */ 5387 config = (WifiConfiguration) message.obj; 5388 netId = message.arg1; 5389 int roam = message.arg2; 5390 loge("CMD_AUTO_CONNECT sup state " 5391 + mSupplicantStateTracker.getSupplicantStateName() 5392 + " my state " + getCurrentState().getName() 5393 + " nid=" + Integer.toString(netId) 5394 + " roam=" + Integer.toString(roam)); 5395 if (config == null) { 5396 loge("AUTO_CONNECT and no config, bail out..."); 5397 break; 5398 } 5399 5400 /* Make sure we cancel any previous roam request */ 5401 autoRoamSetBSSID(config, "any"); 5402 5403 /* Save the network config */ 5404 loge("CMD_AUTO_CONNECT will save config -> " + config.SSID 5405 + " nid=" + Integer.toString(netId)); 5406 result = mWifiConfigStore.saveNetwork(config); 5407 netId = result.getNetworkId(); 5408 loge("CMD_AUTO_CONNECT did save config -> " 5409 + " nid=" + Integer.toString(netId)); 5410 5411 if (mWifiConfigStore.selectNetwork(netId) && 5412 mWifiNative.reconnect()) { 5413 lastConnectAttempt = System.currentTimeMillis(); 5414 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 5415 // We selected a better config, 5416 // maybe because we could not see the last user 5417 // selection, then forget it. We will remember the selection 5418 // only if it was persisted. 5419 mWifiConfigStore. 5420 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 5421 5422 mAutoRoaming = roam; 5423 if (isRoaming() || linkDebouncing) { 5424 transitionTo(mRoamingState); 5425 } else { 5426 transitionTo(mDisconnectingState); 5427 } 5428 } else { 5429 loge("Failed to connect config: " + config + " netId: " + netId); 5430 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 5431 WifiManager.ERROR); 5432 break; 5433 } 5434 break; 5435 case WifiManager.CONNECT_NETWORK: 5436 /** 5437 * The connect message can contain a network id passed as arg1 on message or 5438 * or a config passed as obj on message. 5439 * For a new network, a config is passed to create and connect. 5440 * For an existing network, a network id is passed 5441 */ 5442 netId = message.arg1; 5443 config = (WifiConfiguration) message.obj; 5444 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 5445 5446 if (config == null) { 5447 loge("CONNECT_NETWORK id=" + Integer.toString(netId) + " " 5448 + mSupplicantStateTracker.getSupplicantStateName() + " my state " 5449 + getCurrentState().getName()); 5450 } else { 5451 loge("CONNECT_NETWORK id=" + Integer.toString(netId) 5452 + " config=" + config.SSID 5453 + " cnid=" + config.networkId 5454 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 5455 + " my state " + getCurrentState().getName()); 5456 } 5457 5458 autoRoamSetBSSID(netId, "any"); 5459 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 5460 5461 /* Save the network config */ 5462 if (config != null) { 5463 result = mWifiConfigStore.saveNetwork(config); 5464 netId = result.getNetworkId(); 5465 } 5466 if (mFrameworkAutoJoin.get()) { 5467 /* Tell autojoin the user did try to connect to that network */ 5468 mWifiAutoJoinController.updateConfigurationHistory(netId, true, true); 5469 } 5470 mWifiConfigStore.setLastSelectedConfiguration(netId); 5471 5472 if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID 5473 && mLastNetworkId != netId) { 5474 /** Supplicant will ignore the reconnect if we are currently associated, 5475 * hence trigger a disconnect 5476 */ 5477 mWifiNative.disconnect(); 5478 } 5479 5480 if (mWifiConfigStore.selectNetwork(netId) && 5481 mWifiNative.reconnect()) { 5482 lastConnectAttempt = System.currentTimeMillis(); 5483 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 5484 5485 /* The state tracker handles enabling networks upon completion/failure */ 5486 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 5487 replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 5488 /* Expect a disconnection from the old connection */ 5489 transitionTo(mDisconnectingState); 5490 } else { 5491 loge("Failed to connect config: " + config + " netId: " + netId); 5492 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 5493 WifiManager.ERROR); 5494 break; 5495 } 5496 break; 5497 case WifiManager.SAVE_NETWORK: 5498 config = (WifiConfiguration) message.obj; 5499 int nid = config.networkId; 5500 if (config == null) { 5501 loge("SAVE_NETWORK id=" + Integer.toString(nid) 5502 + " " + mSupplicantStateTracker.getSupplicantStateName() 5503 + " my state " + getCurrentState().getName()); 5504 } else { 5505 loge("SAVE_NETWORK id=" + Integer.toString(nid) 5506 + " config=" + config.SSID 5507 + " cnid=" + config.networkId 5508 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 5509 + " my state " + getCurrentState().getName()); 5510 } 5511 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 5512 5513 result = mWifiConfigStore.saveNetwork(config); 5514 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 5515 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 5516 if (VDBG) { 5517 loge("Success save network nid=" 5518 + Integer.toString(result.getNetworkId()) 5519 + " autojoin " + mFrameworkAutoJoin.get()); 5520 } 5521 if (mFrameworkAutoJoin.get()) { 5522 /* Tell autojoin the user did try to modify and save that network, 5523 * and interpret the SAVE_NETWORK as a request to connect */ 5524 mWifiAutoJoinController.updateConfigurationHistory(result.getNetworkId() 5525 ,true, true); 5526 mWifiAutoJoinController.attemptAutoJoin(); 5527 } 5528 } else { 5529 loge("Failed to save network"); 5530 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 5531 WifiManager.ERROR); 5532 } 5533 break; 5534 case WifiManager.FORGET_NETWORK: 5535 if (mWifiConfigStore.forgetNetwork(message.arg1)) { 5536 replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); 5537 } else { 5538 loge("Failed to forget network"); 5539 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 5540 WifiManager.ERROR); 5541 } 5542 break; 5543 case WifiManager.START_WPS: 5544 WpsInfo wpsInfo = (WpsInfo) message.obj; 5545 WpsResult wpsResult; 5546 switch (wpsInfo.setup) { 5547 case WpsInfo.PBC: 5548 wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo); 5549 break; 5550 case WpsInfo.KEYPAD: 5551 wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); 5552 break; 5553 case WpsInfo.DISPLAY: 5554 wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); 5555 break; 5556 default: 5557 wpsResult = new WpsResult(Status.FAILURE); 5558 loge("Invalid setup for WPS"); 5559 break; 5560 } 5561 mWifiConfigStore.setLastSelectedConfiguration 5562 (WifiConfiguration.INVALID_NETWORK_ID); 5563 if (wpsResult.status == Status.SUCCESS) { 5564 replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult); 5565 transitionTo(mWpsRunningState); 5566 } else { 5567 loge("Failed to start WPS with config " + wpsInfo.toString()); 5568 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR); 5569 } 5570 break; 5571 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5572 if (DBG) log("Network connection established"); 5573 mLastNetworkId = message.arg1; 5574 mLastBssid = (String) message.obj; 5575 5576 mWifiInfo.setBSSID(mLastBssid); 5577 mWifiInfo.setNetworkId(mLastNetworkId); 5578 // Send event to CM & network change broadcast 5579 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 5580 sendNetworkStateChangeBroadcast(mLastBssid); 5581 transitionTo(mObtainingIpState); 5582 break; 5583 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 5584 if (DBG) log("ConnectModeState: Network connection lost "); 5585 handleNetworkDisconnect(); 5586 transitionTo(mDisconnectedState); 5587 break; 5588 default: 5589 return NOT_HANDLED; 5590 } 5591 return HANDLED; 5592 } 5593 } 5594 5595 private class WifiNetworkAgent extends NetworkAgent { 5596 public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni, 5597 NetworkCapabilities nc, LinkProperties lp, int score) { 5598 super(l, c, TAG, ni, nc, lp, score); 5599 } 5600 protected void unwanted() { 5601 // Ignore if we're not the current networkAgent. 5602 if (this != mNetworkAgent) return; 5603 // TODO - don't want this network. What to do? 5604 if (DBG) log("WifiNetworkAgent -> Wifi unwanted score " 5605 + Integer.toString(mWifiInfo.score)); 5606 unwantedNetwork(); 5607 } 5608 } 5609 5610 void unwantedNetwork() { 5611 sendMessage(CMD_UNWANTED_NETWORK); 5612 } 5613 5614 boolean startScanForConfiguration(WifiConfiguration config, boolean restrictChannelList) { 5615 HashSet<Integer> channels 5616 = mWifiConfigStore.makeChannelList(config, 5617 ONE_HOUR_MILLI, restrictChannelList); 5618 if (channels != null && channels.size() != 0) { 5619 StringBuilder freqs = new StringBuilder(); 5620 boolean first = true; 5621 for (Integer channel : channels) { 5622 if (!first) 5623 freqs.append(","); 5624 freqs.append(channel.toString()); 5625 first = false; 5626 } 5627 if (DBG) { 5628 loge("WifiStateMachine starting scan with " + freqs); 5629 } 5630 // Call wifi native to start the scan 5631 if (startScanNative( 5632 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, 5633 freqs.toString())) { 5634 // Only count battery consumption if scan request is accepted 5635 noteScanStart(SCAN_ALARM_SOURCE, null); 5636 } 5637 return true; 5638 } else { 5639 return false; 5640 } 5641 } 5642 5643 private static final String TCP_BUFFER_SIZES_WIFI = 5644 "524288,1048576,2097152,262144,524288,1048576"; 5645 5646 class L2ConnectedState extends State { 5647 @Override 5648 public void enter() { 5649 mRssiPollToken++; 5650 if (mEnableRssiPolling) { 5651 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0); 5652 } 5653 if (mNetworkAgent != null) { 5654 loge("Have NetworkAgent when entering L2Connected"); 5655 setNetworkDetailedState(DetailedState.DISCONNECTED); 5656 } 5657 setNetworkDetailedState(DetailedState.CONNECTING); 5658 mLinkProperties.setTcpBufferSizes(TCP_BUFFER_SIZES_WIFI); 5659 5660 mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext, 5661 "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter, 5662 mLinkProperties, 60); 5663 } 5664 5665 @Override 5666 public void exit() { 5667 // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState 5668 // Bug: 15347363 5669 // For paranoia's sake, call handleNetworkDisconnect only if BSSID is null or last networkId 5670 // is not invalid. 5671 if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 5672 handleNetworkDisconnect(); 5673 } 5674 } 5675 5676 @Override 5677 public boolean processMessage(Message message) { 5678 logStateAndMessage(message, getClass().getSimpleName()); 5679 5680 switch (message.what) { 5681 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 5682 handlePreDhcpSetup(); 5683 break; 5684 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 5685 handlePostDhcpSetup(); 5686 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 5687 if (DBG) log("WifiStateMachine DHCP successful"); 5688 handleIPv4Success((DhcpResults) message.obj, DhcpStateMachine.DHCP_SUCCESS); 5689 // We advance to mVerifyingLinkState because handleIPv4Success will call 5690 // updateLinkProperties, which then sends CMD_IP_CONFIGURATION_SUCCESSFUL. 5691 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { 5692 if (DBG) { 5693 int count = -1; 5694 WifiConfiguration config = getCurrentWifiConfiguration(); 5695 if (config != null) { 5696 count = config.numConnectionFailures; 5697 } 5698 log("WifiStateMachine DHCP failure count=" + count); 5699 } 5700 handleIPv4Failure(DhcpStateMachine.DHCP_FAILURE); 5701 // As above, we transition to mDisconnectingState via updateLinkProperties. 5702 } 5703 break; 5704 case CMD_IP_CONFIGURATION_SUCCESSFUL: 5705 handleSuccessfulIpConfiguration(); 5706 sendConnectedState(); 5707 transitionTo(mConnectedState); 5708 break; 5709 case CMD_IP_CONFIGURATION_LOST: 5710 handleIpConfigurationLost(); 5711 transitionTo(mDisconnectingState); 5712 break; 5713 case CMD_DISCONNECT: 5714 mWifiNative.disconnect(); 5715 transitionTo(mDisconnectingState); 5716 break; 5717 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 5718 if (message.arg1 == 1) { 5719 mWifiNative.disconnect(); 5720 mTemporarilyDisconnectWifi = true; 5721 transitionTo(mDisconnectingState); 5722 } 5723 break; 5724 case CMD_SET_OPERATIONAL_MODE: 5725 if (message.arg1 != CONNECT_MODE) { 5726 sendMessage(CMD_DISCONNECT); 5727 deferMessage(message); 5728 } 5729 break; 5730 case CMD_SET_COUNTRY_CODE: 5731 deferMessage(message); 5732 break; 5733 case CMD_START_SCAN: 5734 if (DBG) { 5735 loge("WifiStateMachine CMD_START_SCAN source " + message.arg1 5736 + " txSuccessRate="+String.format( "%.2f", mWifiInfo.txSuccessRate) 5737 + " rxSuccessRate="+String.format( "%.2f", mWifiInfo.rxSuccessRate) 5738 + " BSSID=" + mTargetRoamBSSID 5739 + " RSSI=" + mWifiInfo.getRssi()); 5740 } 5741 if (message.arg1 == SCAN_ALARM_SOURCE) { 5742 boolean tryFullBandScan = false; 5743 boolean restrictChannelList = false; 5744 long now_ms = System.currentTimeMillis(); 5745 if (mWifiInfo != null) { 5746 if ((now_ms - lastFullBandConnectedTimeMilli) 5747 > fullBandConnectedTimeIntervalMilli) { 5748 if (DBG) { 5749 loge("WifiStateMachine CMD_START_SCAN try full band scan age=" 5750 + Long.toString(now_ms - lastFullBandConnectedTimeMilli) 5751 + " interval=" + fullBandConnectedTimeIntervalMilli); 5752 } 5753 tryFullBandScan = true; 5754 } 5755 5756 if (mWifiInfo.txSuccessRate > 5 || mWifiInfo.rxSuccessRate > 30) { 5757 // Too much traffic at the interface, hence no full band scan 5758 if (DBG) { 5759 loge("WifiStateMachine CMD_START_SCAN " + 5760 "prevent full band scan due to pkt rate"); 5761 } 5762 tryFullBandScan = false; 5763 } 5764 5765 if (mWifiInfo.txSuccessRate > 50 || mWifiInfo.rxSuccessRate > 100) { 5766 // Don't scan if lots of packets are being sent 5767 restrictChannelList = true; 5768 if (mAllowScansWithTraffic == 0) { 5769 if (DBG) { 5770 loge("WifiStateMachine CMD_START_SCAN source " + message.arg1 5771 + " ...and ignore scans" 5772 + " tx=" + String.format("%.2f", mWifiInfo.txSuccessRate) 5773 + " rx=" + String.format("%.2f", mWifiInfo.rxSuccessRate)); 5774 } 5775 return HANDLED; 5776 } 5777 } 5778 } 5779 5780 WifiConfiguration currentConfiguration = getCurrentWifiConfiguration(); 5781 if (currentConfiguration != null) { 5782 if (tryFullBandScan) { 5783 lastFullBandConnectedTimeMilli = now_ms; 5784 if (fullBandConnectedTimeIntervalMilli < 20 * 1000) { 5785 // Paranoia, make sure interval is not less than 20 seconds 5786 fullBandConnectedTimeIntervalMilli = 20 * 1000; 5787 } 5788 if (fullBandConnectedTimeIntervalMilli 5789 < maxFullBandConnectedTimeIntervalMilli) { 5790 // Increase the interval 5791 fullBandConnectedTimeIntervalMilli 5792 = fullBandConnectedTimeIntervalMilli * 3 / 2; 5793 } 5794 handleScanRequest( 5795 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 5796 } else { 5797 if (!startScanForConfiguration(currentConfiguration, restrictChannelList)) { 5798 if (DBG) { 5799 loge("WifiStateMachine starting scan, did not find channels"); 5800 handleScanRequest( 5801 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 5802 } 5803 } 5804 } 5805 } 5806 } else { 5807 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 5808 } 5809 break; 5810 /* Ignore connection to same network */ 5811 case WifiManager.CONNECT_NETWORK: 5812 int netId = message.arg1; 5813 if (mWifiInfo.getNetworkId() == netId) { 5814 break; 5815 } 5816 return NOT_HANDLED; 5817 case WifiManager.SAVE_NETWORK: 5818 WifiConfiguration config = (WifiConfiguration) message.obj; 5819 int nid = config.networkId; 5820 if (config == null) { 5821 loge("SAVE_NETWORK-L2 id=" + Integer.toString(nid) 5822 + " " + mSupplicantStateTracker.getSupplicantStateName() 5823 + " my state " + getCurrentState().getName()); 5824 } else { 5825 loge("SAVE_NETWORK-L2 id=" + Integer.toString(nid) 5826 + " SSID=" + config.SSID 5827 + " cnid=" + config.networkId 5828 + " autojoin=" + Integer.toString(config.autoJoinStatus) 5829 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 5830 + " my state " + getCurrentState().getName() 5831 + " uid " + Integer.toString(config.creatorUid)); 5832 } 5833 5834 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 5835 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 5836 if (result.hasIpChanged()) { 5837 // We switched from DHCP to static or from static to DHCP, or the 5838 // static IP address has changed. 5839 log("Reconfiguring IP on connection"); 5840 // TODO: clear addresses and disable IPv6 to simplify obtainingIpState. 5841 transitionTo(mObtainingIpState); 5842 } 5843 if (result.hasProxyChanged()) { 5844 log("Reconfiguring proxy on connection"); 5845 updateLinkProperties(CMD_UPDATE_LINKPROPERTIES); 5846 } 5847 } 5848 5849 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 5850 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 5851 if (VDBG) { 5852 loge("Success save network l2 nid=" 5853 + Integer.toString(result.getNetworkId()) 5854 + " autojoin " + mFrameworkAutoJoin.get()); 5855 } 5856 if (mFrameworkAutoJoin.get()) { 5857 /* Tell autojoin the user did try to modify and save that network. 5858 * and interpret the SAVE network command as a manual request to connect */ 5859 mWifiAutoJoinController.updateConfigurationHistory(config.networkId, 5860 true, true); 5861 mWifiAutoJoinController.attemptAutoJoin(); 5862 } 5863 } else { 5864 loge("Failed to save network"); 5865 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 5866 WifiManager.ERROR); 5867 } 5868 break; 5869 /* Ignore */ 5870 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5871 break; 5872 case CMD_RSSI_POLL: 5873 if (message.arg1 == mRssiPollToken) { 5874 WifiLinkLayerStats stats = null; 5875 // Try a reading L2 stats a couple of time, allow for a few failures 5876 // in case the HAL/drivers are not completely initialized once we get there 5877 if (mWifiLinkLayerStatsSupported > 0) { 5878 stats = mWifiNative.getWifiLinkLayerStats(); 5879 if (stats == null && mWifiLinkLayerStatsSupported > 0) { 5880 mWifiLinkLayerStatsSupported -= 1; 5881 } 5882 } 5883 // Get Info and continue polling 5884 fetchRssiLinkSpeedAndFrequencyNative(); 5885 calculateWifiScore(stats); 5886 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 5887 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 5888 } else { 5889 // Polling has completed 5890 } 5891 break; 5892 case CMD_ENABLE_RSSI_POLL: 5893 mEnableRssiPolling = (message.arg1 == 1); 5894 mRssiPollToken++; 5895 if (mEnableRssiPolling) { 5896 // First poll 5897 fetchRssiLinkSpeedAndFrequencyNative(); 5898 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 5899 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 5900 } 5901 break; 5902 case WifiManager.RSSI_PKTCNT_FETCH: 5903 RssiPacketCountInfo info = new RssiPacketCountInfo(); 5904 fetchRssiLinkSpeedAndFrequencyNative(); 5905 info.rssi = mWifiInfo.getRssi(); 5906 fetchPktcntNative(info); 5907 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info); 5908 break; 5909 case CMD_UNWANTED_NETWORK: 5910 // mWifiConfigStore.handleBadNetworkDisconnectReport(mLastNetworkId, mWifiInfo); 5911 // disconnecting is probably too rough and reduce the chance we recover quickly. 5912 // we should not have to disconnect, instead rely on network stack to send data 5913 // traffic somewhere else but remember that this network is roamable with a 5914 // low wifi score threshold 5915 sendMessage(CMD_DISCONNECT); 5916 break; 5917 case CMD_DELAYED_NETWORK_DISCONNECT: 5918 if (!linkDebouncing) { 5919 // Ignore if we are not debouncing 5920 loge("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore " + message.arg1); 5921 return HANDLED; 5922 } else { 5923 loge("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect " + message.arg1); 5924 5925 linkDebouncing = false; 5926 // If we are still debouncing while this message comes, 5927 // it means we were not able to reconnect within the alloted time 5928 // = LINK_FLAPPING_DEBOUNCE_MSEC 5929 // and thus, trigger a real disconnect 5930 handleNetworkDisconnect(); 5931 transitionTo(mDisconnectedState); 5932 } 5933 break; 5934 default: 5935 return NOT_HANDLED; 5936 } 5937 5938 return HANDLED; 5939 } 5940 } 5941 5942 class ObtainingIpState extends State { 5943 @Override 5944 public void enter() { 5945 if (DBG) { 5946 String key = ""; 5947 if (getCurrentWifiConfiguration() != null) { 5948 key = getCurrentWifiConfiguration().configKey(); 5949 } 5950 log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId) 5951 + " " + key + " " 5952 + " roam=" + mAutoRoaming 5953 + " static=" + mWifiConfigStore.isUsingStaticIp(mLastNetworkId) 5954 + " watchdog= " + obtainingIpWatchdogCount); 5955 } 5956 5957 // Reset link Debouncing, indicating we have successfully re-connected to the AP 5958 // We might still be roaming 5959 linkDebouncing = false; 5960 5961 try { 5962 mNwService.enableIpv6(mInterfaceName); 5963 } catch (RemoteException re) { 5964 loge("Failed to enable IPv6: " + re); 5965 } catch (IllegalStateException e) { 5966 loge("Failed to enable IPv6: " + e); 5967 } 5968 5969 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 5970 // TODO: If we're switching between static IP configuration and DHCP, remove the 5971 // static configuration first. 5972 if (isRoaming()) { 5973 renewDhcp(); 5974 } else { 5975 startDhcp(); 5976 } 5977 obtainingIpWatchdogCount++; 5978 loge("Start Dhcp Watchdog " + obtainingIpWatchdogCount); 5979 sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER, 5980 obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC); 5981 } else { 5982 // stop any running dhcp before assigning static IP 5983 stopDhcp(); 5984 DhcpResults dhcpResults = new DhcpResults( 5985 mWifiConfigStore.getLinkProperties(mLastNetworkId)); 5986 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 5987 Iterator<LinkAddress> addrs = 5988 dhcpResults.linkProperties.getLinkAddresses().iterator(); 5989 if (!addrs.hasNext()) { 5990 loge("Static IP lacks address"); 5991 sendMessage(CMD_STATIC_IP_FAILURE); 5992 } else { 5993 ifcg.setLinkAddress(addrs.next()); 5994 ifcg.setInterfaceUp(); 5995 try { 5996 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 5997 if (DBG) log("Static IP configuration succeeded"); 5998 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults); 5999 } catch (RemoteException re) { 6000 loge("Static IP configuration failed: " + re); 6001 sendMessage(CMD_STATIC_IP_FAILURE); 6002 } catch (IllegalStateException e) { 6003 loge("Static IP configuration failed: " + e); 6004 sendMessage(CMD_STATIC_IP_FAILURE); 6005 } 6006 } 6007 } 6008 } 6009 @Override 6010 public boolean processMessage(Message message) { 6011 logStateAndMessage(message, getClass().getSimpleName()); 6012 6013 switch(message.what) { 6014 case CMD_STATIC_IP_SUCCESS: 6015 handleIPv4Success((DhcpResults) message.obj, CMD_STATIC_IP_SUCCESS); 6016 break; 6017 case CMD_STATIC_IP_FAILURE: 6018 handleIPv4Failure(CMD_STATIC_IP_FAILURE); 6019 break; 6020 case WifiManager.SAVE_NETWORK: 6021 deferMessage(message); 6022 break; 6023 /* Defer any power mode changes since we must keep active power mode at DHCP */ 6024 case CMD_SET_HIGH_PERF_MODE: 6025 deferMessage(message); 6026 break; 6027 /* Defer scan request since we should not switch to other channels at DHCP */ 6028 case CMD_START_SCAN: 6029 deferMessage(message); 6030 break; 6031 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: 6032 if (message.arg1 == obtainingIpWatchdogCount) { 6033 loge("ObtainingIpAddress: Watchdog Triggered, count=" + obtainingIpWatchdogCount); 6034 handleIpConfigurationLost(); 6035 transitionTo(mDisconnectingState); 6036 break; 6037 } 6038 default: 6039 return NOT_HANDLED; 6040 } 6041 return HANDLED; 6042 } 6043 } 6044 6045 class VerifyingLinkState extends State { 6046 @Override 6047 public void enter() { 6048 log(getName() + " enter"); 6049 setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); 6050 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); 6051 sendNetworkStateChangeBroadcast(mLastBssid); 6052 // End roaming 6053 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 6054 } 6055 @Override 6056 public boolean processMessage(Message message) { 6057 logStateAndMessage(message, getClass().getSimpleName()); 6058 6059 switch (message.what) { 6060 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 6061 // Stay here 6062 log(getName() + " POOR_LINK_DETECTED: no transition"); 6063 break; 6064 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 6065 log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); 6066 6067 log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED"); 6068 sendConnectedState(); 6069 transitionTo(mConnectedState); 6070 break; 6071 case CMD_START_SCAN: 6072 deferMessage(message); 6073 break; 6074 default: 6075 if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); 6076 return NOT_HANDLED; 6077 } 6078 return HANDLED; 6079 } 6080 } 6081 6082 private void sendConnectedState() { 6083 // Send out a broadcast with the CAPTIVE_PORTAL_CHECK to preserve 6084 // existing behaviour. The captive portal check really happens after we 6085 // transition into DetailedState.CONNECTED. 6086 setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); 6087 mWifiConfigStore.updateStatus(mLastNetworkId, 6088 DetailedState.CAPTIVE_PORTAL_CHECK); 6089 sendNetworkStateChangeBroadcast(mLastBssid); 6090 6091 setNetworkDetailedState(DetailedState.CONNECTED); 6092 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); 6093 sendNetworkStateChangeBroadcast(mLastBssid); 6094 } 6095 6096 class RoamingState extends State { 6097 @Override 6098 public void enter() { 6099 if (DBG) { 6100 log("RoamingState Enter" 6101 + " mScreenOn=" + mScreenOn ); 6102 } 6103 setScanAlarm(false); 6104 //TODO: actually implement an alarm, but so as to disconnect if roaming fails 6105 } 6106 @Override 6107 public boolean processMessage(Message message) { 6108 logStateAndMessage(message, getClass().getSimpleName()); 6109 6110 switch (message.what) { 6111 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 6112 if (DBG) log("Roaming and Watchdog reports poor link -> ignore"); 6113 return HANDLED; 6114 case CMD_UNWANTED_NETWORK: 6115 if (DBG) log("Roaming and CS doesnt want the network -> ignore"); 6116 return HANDLED; 6117 case CMD_SET_OPERATIONAL_MODE: 6118 if (message.arg1 != CONNECT_MODE) { 6119 deferMessage(message); 6120 } 6121 break; 6122 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6123 /** 6124 * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT 6125 * before NETWORK_DISCONNECTION_EVENT 6126 * And there is an associated BSSID corresponding to our target BSSID, then 6127 * we have missed the network disconnection, transition to mDisconnectedState 6128 * and handle the rest of the events there. 6129 */ 6130 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 6131 if (stateChangeResult.state == SupplicantState.DISCONNECTED 6132 || stateChangeResult.state == SupplicantState.INACTIVE 6133 || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) { 6134 if (DBG) { 6135 log("STATE_CHANGE_EVENT in roaming state " 6136 + stateChangeResult.toString() ); 6137 } 6138 if (stateChangeResult.BSSID != null 6139 && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) { 6140 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 6141 handleNetworkDisconnect(); 6142 } 6143 } 6144 break; 6145 case WifiMonitor.NETWORK_CONNECTION_EVENT: 6146 if (DBG) log("roaming and Network connection established"); 6147 mLastNetworkId = message.arg1; 6148 mLastBssid = (String) message.obj; 6149 mWifiInfo.setBSSID(mLastBssid); 6150 mWifiInfo.setNetworkId(mLastNetworkId); 6151 mWifiConfigStore.handleBSSIDBlackList(mLastNetworkId, mLastBssid, true); 6152 /** 6153 * We already have an IP address, we are going to the ObtainingIpAddress 6154 * state to renew it. Other parts of the system interpret an 6155 * ObtainingIpState change as not having IP address anymore, 6156 * hence, don't send the state change there. */ 6157 // setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 6158 // sendNetworkStateChangeBroadcast(mLastBssid); 6159 transitionTo(mObtainingIpState); 6160 break; 6161 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 6162 // Throw away but only if it correspond to the network we're roaming to 6163 String bssid = (String)message.obj; 6164 if (DBG) { 6165 log("NETWORK_DISCONNECTION_EVENT in roaming state" 6166 + " BSSID=" + bssid ); 6167 } 6168 if (bssid != null && bssid.equals(mTargetRoamBSSID)) { 6169 handleNetworkDisconnect(); 6170 } 6171 break; 6172 case WifiMonitor.SSID_TEMP_DISABLED: 6173 // Auth error while roaming 6174 if (message.arg1 == mLastNetworkId) { 6175 loge("DISABLED while roaming nid=" + Integer.toString(mLastNetworkId)); 6176 sendMessage(CMD_DISCONNECT); 6177 transitionTo(mDisconnectingState); 6178 } 6179 return NOT_HANDLED; 6180 case CMD_START_SCAN: 6181 deferMessage(message); 6182 break; 6183 default: 6184 return NOT_HANDLED; 6185 } 6186 return HANDLED; 6187 } 6188 6189 @Override 6190 public void exit() { 6191 loge("WifiStateMachine: Leaving Roaming state"); 6192 } 6193 } 6194 6195 class ConnectedState extends State { 6196 @Override 6197 public void enter() { 6198 String address; 6199 updateDefaultRouteMacAddress(1000); 6200 if (DBG) { 6201 log("ConnectedState Enter autojoin=" + mFrameworkAutoJoin.get() 6202 + " mScreenOn=" + mScreenOn 6203 + " scanperiod=" + Integer.toString(mConnectedScanPeriodMs) ); 6204 } 6205 if (mFrameworkAutoJoin.get() && mScreenOn) { 6206 mCurrentScanAlarmMs = mConnectedScanPeriodMs; 6207 setScanAlarm(true); 6208 } else { 6209 mCurrentScanAlarmMs = 0; 6210 } 6211 registerConnected(); 6212 lastConnectAttempt = 0; 6213 targetWificonfiguration = null; 6214 // Paranoia 6215 linkDebouncing = false; 6216 6217 // Not roaming anymore 6218 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 6219 6220 if (testNetworkDisconnect) { 6221 testNetworkDisconnectCounter++; 6222 loge("ConnectedState Enter start disconnect test " + 6223 testNetworkDisconnectCounter); 6224 sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT, 6225 testNetworkDisconnectCounter, 0), 15000); 6226 } 6227 } 6228 @Override 6229 public boolean processMessage(Message message) { 6230 logStateAndMessage(message, getClass().getSimpleName()); 6231 6232 switch (message.what) { 6233 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 6234 if (DBG) log("Watchdog reports poor link"); 6235 transitionTo(mVerifyingLinkState); 6236 break; 6237 case CMD_UNWANTED_NETWORK: 6238 mWifiConfigStore.handleBadNetworkDisconnectReport(mLastNetworkId, mWifiInfo); 6239 mWifiNative.disconnect(); 6240 transitionTo(mDisconnectingState); 6241 return HANDLED; 6242 case CMD_TEST_NETWORK_DISCONNECT: 6243 // Force a disconnect 6244 if (message.arg1 == testNetworkDisconnectCounter) { 6245 mWifiNative.disconnect(); 6246 } 6247 break; 6248 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 6249 if (!linkDebouncing && ( 6250 (ScanResult.is24GHz(mWifiInfo.getFrequency()) 6251 && mWifiInfo.getRssi() > 6252 WifiConfiguration.BAD_RSSI_24) 6253 || (ScanResult.is5GHz(mWifiInfo.getFrequency()) 6254 && mWifiInfo.getRssi() > 6255 WifiConfiguration.BAD_RSSI_5))) { 6256 // Start de-bouncing the L2 disconnection: 6257 // this L2 disconnection might be spurious. 6258 // Hence we allow 7 seconds for the state machine to try 6259 // to reconnect, go thru the 6260 // roaming cycle and enter Obtaining IP address 6261 // before signalling the disconnect to ConnectivityService and L3 6262 startScanForConfiguration(getCurrentWifiConfiguration(), false); 6263 linkDebouncing = true; 6264 6265 sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT, 6266 0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC); 6267 if (DBG) { 6268 log("NETWORK_DISCONNECTION_EVENT in connected state" 6269 + " BSSID=" + mWifiInfo.getBSSID() 6270 + " RSSI=" + mWifiInfo.getRssi() 6271 + " freq=" + mWifiInfo.getFrequency() 6272 + " -> debounce"); 6273 } 6274 return HANDLED; 6275 } else { 6276 if (DBG) { 6277 log("NETWORK_DISCONNECTION_EVENT in connected state" 6278 + " BSSID=" + mWifiInfo.getBSSID() 6279 + " RSSI=" + mWifiInfo.getRssi() 6280 + " freq=" + mWifiInfo.getFrequency() 6281 + " was debouncing=" + linkDebouncing); 6282 } 6283 } 6284 break; 6285 case CMD_AUTO_ROAM: 6286 /* This will happen similarly to an Auto_CONNECT, except we specify the BSSID */ 6287 /* Work Around: wpa_supplicant can get in a bad state where it returns a non 6288 * associated status thus the STATUS command but somehow-someplace still thinks 6289 * it is associated and thus will ignore select/reconnect command with 6290 * following message: 6291 * "Already associated with the selected network - do nothing" 6292 * 6293 * Hence, sends a disconnect to supplicant first. 6294 */ 6295 //mWifiNative.disconnect(); 6296 6297 /* Connect command coming from auto-join */ 6298 ScanResult candidate = (ScanResult)message.obj; 6299 String bssid = "any"; 6300 if (candidate != null) { 6301 bssid = candidate.BSSID; 6302 } 6303 int netId = mLastNetworkId; 6304 WifiConfiguration config = getCurrentWifiConfiguration(); 6305 6306 loge("CMD_AUTO_ROAM sup state " 6307 + mSupplicantStateTracker.getSupplicantStateName() 6308 + " my state " + getCurrentState().getName() 6309 + " nid=" + Integer.toString(netId) 6310 + " roam=" + Integer.toString(message.arg2) 6311 + bssid); 6312 if (config == null) { 6313 loge("AUTO_ROAM and no config, bail out..."); 6314 break; 6315 } 6316 6317 /* Save the BSSID so as to lock it @ firmware */ 6318 autoRoamSetBSSID(config, bssid); 6319 6320 /* Save the network config */ 6321 loge("CMD_AUTO_ROAM will save config -> " + config.SSID 6322 + " nid=" + Integer.toString(netId)); 6323 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 6324 netId = result.getNetworkId(); 6325 loge("CMD_AUTO_ROAM did save config -> " 6326 + " nid=" + Integer.toString(netId)); 6327 6328 if (mWifiConfigStore.selectNetwork(netId) && 6329 mWifiNative.reassociate()) { 6330 lastConnectAttempt = System.currentTimeMillis(); 6331 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 6332 6333 // replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 6334 mAutoRoaming = message.arg2; 6335 transitionTo(mRoamingState); 6336 6337 } else { 6338 loge("Failed to connect config: " + config + " netId: " + netId); 6339 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 6340 WifiManager.ERROR); 6341 break; 6342 } 6343 break; 6344 default: 6345 return NOT_HANDLED; 6346 } 6347 return HANDLED; 6348 } 6349 6350 @Override 6351 public void exit() { 6352 loge("WifiStateMachine: Leaving Connected state"); 6353 setScanAlarm(false); 6354 } 6355 } 6356 6357 class DisconnectingState extends State { 6358 6359 @Override 6360 public void enter() { 6361 if (mFrameworkAutoJoin.get()) { 6362 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 6363 } else { 6364 6365 mCurrentScanAlarmMs = mFrameworkScanIntervalMs; 6366 } 6367 6368 if (PDBG) { 6369 loge(" Enter DisconnectingState State scan interval " + mFrameworkScanIntervalMs 6370 + " mEnableBackgroundScan= " + mEnableBackgroundScan 6371 + " screenOn=" + mScreenOn); 6372 } 6373 if (mScreenOn) 6374 setScanAlarm(true); 6375 } 6376 6377 @Override 6378 public boolean processMessage(Message message) { 6379 logStateAndMessage(message, getClass().getSimpleName()); 6380 switch (message.what) { 6381 case CMD_SET_OPERATIONAL_MODE: 6382 if (message.arg1 != CONNECT_MODE) { 6383 deferMessage(message); 6384 } 6385 break; 6386 case CMD_START_SCAN: 6387 // Ignore scans while disconnecting 6388 return HANDLED; 6389 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6390 /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT 6391 * we have missed the network disconnection, transition to mDisconnectedState 6392 * and handle the rest of the events there 6393 */ 6394 deferMessage(message); 6395 handleNetworkDisconnect(); 6396 transitionTo(mDisconnectedState); 6397 break; 6398 default: 6399 return NOT_HANDLED; 6400 } 6401 return HANDLED; 6402 } 6403 6404 @Override 6405 public void exit() { 6406 mCurrentScanAlarmMs = 0; 6407 } 6408 } 6409 6410 class DisconnectedState extends State { 6411 @Override 6412 public void enter() { 6413 // We dont scan frequently if this is a temporary disconnect 6414 // due to p2p 6415 if (mTemporarilyDisconnectWifi) { 6416 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 6417 return; 6418 } 6419 6420 // Loose the last selection choice 6421 // mWifiAutoJoinController.setLastSelectedConfiguration 6422 // (WifiConfiguration.INVALID_NETWORK_ID); 6423 6424 mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 6425 Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS, 6426 mDefaultFrameworkScanIntervalMs); 6427 6428 if (mFrameworkAutoJoin.get()) { 6429 if (mScreenOn) 6430 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 6431 } else { 6432 mCurrentScanAlarmMs = mFrameworkScanIntervalMs; 6433 } 6434 6435 if (PDBG) { 6436 loge(" Enter disconnected State scan interval " + mFrameworkScanIntervalMs 6437 + " mEnableBackgroundScan= " + mEnableBackgroundScan 6438 + " screenOn=" + mScreenOn); 6439 } 6440 6441 /** clear the roaming state, if we were roaming, we failed */ 6442 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 6443 6444 /** 6445 * mFrameworkAutoJoin is False: We initiate background scanning if it is enabled, 6446 * otherwise we initiate an infrequent scan that wakes up the device to ensure 6447 * a user connects to an access point on the move 6448 * 6449 * mFrameworkAutoJoin is True: 6450 * - screen dark and PNO supported => scan alarm disabled 6451 * - everything else => scan alarm enabled with mDefaultFrameworkScanIntervalMs period 6452 */ 6453 if ((mScreenOn == false) && mEnableBackgroundScan) { //mEnableBackgroundScan) { 6454 /* If a regular scan result is pending, do not initiate background 6455 * scan until the scan results are returned. This is needed because 6456 * initiating a background scan will cancel the regular scan and 6457 * scan results will not be returned until background scanning is 6458 * cleared 6459 */ 6460 if (!mIsScanOngoing) { 6461 mWifiNative.enableBackgroundScan(true); 6462 } 6463 } else { 6464 setScanAlarm(true); 6465 } 6466 6467 if (mFrameworkAutoJoin.get() && mScreenOn && isScanAllowed()) { 6468 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 6469 } 6470 6471 /** 6472 * If we have no networks saved, the supplicant stops doing the periodic scan. 6473 * The scans are useful to notify the user of the presence of an open network. 6474 * Note that these are not wake up scans. 6475 */ 6476 if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) { 6477 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 6478 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 6479 } 6480 } 6481 @Override 6482 public boolean processMessage(Message message) { 6483 boolean ret = HANDLED; 6484 6485 logStateAndMessage(message, getClass().getSimpleName()); 6486 6487 switch (message.what) { 6488 case CMD_NO_NETWORKS_PERIODIC_SCAN: 6489 if (mP2pConnected.get()) break; 6490 if (message.arg1 == mPeriodicScanToken && 6491 mWifiConfigStore.getConfiguredNetworks().size() == 0) { 6492 startScan(UNKNOWN_SCAN_SOURCE, null, null); 6493 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 6494 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 6495 } 6496 break; 6497 case WifiManager.FORGET_NETWORK: 6498 case CMD_REMOVE_NETWORK: 6499 // Set up a delayed message here. After the forget/remove is handled 6500 // the handled delayed message will determine if there is a need to 6501 // scan and continue 6502 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 6503 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 6504 ret = NOT_HANDLED; 6505 break; 6506 case CMD_SET_OPERATIONAL_MODE: 6507 if (message.arg1 != CONNECT_MODE) { 6508 mOperationalMode = message.arg1; 6509 6510 mWifiConfigStore.disableAllNetworks(); 6511 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 6512 mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); 6513 setWifiState(WIFI_STATE_DISABLED); 6514 } 6515 6516 transitionTo(mScanModeState); 6517 } 6518 break; 6519 case CMD_ENABLE_BACKGROUND_SCAN: 6520 mEnableBackgroundScan = (message.arg1 == 1); 6521 loge("enableBackgroundScanCommand enabled=" + mEnableBackgroundScan 6522 + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); 6523 6524 if (mEnableBackgroundScan) { 6525 mWifiNative.enableBackgroundScan(true); 6526 setScanAlarm(false); 6527 } else { 6528 if (mFrameworkAutoJoin.get()) { 6529 // Tell supplicant to disconnect so as it doesnt start scanning 6530 // for connection upon disabling background scan 6531 mWifiNative.disconnect(); 6532 } 6533 mWifiNative.enableBackgroundScan(false); 6534 setScanAlarm(true); 6535 } 6536 break; 6537 /* Ignore network disconnect */ 6538 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 6539 break; 6540 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6541 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 6542 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 6543 /* ConnectModeState does the rest of the handling */ 6544 ret = NOT_HANDLED; 6545 break; 6546 case CMD_START_SCAN: 6547 if (!isScanAllowed()) { 6548 // Ignore the scan request 6549 return HANDLED; 6550 } 6551 /* Disable background scan temporarily during a regular scan */ 6552 if (mEnableBackgroundScan) { 6553 mWifiNative.enableBackgroundScan(false); 6554 } 6555 /* Handled in parent state */ 6556 ret = NOT_HANDLED; 6557 break; 6558 case WifiMonitor.SCAN_RESULTS_EVENT: 6559 /* Re-enable background scan when a pending scan result is received */ 6560 if (mEnableBackgroundScan && mIsScanOngoing) { 6561 mWifiNative.enableBackgroundScan(true); 6562 } 6563 /* Handled in parent state */ 6564 ret = NOT_HANDLED; 6565 break; 6566 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 6567 NetworkInfo info = (NetworkInfo) message.obj; 6568 mP2pConnected.set(info.isConnected()); 6569 if (mP2pConnected.get()) { 6570 int defaultInterval = mContext.getResources().getInteger( 6571 R.integer.config_wifi_scan_interval_p2p_connected); 6572 long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 6573 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 6574 defaultInterval); 6575 mWifiNative.setScanInterval((int) scanIntervalMs/1000); 6576 } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { 6577 if (DBG) log("Turn on scanning after p2p disconnected"); 6578 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 6579 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 6580 } 6581 case CMD_RECONNECT: 6582 case CMD_REASSOCIATE: 6583 if (mTemporarilyDisconnectWifi) { 6584 // Drop a third party reconnect/reassociate if STA is 6585 // temporarily disconnected for p2p 6586 break; 6587 } else { 6588 // ConnectModeState handles it 6589 ret = NOT_HANDLED; 6590 } 6591 break; 6592 default: 6593 ret = NOT_HANDLED; 6594 } 6595 return ret; 6596 } 6597 6598 @Override 6599 public void exit() { 6600 /* No need for a background scan upon exit from a disconnected state */ 6601 if (mEnableBackgroundScan) { 6602 mWifiNative.enableBackgroundScan(false); 6603 } 6604 mCurrentScanAlarmMs = 0; 6605 setScanAlarm(false); 6606 } 6607 } 6608 6609 class WpsRunningState extends State { 6610 // Tracks the source to provide a reply 6611 private Message mSourceMessage; 6612 @Override 6613 public void enter() { 6614 mSourceMessage = Message.obtain(getCurrentMessage()); 6615 } 6616 @Override 6617 public boolean processMessage(Message message) { 6618 logStateAndMessage(message, getClass().getSimpleName()); 6619 6620 switch (message.what) { 6621 case WifiMonitor.WPS_SUCCESS_EVENT: 6622 // Ignore intermediate success, wait for full connection 6623 break; 6624 case WifiMonitor.NETWORK_CONNECTION_EVENT: 6625 replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED); 6626 mSourceMessage.recycle(); 6627 mSourceMessage = null; 6628 deferMessage(message); 6629 transitionTo(mDisconnectedState); 6630 break; 6631 case WifiMonitor.WPS_OVERLAP_EVENT: 6632 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 6633 WifiManager.WPS_OVERLAP_ERROR); 6634 mSourceMessage.recycle(); 6635 mSourceMessage = null; 6636 transitionTo(mDisconnectedState); 6637 break; 6638 case WifiMonitor.WPS_FAIL_EVENT: 6639 // Arg1 has the reason for the failure 6640 if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) { 6641 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1); 6642 mSourceMessage.recycle(); 6643 mSourceMessage = null; 6644 transitionTo(mDisconnectedState); 6645 } else { 6646 if (DBG) log("Ignore unspecified fail event during WPS connection"); 6647 } 6648 break; 6649 case WifiMonitor.WPS_TIMEOUT_EVENT: 6650 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 6651 WifiManager.WPS_TIMED_OUT); 6652 mSourceMessage.recycle(); 6653 mSourceMessage = null; 6654 transitionTo(mDisconnectedState); 6655 break; 6656 case WifiManager.START_WPS: 6657 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS); 6658 break; 6659 case WifiManager.CANCEL_WPS: 6660 if (mWifiNative.cancelWps()) { 6661 replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED); 6662 } else { 6663 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR); 6664 } 6665 transitionTo(mDisconnectedState); 6666 break; 6667 /** 6668 * Defer all commands that can cause connections to a different network 6669 * or put the state machine out of connect mode 6670 */ 6671 case CMD_STOP_DRIVER: 6672 case CMD_SET_OPERATIONAL_MODE: 6673 case WifiManager.CONNECT_NETWORK: 6674 case CMD_ENABLE_NETWORK: 6675 case CMD_RECONNECT: 6676 case CMD_REASSOCIATE: 6677 deferMessage(message); 6678 break; 6679 case CMD_AUTO_CONNECT: 6680 case CMD_AUTO_ROAM: 6681 case CMD_START_SCAN: 6682 return HANDLED; 6683 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 6684 if (DBG) log("Network connection lost"); 6685 handleNetworkDisconnect(); 6686 break; 6687 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 6688 if (DBG) log("Ignore Assoc reject event during WPS Connection"); 6689 break; 6690 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 6691 // Disregard auth failure events during WPS connection. The 6692 // EAP sequence is retried several times, and there might be 6693 // failures (especially for wps pin). We will get a WPS_XXX 6694 // event at the end of the sequence anyway. 6695 if (DBG) log("Ignore auth failure during WPS connection"); 6696 break; 6697 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6698 // Throw away supplicant state changes when WPS is running. 6699 // We will start getting supplicant state changes once we get 6700 // a WPS success or failure 6701 break; 6702 default: 6703 return NOT_HANDLED; 6704 } 6705 return HANDLED; 6706 } 6707 6708 @Override 6709 public void exit() { 6710 mWifiConfigStore.enableAllNetworks(); 6711 mWifiConfigStore.loadConfiguredNetworks(); 6712 } 6713 } 6714 6715 class SoftApStartingState extends State { 6716 @Override 6717 public void enter() { 6718 final Message message = getCurrentMessage(); 6719 if (message.what == CMD_START_AP) { 6720 final WifiConfiguration config = (WifiConfiguration) message.obj; 6721 6722 if (config == null) { 6723 mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); 6724 } else { 6725 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 6726 startSoftApWithConfig(config); 6727 } 6728 } else { 6729 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); 6730 } 6731 } 6732 @Override 6733 public boolean processMessage(Message message) { 6734 logStateAndMessage(message, getClass().getSimpleName()); 6735 6736 switch(message.what) { 6737 case CMD_START_SUPPLICANT: 6738 case CMD_STOP_SUPPLICANT: 6739 case CMD_START_AP: 6740 case CMD_STOP_AP: 6741 case CMD_START_DRIVER: 6742 case CMD_STOP_DRIVER: 6743 case CMD_SET_OPERATIONAL_MODE: 6744 case CMD_SET_COUNTRY_CODE: 6745 case CMD_SET_FREQUENCY_BAND: 6746 case CMD_START_PACKET_FILTERING: 6747 case CMD_STOP_PACKET_FILTERING: 6748 case CMD_TETHER_STATE_CHANGE: 6749 deferMessage(message); 6750 break; 6751 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: 6752 WifiConfiguration config = (WifiConfiguration) message.obj; 6753 if (config != null) { 6754 startSoftApWithConfig(config); 6755 } else { 6756 loge("Softap config is null!"); 6757 sendMessage(CMD_START_AP_FAILURE); 6758 } 6759 break; 6760 case CMD_START_AP_SUCCESS: 6761 setWifiApState(WIFI_AP_STATE_ENABLED); 6762 transitionTo(mSoftApStartedState); 6763 break; 6764 case CMD_START_AP_FAILURE: 6765 setWifiApState(WIFI_AP_STATE_FAILED); 6766 transitionTo(mInitialState); 6767 break; 6768 default: 6769 return NOT_HANDLED; 6770 } 6771 return HANDLED; 6772 } 6773 } 6774 6775 class SoftApStartedState extends State { 6776 @Override 6777 public boolean processMessage(Message message) { 6778 logStateAndMessage(message, getClass().getSimpleName()); 6779 6780 switch(message.what) { 6781 case CMD_STOP_AP: 6782 if (DBG) log("Stopping Soft AP"); 6783 /* We have not tethered at this point, so we just shutdown soft Ap */ 6784 try { 6785 mNwService.stopAccessPoint(mInterfaceName); 6786 } catch(Exception e) { 6787 loge("Exception in stopAccessPoint()"); 6788 } 6789 setWifiApState(WIFI_AP_STATE_DISABLED); 6790 transitionTo(mInitialState); 6791 break; 6792 case CMD_START_AP: 6793 // Ignore a start on a running access point 6794 break; 6795 // Fail client mode operation when soft AP is enabled 6796 case CMD_START_SUPPLICANT: 6797 loge("Cannot start supplicant with a running soft AP"); 6798 setWifiState(WIFI_STATE_UNKNOWN); 6799 break; 6800 case CMD_TETHER_STATE_CHANGE: 6801 TetherStateChange stateChange = (TetherStateChange) message.obj; 6802 if (startTethering(stateChange.available)) { 6803 transitionTo(mTetheringState); 6804 } 6805 break; 6806 default: 6807 return NOT_HANDLED; 6808 } 6809 return HANDLED; 6810 } 6811 } 6812 6813 class TetheringState extends State { 6814 @Override 6815 public void enter() { 6816 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 6817 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 6818 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 6819 } 6820 @Override 6821 public boolean processMessage(Message message) { 6822 logStateAndMessage(message, getClass().getSimpleName()); 6823 6824 switch(message.what) { 6825 case CMD_TETHER_STATE_CHANGE: 6826 TetherStateChange stateChange = (TetherStateChange) message.obj; 6827 if (isWifiTethered(stateChange.active)) { 6828 transitionTo(mTetheredState); 6829 } 6830 return HANDLED; 6831 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 6832 if (message.arg1 == mTetherToken) { 6833 loge("Failed to get tether update, shutdown soft access point"); 6834 transitionTo(mSoftApStartedState); 6835 // Needs to be first thing handled 6836 sendMessageAtFrontOfQueue(CMD_STOP_AP); 6837 } 6838 break; 6839 case CMD_START_SUPPLICANT: 6840 case CMD_STOP_SUPPLICANT: 6841 case CMD_START_AP: 6842 case CMD_STOP_AP: 6843 case CMD_START_DRIVER: 6844 case CMD_STOP_DRIVER: 6845 case CMD_SET_OPERATIONAL_MODE: 6846 case CMD_SET_COUNTRY_CODE: 6847 case CMD_SET_FREQUENCY_BAND: 6848 case CMD_START_PACKET_FILTERING: 6849 case CMD_STOP_PACKET_FILTERING: 6850 deferMessage(message); 6851 break; 6852 default: 6853 return NOT_HANDLED; 6854 } 6855 return HANDLED; 6856 } 6857 } 6858 6859 class TetheredState extends State { 6860 @Override 6861 public boolean processMessage(Message message) { 6862 logStateAndMessage(message, getClass().getSimpleName()); 6863 6864 switch(message.what) { 6865 case CMD_TETHER_STATE_CHANGE: 6866 TetherStateChange stateChange = (TetherStateChange) message.obj; 6867 if (!isWifiTethered(stateChange.active)) { 6868 loge("Tethering reports wifi as untethered!, shut down soft Ap"); 6869 setHostApRunning(null, false); 6870 setHostApRunning(null, true); 6871 } 6872 return HANDLED; 6873 case CMD_STOP_AP: 6874 if (DBG) log("Untethering before stopping AP"); 6875 setWifiApState(WIFI_AP_STATE_DISABLING); 6876 stopTethering(); 6877 transitionTo(mUntetheringState); 6878 // More work to do after untethering 6879 deferMessage(message); 6880 break; 6881 default: 6882 return NOT_HANDLED; 6883 } 6884 return HANDLED; 6885 } 6886 } 6887 6888 class UntetheringState extends State { 6889 @Override 6890 public void enter() { 6891 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 6892 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 6893 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 6894 6895 } 6896 @Override 6897 public boolean processMessage(Message message) { 6898 logStateAndMessage(message, getClass().getSimpleName()); 6899 6900 switch(message.what) { 6901 case CMD_TETHER_STATE_CHANGE: 6902 TetherStateChange stateChange = (TetherStateChange) message.obj; 6903 6904 /* Wait till wifi is untethered */ 6905 if (isWifiTethered(stateChange.active)) break; 6906 6907 transitionTo(mSoftApStartedState); 6908 break; 6909 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 6910 if (message.arg1 == mTetherToken) { 6911 loge("Failed to get tether update, force stop access point"); 6912 transitionTo(mSoftApStartedState); 6913 } 6914 break; 6915 case CMD_START_SUPPLICANT: 6916 case CMD_STOP_SUPPLICANT: 6917 case CMD_START_AP: 6918 case CMD_STOP_AP: 6919 case CMD_START_DRIVER: 6920 case CMD_STOP_DRIVER: 6921 case CMD_SET_OPERATIONAL_MODE: 6922 case CMD_SET_COUNTRY_CODE: 6923 case CMD_SET_FREQUENCY_BAND: 6924 case CMD_START_PACKET_FILTERING: 6925 case CMD_STOP_PACKET_FILTERING: 6926 deferMessage(message); 6927 break; 6928 default: 6929 return NOT_HANDLED; 6930 } 6931 return HANDLED; 6932 } 6933 } 6934 6935 //State machine initiated requests can have replyTo set to null indicating 6936 //there are no recepients, we ignore those reply actions 6937 private void replyToMessage(Message msg, int what) { 6938 if (msg.replyTo == null) return; 6939 Message dstMsg = obtainMessageWithArg2(msg); 6940 dstMsg.what = what; 6941 mReplyChannel.replyToMessage(msg, dstMsg); 6942 } 6943 6944 private void replyToMessage(Message msg, int what, int arg1) { 6945 if (msg.replyTo == null) return; 6946 Message dstMsg = obtainMessageWithArg2(msg); 6947 dstMsg.what = what; 6948 dstMsg.arg1 = arg1; 6949 mReplyChannel.replyToMessage(msg, dstMsg); 6950 } 6951 6952 private void replyToMessage(Message msg, int what, Object obj) { 6953 if (msg.replyTo == null) return; 6954 Message dstMsg = obtainMessageWithArg2(msg); 6955 dstMsg.what = what; 6956 dstMsg.obj = obj; 6957 mReplyChannel.replyToMessage(msg, dstMsg); 6958 } 6959 6960 /** 6961 * arg2 on the source message has a unique id that needs to be retained in replies 6962 * to match the request 6963 6964 * see WifiManager for details 6965 */ 6966 private Message obtainMessageWithArg2(Message srcMsg) { 6967 Message msg = Message.obtain(); 6968 msg.arg2 = srcMsg.arg2; 6969 return msg; 6970 } 6971 6972 private static int parseHex(char ch) { 6973 if ('0' <= ch && ch <= '9') { 6974 return ch - '0'; 6975 } else if ('a' <= ch && ch <= 'f') { 6976 return ch - 'a' + 10; 6977 } else if ('A' <= ch && ch <= 'F') { 6978 return ch - 'A' + 10; 6979 } else { 6980 throw new NumberFormatException("" + ch + " is not a valid hex digit"); 6981 } 6982 } 6983 6984 private byte[] parseHex(String hex) { 6985 /* This only works for good input; don't throw bad data at it */ 6986 if (hex == null) { 6987 return new byte[0]; 6988 } 6989 6990 if (hex.length() % 2 != 0) { 6991 throw new NumberFormatException(hex + " is not a valid hex string"); 6992 } 6993 6994 byte[] result = new byte[(hex.length())/2]; 6995 for (int i = 0, j = 0; i < hex.length(); i += 2, j++) { 6996 6997 int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i+1)); 6998 byte b = (byte) (val & 0xFF); 6999 result[j] = b; 7000 } 7001 7002 return result; 7003 } 7004 7005 private static String makeHex(byte[] bytes) { 7006 StringBuilder sb = new StringBuilder(); 7007 for (byte b : bytes) { 7008 sb.append(String.format("%02x", b)); 7009 } 7010 return sb.toString(); 7011 } 7012 7013 private static byte[] concat(byte[] array1, byte[] array2, byte[] array3) { 7014 7015 int len = array1.length + array2.length + array3.length; 7016 7017 if (array1.length != 0) { 7018 len++; /* add another byte for size */ 7019 } 7020 7021 if (array2.length != 0) { 7022 len++; /* add another byte for size */ 7023 } 7024 7025 if (array3.length != 0) { 7026 len++; /* add another byte for size */ 7027 } 7028 7029 byte[] result = new byte[len]; 7030 7031 int index = 0; 7032 if (array1.length != 0) { 7033 result[index] = (byte) (array1.length & 0xFF); 7034 index++; 7035 for (byte b : array1) { 7036 result[index] = b; 7037 index++; 7038 } 7039 } 7040 7041 if (array2.length != 0) { 7042 result[index] = (byte) (array2.length & 0xFF); 7043 index++; 7044 for (byte b : array2) { 7045 result[index] = b; 7046 index++; 7047 } 7048 } 7049 7050 if (array3.length != 0) { 7051 result[index] = (byte) (array3.length & 0xFF); 7052 index++; 7053 for (byte b : array3) { 7054 result[index] = b; 7055 index++; 7056 } 7057 } 7058 return result; 7059 } 7060 7061 void handleSimAuthRequest(SimAuthRequestData requestData) { 7062 if (targetWificonfiguration == null 7063 || targetWificonfiguration.networkId == requestData.networkId) { 7064 logd("id matches targetWifiConfiguration"); 7065 } else { 7066 logd("id does not match targetWifiConfiguration"); 7067 } 7068 7069 logd("rand1 = " + requestData.rand1); 7070 logd("rand2 = " + requestData.rand2); 7071 logd("rand3 = " + requestData.rand3); 7072 7073 byte[] rand1, rand2, rand3; 7074 7075 try { 7076 rand1 = parseHex(requestData.rand1); 7077 rand2 = parseHex(requestData.rand2); 7078 rand3 = parseHex(requestData.rand3); 7079 } catch (NumberFormatException e) { 7080 loge("malformed challenge"); 7081 return; 7082 } 7083 7084 byte[] c = concat(rand1, rand2, rand3); 7085 7086 String challenge = android.util.Base64.encodeToString(c, android.util.Base64.NO_WRAP); 7087 7088 logd("challenge = " + challenge); 7089 logd("challenge length = " + challenge.length()); 7090 7091 TelephonyManager tm = (TelephonyManager) 7092 mContext.getSystemService(Context.TELEPHONY_SERVICE); 7093 7094 if (tm != null) { 7095 /* 7096 * appType = 1 => SIM, 2 => USIM according to 7097 * com.android.internal.telephony.PhoneConstants#APPTYPE_xxx 7098 */ 7099 7100 int appType = 2; 7101 String response = tm.getIccSimChallengeResponse(appType, challenge); 7102 logd("Raw Response - " + response); 7103 7104 if (response != null) { 7105 byte[] result = android.util.Base64.decode(response, android.util.Base64.DEFAULT); 7106 response = makeHex(result); 7107 logd("Sim Response - " + response); 7108 mWifiNative.simAuthResponse(requestData.networkId, response); 7109 } else { 7110 logd("bad response - " + response); 7111 } 7112 7113 } else { 7114 loge("could not get telephony manager"); 7115 } 7116 7117 } 7118} 7119