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