WifiStateMachine.java revision 3b26801d62a06475b722bbf29cba7f48f376654e
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.wifi; 18 19import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; 20import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; 21import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; 22import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; 23import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; 24 25/** 26 * TODO: 27 * Deprecate WIFI_STATE_UNKNOWN 28 */ 29import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; 30import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; 31import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; 32import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; 33import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; 34 35import android.app.AlarmManager; 36import android.app.PendingIntent; 37import android.app.backup.IBackupManager; 38import android.bluetooth.BluetoothAdapter; 39import android.content.BroadcastReceiver; 40import android.content.Context; 41import android.content.Intent; 42import android.content.IntentFilter; 43import android.content.pm.PackageManager; 44import android.database.ContentObserver; 45import android.net.ConnectivityManager; 46import android.net.DhcpResults; 47import android.net.DhcpStateMachine; 48import android.net.InterfaceConfiguration; 49import android.net.LinkAddress; 50import android.net.LinkProperties; 51import android.net.NetworkAgent; 52import android.net.NetworkCapabilities; 53import android.net.NetworkFactory; 54import android.net.NetworkInfo; 55import android.net.NetworkInfo.DetailedState; 56import android.net.NetworkUtils; 57import android.net.RouteInfo; 58import android.net.StaticIpConfiguration; 59import android.net.TrafficStats; 60import android.net.wifi.*; 61import android.net.wifi.WpsResult.Status; 62import android.net.wifi.p2p.IWifiP2pManager; 63import android.net.wifi.passpoint.IWifiPasspointManager; 64import android.os.BatteryStats; 65import android.os.Bundle; 66import android.os.IBinder; 67import android.os.INetworkManagementService; 68import android.os.Looper; 69import android.os.Message; 70import android.os.Messenger; 71import android.os.PowerManager; 72import android.os.Process; 73import android.os.RemoteException; 74import android.os.ServiceManager; 75import android.os.SystemClock; 76import android.os.SystemProperties; 77import android.os.UserHandle; 78import android.os.WorkSource; 79import android.provider.Settings; 80import android.telephony.TelephonyManager; 81import android.util.LruCache; 82import android.text.TextUtils; 83import android.util.Log; 84 85import com.android.internal.R; 86import com.android.internal.app.IBatteryStats; 87import com.android.internal.util.AsyncChannel; 88import com.android.internal.util.Protocol; 89import com.android.internal.util.State; 90import com.android.internal.util.StateMachine; 91import com.android.server.net.BaseNetworkObserver; 92import com.android.server.net.NetlinkTracker; 93 94import com.android.server.wifi.p2p.WifiP2pServiceImpl; 95import com.android.server.wifi.passpoint.WifiPasspointServiceImpl; 96 97import java.io.FileDescriptor; 98import java.io.PrintWriter; 99import java.net.InetAddress; 100import java.util.*; 101import java.util.concurrent.atomic.AtomicInteger; 102import java.util.concurrent.atomic.AtomicBoolean; 103import java.util.regex.Pattern; 104import java.io.FileReader; 105import java.io.BufferedReader; 106import java.io.FileNotFoundException; 107import java.io.IOException; 108import java.net.Inet4Address; 109 110/** 111 * Track the state of Wifi connectivity. All event handling is done here, 112 * and all changes in connectivity state are initiated here. 113 * 114 * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p 115 * In the current implementation, we support concurrent wifi p2p and wifi operation. 116 * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService 117 * handles p2p operation. 118 * 119 * @hide 120 */ 121public class WifiStateMachine extends StateMachine { 122 123 private static final String NETWORKTYPE = "WIFI"; 124 private static boolean DBG = false; 125 private static boolean VDBG = false; 126 private static boolean mLogMessages = false; 127 128 private static final int ONE_HOUR_MILLI = 1000 * 60 * 60; 129 130 /* temporary debug flag - best network selection development */ 131 private static boolean PDBG = false; 132 133 /* debug flag, indicating if handling of ASSOCIATION_REJECT ended up blacklisting 134 * the corresponding BSSID. 135 */ 136 private boolean didBlackListBSSID = false; 137 138 /** 139 * Log with error attribute 140 * 141 * @param s is string log 142 */ 143 protected void loge(String s) { 144 Log.e(getName(), s); 145 } 146 protected void log(String s) {; 147 Log.e(getName(), s); 148 } 149 150 private WifiMonitor mWifiMonitor; 151 private WifiNative mWifiNative; 152 private WifiConfigStore mWifiConfigStore; 153 private WifiAutoJoinController mWifiAutoJoinController; 154 private INetworkManagementService mNwService; 155 private ConnectivityManager mCm; 156 157 private final boolean mP2pSupported; 158 private final AtomicBoolean mP2pConnected = new AtomicBoolean(false); 159 private boolean mTemporarilyDisconnectWifi = false; 160 private final String mPrimaryDeviceType; 161 162 /* Scan results handling */ 163 private List<ScanResult> mScanResults = new ArrayList<ScanResult>(); 164 private static final Pattern scanResultPattern = Pattern.compile("\t+"); 165 private static final int SCAN_RESULT_CACHE_SIZE = 80; 166 private final LruCache<String, ScanResult> mScanResultCache; 167 168 /* Batch scan results */ 169 private final List<BatchedScanResult> mBatchedScanResults = 170 new ArrayList<BatchedScanResult>(); 171 private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE; 172 private int mExpectedBatchedScans = 0; 173 private long mBatchedScanMinPollTime = 0; 174 175 private boolean mScreenOn = false; 176 177 /* Chipset supports background scan */ 178 private final boolean mBackgroundScanSupported; 179 180 private String mInterfaceName; 181 /* Tethering interface could be separate from wlan interface */ 182 private String mTetherInterfaceName; 183 184 private int mLastSignalLevel = -1; 185 private String mLastBssid; 186 private int mLastNetworkId; // The network Id we successfully joined 187 private boolean linkDebouncing = false; 188 189 // Testing various network disconnect cases by sending lots of spurious 190 // disconnect to supplicant 191 private boolean testNetworkDisconnect = false; 192 193 private boolean mEnableRssiPolling = false; 194 private boolean mEnableBackgroundScan = false; 195 private int mRssiPollToken = 0; 196 /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE 197 * In CONNECT_MODE, the STA can scan and connect to an access point 198 * In SCAN_ONLY_MODE, the STA can only scan for access points 199 * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off 200 */ 201 private int mOperationalMode = CONNECT_MODE; 202 private boolean mIsScanOngoing = false; 203 private boolean mIsFullScanOngoing = false; 204 private final Queue<Message> mBufferedScanMsg = new LinkedList<Message>(); 205 private WorkSource mScanWorkSource = null; 206 private static final int UNKNOWN_SCAN_SOURCE = -1; 207 private static final int SCAN_ALARM_SOURCE = -2; 208 209 private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10; 210 private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings"; 211 private static final String CUSTOMIZED_SCAN_WORKSOURCE = "customized_scan_worksource"; 212 private static final String BATCHED_SETTING = "batched_settings"; 213 private static final String BATCHED_WORKSOURCE = "batched_worksource"; 214 215 /* Tracks if state machine has received any screen state change broadcast yet. 216 * We can miss one of these at boot. 217 */ 218 private AtomicBoolean mScreenBroadcastReceived = new AtomicBoolean(false); 219 220 private boolean mBluetoothConnectionActive = false; 221 222 private PowerManager.WakeLock mSuspendWakeLock; 223 224 /** 225 * Interval in milliseconds between polling for RSSI 226 * and linkspeed information 227 */ 228 private static final int POLL_RSSI_INTERVAL_MSECS = 3000; 229 230 /** 231 * Interval in milliseconds between receiving a disconnect event 232 * while connected to a good AP, and handling the disconnect proper 233 */ 234 private static final int LINK_FLAPPING_DEBOUNCE_MSEC = 7000; 235 236 /** 237 * Delay between supplicant restarts upon failure to establish connection 238 */ 239 private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000; 240 241 /** 242 * Number of times we attempt to restart supplicant 243 */ 244 private static final int SUPPLICANT_RESTART_TRIES = 5; 245 246 private int mSupplicantRestartCount = 0; 247 /* Tracks sequence number on stop failure message */ 248 private int mSupplicantStopFailureToken = 0; 249 250 /** 251 * Tether state change notification time out 252 */ 253 private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000; 254 255 /* Tracks sequence number on a tether notification time out */ 256 private int mTetherToken = 0; 257 258 /** 259 * Driver start time out. 260 */ 261 private static final int DRIVER_START_TIME_OUT_MSECS = 10000; 262 263 /* Tracks sequence number on a driver time out */ 264 private int mDriverStartToken = 0; 265 266 /** 267 * The link properties of the wifi interface. 268 * Do not modify this directly; use updateLinkProperties instead. 269 */ 270 private LinkProperties mLinkProperties; 271 272 /* Tracks sequence number on a periodic scan message */ 273 private int mPeriodicScanToken = 0; 274 275 // Wakelock held during wifi start/stop and driver load/unload 276 private PowerManager.WakeLock mWakeLock; 277 278 private Context mContext; 279 280 private final Object mDhcpResultsLock = new Object(); 281 private DhcpResults mDhcpResults; 282 private WifiInfo mWifiInfo; 283 private NetworkInfo mNetworkInfo; 284 private NetworkCapabilities mNetworkCapabilities; 285 private SupplicantStateTracker mSupplicantStateTracker; 286 private DhcpStateMachine mDhcpStateMachine; 287 private boolean mDhcpActive = false; 288 289 private int mWifiLinkLayerStatsSupported = 4; 290 291 private final AtomicInteger mCountryCodeSequence = new AtomicInteger(); 292 293 //whether the state machine goes thru the Disconnecting->Disconnected->ObtainingIpAddress 294 private int mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 295 296 private String mTargetRoamBSSID = "any"; 297 298 private WifiConfiguration targetWificonfiguration = null; 299 300 boolean isRoaming() { 301 return mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_ROAMING 302 || mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_EXTENDED_ROAMING; 303 } 304 305 public void autoRoamSetBSSID(int netId, String bssid) { 306 autoRoamSetBSSID(mWifiConfigStore.getWifiConfiguration(netId), bssid); 307 } 308 309 public void autoRoamSetBSSID(WifiConfiguration config, String bssid) { 310 mTargetRoamBSSID = "any"; 311 if (config == null || bssid == null) 312 return; 313 if (config.bssidOwnerUid == 0 || config.bssidOwnerUid == Process.WIFI_UID) { 314 if (VDBG) { 315 loge("autoRoamSetBSSID uid=" + Long.toString(config.bssidOwnerUid) 316 + " bssid=" + bssid 317 + " key=" + config.configKey()); 318 } 319 config.bssidOwnerUid = Process.WIFI_UID; 320 config.BSSID = bssid; 321 mTargetRoamBSSID = bssid; 322 } 323 } 324 325 /** 326 * Subset of link properties coming from netlink. 327 * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers 328 * and domains obtained from router advertisements (RFC 6106). 329 */ 330 private NetlinkTracker mNetlinkTracker; 331 332 private AlarmManager mAlarmManager; 333 private PendingIntent mScanIntent; 334 private PendingIntent mDriverStopIntent; 335 private PendingIntent mBatchedScanIntervalIntent; 336 337 /* Tracks current frequency mode */ 338 private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO); 339 340 /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */ 341 private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true); 342 343 // Channel for sending replies. 344 private AsyncChannel mReplyChannel = new AsyncChannel(); 345 346 private WifiP2pServiceImpl mWifiP2pServiceImpl; 347 private WifiPasspointServiceImpl mPasspointServiceImpl; 348 349 // Used to initiate a connection with WifiP2pService 350 private AsyncChannel mWifiP2pChannel; 351 private AsyncChannel mWifiApConfigChannel; 352 353 private WifiNetworkFactory mNetworkFactory; 354 private WifiNetworkAgent mNetworkAgent; 355 356 // Keep track of various statistics, for retrieval by System Apps, i.e. under @SystemApi 357 // We should really persist that into the networkHistory.txt file, and read it back when 358 // WifiStateMachine starts up 359 private WifiConnectionStatistics mWifiConnectionStatistics = new WifiConnectionStatistics(); 360 361 // Used to filter out requests we couldn't possibly satisfy. 362 private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities(); 363 364 /* The base for wifi message types */ 365 static final int BASE = Protocol.BASE_WIFI; 366 /* Start the supplicant */ 367 static final int CMD_START_SUPPLICANT = BASE + 11; 368 /* Stop the supplicant */ 369 static final int CMD_STOP_SUPPLICANT = BASE + 12; 370 /* Start the driver */ 371 static final int CMD_START_DRIVER = BASE + 13; 372 /* Stop the driver */ 373 static final int CMD_STOP_DRIVER = BASE + 14; 374 /* Indicates Static IP succeeded */ 375 static final int CMD_STATIC_IP_SUCCESS = BASE + 15; 376 /* Indicates Static IP failed */ 377 static final int CMD_STATIC_IP_FAILURE = BASE + 16; 378 /* Indicates supplicant stop failed */ 379 static final int CMD_STOP_SUPPLICANT_FAILED = BASE + 17; 380 /* Delayed stop to avoid shutting down driver too quick*/ 381 static final int CMD_DELAYED_STOP_DRIVER = BASE + 18; 382 /* A delayed message sent to start driver when it fail to come up */ 383 static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19; 384 385 /* Start the soft access point */ 386 static final int CMD_START_AP = BASE + 21; 387 /* Indicates soft ap start succeeded */ 388 static final int CMD_START_AP_SUCCESS = BASE + 22; 389 /* Indicates soft ap start failed */ 390 static final int CMD_START_AP_FAILURE = BASE + 23; 391 /* Stop the soft access point */ 392 static final int CMD_STOP_AP = BASE + 24; 393 /* Set the soft access point configuration */ 394 static final int CMD_SET_AP_CONFIG = BASE + 25; 395 /* Soft access point configuration set completed */ 396 static final int CMD_SET_AP_CONFIG_COMPLETED = BASE + 26; 397 /* Request the soft access point configuration */ 398 static final int CMD_REQUEST_AP_CONFIG = BASE + 27; 399 /* Response to access point configuration request */ 400 static final int CMD_RESPONSE_AP_CONFIG = BASE + 28; 401 /* Invoked when getting a tether state change notification */ 402 static final int CMD_TETHER_STATE_CHANGE = BASE + 29; 403 /* A delayed message sent to indicate tether state change failed to arrive */ 404 static final int CMD_TETHER_NOTIFICATION_TIMED_OUT = BASE + 30; 405 406 static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31; 407 408 /* Supplicant commands */ 409 /* Is supplicant alive ? */ 410 static final int CMD_PING_SUPPLICANT = BASE + 51; 411 /* Add/update a network configuration */ 412 static final int CMD_ADD_OR_UPDATE_NETWORK = BASE + 52; 413 /* Delete a network */ 414 static final int CMD_REMOVE_NETWORK = BASE + 53; 415 /* Enable a network. The device will attempt a connection to the given network. */ 416 static final int CMD_ENABLE_NETWORK = BASE + 54; 417 /* Enable all networks */ 418 static final int CMD_ENABLE_ALL_NETWORKS = BASE + 55; 419 /* Blacklist network. De-prioritizes the given BSSID for connection. */ 420 static final int CMD_BLACKLIST_NETWORK = BASE + 56; 421 /* Clear the blacklist network list */ 422 static final int CMD_CLEAR_BLACKLIST = BASE + 57; 423 /* Save configuration */ 424 static final int CMD_SAVE_CONFIG = BASE + 58; 425 /* Get configured networks */ 426 static final int CMD_GET_CONFIGURED_NETWORKS = BASE + 59; 427 /* Get available frequencies */ 428 static final int CMD_GET_CAPABILITY_FREQ = BASE + 60; 429 /* Get adaptors */ 430 static final int CMD_GET_ADAPTORS = BASE + 61; 431 /* Get configured networks with real preSharedKey */ 432 static final int CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS = BASE + 62; 433 434 /* Supplicant commands after driver start*/ 435 /* Initiate a scan */ 436 static final int CMD_START_SCAN = BASE + 71; 437 /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */ 438 static final int CMD_SET_OPERATIONAL_MODE = BASE + 72; 439 /* Disconnect from a network */ 440 static final int CMD_DISCONNECT = BASE + 73; 441 /* Reconnect to a network */ 442 static final int CMD_RECONNECT = BASE + 74; 443 /* Reassociate to a network */ 444 static final int CMD_REASSOCIATE = BASE + 75; 445 /* Get Connection Statistis */ 446 static final int CMD_GET_CONNECTION_STATISTICS = BASE + 76; 447 448 /* Controls suspend mode optimizations 449 * 450 * When high perf mode is enabled, suspend mode optimizations are disabled 451 * 452 * When high perf mode is disabled, suspend mode optimizations are enabled 453 * 454 * Suspend mode optimizations include: 455 * - packet filtering 456 * - turn off roaming 457 * - DTIM wake up settings 458 */ 459 static final int CMD_SET_HIGH_PERF_MODE = BASE + 77; 460 /* Set the country code */ 461 static final int CMD_SET_COUNTRY_CODE = BASE + 80; 462 /* Enables RSSI poll */ 463 static final int CMD_ENABLE_RSSI_POLL = BASE + 82; 464 /* RSSI poll */ 465 static final int CMD_RSSI_POLL = BASE + 83; 466 /* Set up packet filtering */ 467 static final int CMD_START_PACKET_FILTERING = BASE + 84; 468 /* Clear packet filter */ 469 static final int CMD_STOP_PACKET_FILTERING = BASE + 85; 470 /* Enable suspend mode optimizations in the driver */ 471 static final int CMD_SET_SUSPEND_OPT_ENABLED = BASE + 86; 472 /* Delayed NETWORK_DISCONNECT */ 473 static final int CMD_DELAYED_NETWORK_DISCONNECT = BASE + 87; 474 /* When there are no saved networks, we do a periodic scan to notify user of 475 * an open network */ 476 static final int CMD_NO_NETWORKS_PERIODIC_SCAN = BASE + 88; 477 /* Test network Disconnection NETWORK_DISCONNECT */ 478 static final int CMD_TEST_NETWORK_DISCONNECT = BASE + 89; 479 private int testNetworkDisconnectCounter = 0; 480 481 /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */ 482 static final int MULTICAST_V6 = 1; 483 static final int MULTICAST_V4 = 0; 484 485 /* Set the frequency band */ 486 static final int CMD_SET_FREQUENCY_BAND = BASE + 90; 487 /* Enable background scan for configured networks */ 488 static final int CMD_ENABLE_BACKGROUND_SCAN = BASE + 91; 489 /* Enable TDLS on a specific MAC address */ 490 static final int CMD_ENABLE_TDLS = BASE + 92; 491 /* Enable TDLS on a specific MAC address */ 492 static final int CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER = BASE + 93; 493 494 /** 495 * Make this timer 32 seconds, which is about the normal DHCP timeout. 496 * In no valid case, the WiFiStateMachine should remain stuck in ObtainingIpAddress 497 * for more than 30 seconds. 498 */ 499 static final int OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC = 32000; 500 501 int obtainingIpWatchdogCount = 0; 502 /* Commands from/to the SupplicantStateTracker */ 503 /* Reset the supplicant state tracker */ 504 static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111; 505 506 /* P2p commands */ 507 /* We are ok with no response here since we wont do much with it anyway */ 508 public static final int CMD_ENABLE_P2P = BASE + 131; 509 /* In order to shut down supplicant cleanly, we wait till p2p has 510 * been disabled */ 511 public static final int CMD_DISABLE_P2P_REQ = BASE + 132; 512 public static final int CMD_DISABLE_P2P_RSP = BASE + 133; 513 514 public static final int CMD_BOOT_COMPLETED = BASE + 134; 515 516 /* change the batch scan settings. 517 * arg1 = responsible UID 518 * arg2 = csph (channel scans per hour) 519 * obj = bundle with the new settings and the optional worksource 520 */ 521 public static final int CMD_SET_BATCHED_SCAN = BASE + 135; 522 public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136; 523 public static final int CMD_POLL_BATCHED_SCAN = BASE + 137; 524 525 /* We now have a valid IP configuration. */ 526 static final int CMD_IP_CONFIGURATION_SUCCESSFUL = BASE + 138; 527 /* We no longer have a valid IP configuration. */ 528 static final int CMD_IP_CONFIGURATION_LOST = BASE + 139; 529 /* Link configuration (IP address, DNS, ...) changes notified via netlink */ 530 static final int CMD_UPDATE_LINKPROPERTIES = BASE + 140; 531 532 533 /* Reload all networks and reconnect */ 534 static final int CMD_RELOAD_TLS_AND_RECONNECT = BASE + 142; 535 536 static final int CMD_AUTO_CONNECT = BASE + 143; 537 538 static final int CMD_UNWANTED_NETWORK = BASE + 144; 539 540 static final int CMD_AUTO_ROAM = BASE + 145; 541 542 543 /* Wifi state machine modes of operation */ 544 /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ 545 public static final int CONNECT_MODE = 1; 546 /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */ 547 public static final int SCAN_ONLY_MODE = 2; 548 /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */ 549 public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3; 550 551 private static final int SUCCESS = 1; 552 private static final int FAILURE = -1; 553 554 /* Tracks if suspend optimizations need to be disabled by DHCP, 555 * screen or due to high perf mode. 556 * When any of them needs to disable it, we keep the suspend optimizations 557 * disabled 558 */ 559 private int mSuspendOptNeedsDisabled = 0; 560 561 private static final int SUSPEND_DUE_TO_DHCP = 1; 562 private static final int SUSPEND_DUE_TO_HIGH_PERF = 1<<1; 563 private static final int SUSPEND_DUE_TO_SCREEN = 1<<2; 564 565 /* Tracks if user has enabled suspend optimizations through settings */ 566 private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true); 567 568 /** 569 * Default framework scan interval in milliseconds. This is used in the scenario in which 570 * wifi chipset does not support background scanning to set up a 571 * periodic wake up scan so that the device can connect to a new access 572 * point on the move. {@link Settings.Global#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can 573 * override this. 574 */ 575 private final int mDefaultFrameworkScanIntervalMs; 576 577 /** 578 * Connected state framework scan interval in milliseconds. 579 * This is used for extended roaming, when screen is lit. 580 */ 581 private int mConnectedScanPeriodMs = 10000; 582 private int mDisconnectedScanPeriodMs = 10000; 583 584 /** 585 * Supplicant scan interval in milliseconds. 586 * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or 587 * from the default config if the setting is not set 588 */ 589 private long mSupplicantScanIntervalMs; 590 591 /** 592 * timeStamp of last full band scan we perfoemed for autojoin while connected with screen lit 593 */ 594 private long lastFullBandConnectedTimeMilli; 595 596 /** 597 * time interval to the next full band scan we will perform for 598 * autojoin while connected with screen lit 599 */ 600 private long fullBandConnectedTimeIntervalMilli; 601 602 /** 603 * max time interval to the next full band scan we will perform for 604 * autojoin while connected with screen lit 605 * Max time is 5 minutes 606 */ 607 private static final long maxFullBandConnectedTimeIntervalMilli = 1000 * 60 * 5; 608 609 /** 610 * Minimum time interval between enabling all networks. 611 * A device can end up repeatedly connecting to a bad network on screen on/off toggle 612 * due to enabling every time. We add a threshold to avoid this. 613 */ 614 private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */ 615 private long mLastEnableAllNetworksTime; 616 617 /** 618 * Starting and shutting down driver too quick causes problems leading to driver 619 * being in a bad state. Delay driver stop. 620 */ 621 private final int mDriverStopDelayMs; 622 private int mDelayedStopCounter; 623 private boolean mInDelayedStop = false; 624 625 // sometimes telephony gives us this data before boot is complete and we can't store it 626 // until after, so the write is deferred 627 private volatile String mPersistedCountryCode; 628 629 // Supplicant doesn't like setting the same country code multiple times (it may drop 630 // currently connected network), so we save the country code here to avoid redundency 631 private String mLastSetCountryCode; 632 633 /* Default parent state */ 634 private State mDefaultState = new DefaultState(); 635 /* Temporary initial state */ 636 private State mInitialState = new InitialState(); 637 /* Driver loaded, waiting for supplicant to start */ 638 private State mSupplicantStartingState = new SupplicantStartingState(); 639 /* Driver loaded and supplicant ready */ 640 private State mSupplicantStartedState = new SupplicantStartedState(); 641 /* Waiting for supplicant to stop and monitor to exit */ 642 private State mSupplicantStoppingState = new SupplicantStoppingState(); 643 /* Driver start issued, waiting for completed event */ 644 private State mDriverStartingState = new DriverStartingState(); 645 /* Driver started */ 646 private State mDriverStartedState = new DriverStartedState(); 647 /* Wait until p2p is disabled 648 * This is a special state which is entered right after we exit out of DriverStartedState 649 * before transitioning to another state. 650 */ 651 private State mWaitForP2pDisableState = new WaitForP2pDisableState(); 652 /* Driver stopping */ 653 private State mDriverStoppingState = new DriverStoppingState(); 654 /* Driver stopped */ 655 private State mDriverStoppedState = new DriverStoppedState(); 656 /* Scan for networks, no connection will be established */ 657 private State mScanModeState = new ScanModeState(); 658 /* Connecting to an access point */ 659 private State mConnectModeState = new ConnectModeState(); 660 /* Connected at 802.11 (L2) level */ 661 private State mL2ConnectedState = new L2ConnectedState(); 662 /* fetching IP after connection to access point (assoc+auth complete) */ 663 private State mObtainingIpState = new ObtainingIpState(); 664 /* Waiting for link quality verification to be complete */ 665 private State mVerifyingLinkState = new VerifyingLinkState(); 666 /* Connected with IP addr */ 667 private State mConnectedState = new ConnectedState(); 668 /* Roaming */ 669 private State mRoamingState = new RoamingState(); 670 /* disconnect issued, waiting for network disconnect confirmation */ 671 private State mDisconnectingState = new DisconnectingState(); 672 /* Network is not connected, supplicant assoc+auth is not complete */ 673 private State mDisconnectedState = new DisconnectedState(); 674 /* Waiting for WPS to be completed*/ 675 private State mWpsRunningState = new WpsRunningState(); 676 677 /* Soft ap is starting up */ 678 private State mSoftApStartingState = new SoftApStartingState(); 679 /* Soft ap is running */ 680 private State mSoftApStartedState = new SoftApStartedState(); 681 /* Soft ap is running and we are waiting for tether notification */ 682 private State mTetheringState = new TetheringState(); 683 /* Soft ap is running and we are tethered through connectivity service */ 684 private State mTetheredState = new TetheredState(); 685 /* Waiting for untether confirmation before stopping soft Ap */ 686 private State mUntetheringState = new UntetheringState(); 687 688 private class TetherStateChange { 689 ArrayList<String> available; 690 ArrayList<String> active; 691 TetherStateChange(ArrayList<String> av, ArrayList<String> ac) { 692 available = av; 693 active = ac; 694 } 695 } 696 697 public static class SimAuthRequestData { 698 int networkId; 699 int protocol; 700 String ssid; 701 String[] challenges; 702 } 703 704 public static class SimAuthResponseData { 705 int id; 706 String Kc1; 707 String SRES1; 708 String Kc2; 709 String SRES2; 710 String Kc3; 711 String SRES3; 712 } 713 714 /** 715 * One of {@link WifiManager#WIFI_STATE_DISABLED}, 716 * {@link WifiManager#WIFI_STATE_DISABLING}, 717 * {@link WifiManager#WIFI_STATE_ENABLED}, 718 * {@link WifiManager#WIFI_STATE_ENABLING}, 719 * {@link WifiManager#WIFI_STATE_UNKNOWN} 720 * 721 */ 722 private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED); 723 724 /** 725 * One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 726 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 727 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 728 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 729 * {@link WifiManager#WIFI_AP_STATE_FAILED} 730 * 731 */ 732 private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED); 733 734 private static final int SCAN_REQUEST = 0; 735 private static final String ACTION_START_SCAN = 736 "com.android.server.WifiManager.action.START_SCAN"; 737 738 private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter"; 739 private static final int DRIVER_STOP_REQUEST = 0; 740 private static final String ACTION_DELAYED_DRIVER_STOP = 741 "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP"; 742 743 private static final String ACTION_REFRESH_BATCHED_SCAN = 744 "com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN"; 745 /** 746 * Keep track of whether WIFI is running. 747 */ 748 private boolean mIsRunning = false; 749 750 /** 751 * Keep track of whether we last told the battery stats we had started. 752 */ 753 private boolean mReportedRunning = false; 754 755 /** 756 * Most recently set source of starting WIFI. 757 */ 758 private final WorkSource mRunningWifiUids = new WorkSource(); 759 760 /** 761 * The last reported UIDs that were responsible for starting WIFI. 762 */ 763 private final WorkSource mLastRunningWifiUids = new WorkSource(); 764 765 private final IBatteryStats mBatteryStats; 766 767 private BatchedScanSettings mBatchedScanSettings = null; 768 769 /** 770 * Track the worksource/cost of the current settings and track what's been noted 771 * to the battery stats, so we can mark the end of the previous when changing. 772 */ 773 private WorkSource mBatchedScanWorkSource = null; 774 private int mBatchedScanCsph = 0; 775 private WorkSource mNotedBatchedScanWorkSource = null; 776 private int mNotedBatchedScanCsph = 0; 777 778 private AtomicBoolean mFrameworkAutoJoin = new AtomicBoolean(true); //enable by default 779 780 public WifiStateMachine(Context context, String wlanInterface, 781 WifiTrafficPoller trafficPoller){ 782 super("WifiStateMachine"); 783 mContext = context; 784 mInterfaceName = wlanInterface; 785 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); 786 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 787 BatteryStats.SERVICE_NAME)); 788 789 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 790 mNwService = INetworkManagementService.Stub.asInterface(b); 791 792 mP2pSupported = mContext.getPackageManager().hasSystemFeature( 793 PackageManager.FEATURE_WIFI_DIRECT); 794 795 mWifiNative = new WifiNative(mInterfaceName); 796 mWifiConfigStore = new WifiConfigStore(context, mWifiNative); 797 mWifiAutoJoinController = new WifiAutoJoinController(context, this, 798 mWifiConfigStore, mWifiConnectionStatistics, mWifiNative); 799 mWifiMonitor = new WifiMonitor(this, mWifiNative); 800 mWifiInfo = new WifiInfo(); 801 mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, 802 getHandler()); 803 mLinkProperties = new LinkProperties(); 804 805 IBinder s1 = ServiceManager.getService(Context.WIFI_P2P_SERVICE); 806 mWifiP2pServiceImpl = (WifiP2pServiceImpl)IWifiP2pManager.Stub.asInterface(s1); 807 808 IBinder s2 = ServiceManager.getService(Context.WIFI_PASSPOINT_SERVICE); 809 mPasspointServiceImpl = 810 (WifiPasspointServiceImpl)IWifiPasspointManager.Stub.asInterface(s2); 811 812 mNetworkInfo.setIsAvailable(false); 813 mLastBssid = null; 814 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 815 mLastSignalLevel = -1; 816 817 mNetlinkTracker = new NetlinkTracker(mInterfaceName, new NetlinkTracker.Callback() { 818 public void update() { 819 sendMessage(CMD_UPDATE_LINKPROPERTIES); 820 } 821 }); 822 try { 823 mNwService.registerObserver(mNetlinkTracker); 824 } catch (RemoteException e) { 825 loge("Couldn't register netlink tracker: " + e.toString()); 826 } 827 828 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 829 Intent scanIntent = new Intent(ACTION_START_SCAN, null); 830 mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0); 831 832 Intent batchedIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null); 833 mBatchedScanIntervalIntent = PendingIntent.getBroadcast(mContext, 0, batchedIntent, 0); 834 835 mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger( 836 R.integer.config_wifi_framework_scan_interval); 837 838 mDriverStopDelayMs = mContext.getResources().getInteger( 839 R.integer.config_wifi_driver_stop_delay); 840 841 mBackgroundScanSupported = mContext.getResources().getBoolean( 842 R.bool.config_wifi_background_scan_support); 843 844 mPrimaryDeviceType = mContext.getResources().getString( 845 R.string.config_wifi_p2p_device_type); 846 847 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 848 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 849 850 mFrameworkAutoJoin.set(Settings.Global.getInt(mContext.getContentResolver(), 851 Settings.Global.WIFI_ENHANCED_AUTO_JOIN, 1) == 1); 852 853 mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); 854 mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 855 mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 856 mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024); 857 mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024); 858 // TODO - needs to be a bit more dynamic 859 mNetworkCapabilities = new NetworkCapabilities(mNetworkCapabilitiesFilter); 860 861 mContext.registerReceiver( 862 new BroadcastReceiver() { 863 @Override 864 public void onReceive(Context context, Intent intent) { 865 ArrayList<String> available = intent.getStringArrayListExtra( 866 ConnectivityManager.EXTRA_AVAILABLE_TETHER); 867 ArrayList<String> active = intent.getStringArrayListExtra( 868 ConnectivityManager.EXTRA_ACTIVE_TETHER); 869 sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active)); 870 } 871 },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); 872 873 mContext.registerReceiver( 874 new BroadcastReceiver() { 875 @Override 876 public void onReceive(Context context, Intent intent) { 877 startScan(SCAN_ALARM_SOURCE, null, null); 878 if (VDBG) 879 loge("WiFiStateMachine SCAN ALARM"); 880 } 881 }, 882 new IntentFilter(ACTION_START_SCAN)); 883 884 IntentFilter filter = new IntentFilter(); 885 filter.addAction(Intent.ACTION_SCREEN_ON); 886 filter.addAction(Intent.ACTION_SCREEN_OFF); 887 filter.addAction(ACTION_REFRESH_BATCHED_SCAN); 888 mContext.registerReceiver( 889 new BroadcastReceiver() { 890 @Override 891 public void onReceive(Context context, Intent intent) { 892 String action = intent.getAction(); 893 894 if (action.equals(Intent.ACTION_SCREEN_ON)) { 895 handleScreenStateChanged(true); 896 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 897 handleScreenStateChanged(false); 898 } else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) { 899 startNextBatchedScanAsync(); 900 } 901 } 902 }, filter); 903 904 mContext.registerReceiver( 905 new BroadcastReceiver() { 906 @Override 907 public void onReceive(Context context, Intent intent) { 908 int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0); 909 sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0); 910 } 911 }, 912 new IntentFilter(ACTION_DELAYED_DRIVER_STOP)); 913 914 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 915 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false, 916 new ContentObserver(getHandler()) { 917 @Override 918 public void onChange(boolean selfChange) { 919 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 920 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 921 } 922 }); 923 924 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 925 Settings.Global.WIFI_ENHANCED_AUTO_JOIN), false, 926 new ContentObserver(getHandler()) { 927 @Override 928 public void onChange(boolean selfChange) { 929 mFrameworkAutoJoin.set(Settings.Global.getInt(mContext.getContentResolver(), 930 Settings.Global.WIFI_ENHANCED_AUTO_JOIN, 0) == 1); 931 } 932 }); 933 934 mContext.registerReceiver( 935 new BroadcastReceiver() { 936 @Override 937 public void onReceive(Context context, Intent intent) { 938 sendMessage(CMD_BOOT_COMPLETED); 939 } 940 }, 941 new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); 942 943 mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE); 944 945 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 946 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName()); 947 948 mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend"); 949 mSuspendWakeLock.setReferenceCounted(false); 950 951 addState(mDefaultState); 952 addState(mInitialState, mDefaultState); 953 addState(mSupplicantStartingState, mDefaultState); 954 addState(mSupplicantStartedState, mDefaultState); 955 addState(mDriverStartingState, mSupplicantStartedState); 956 addState(mDriverStartedState, mSupplicantStartedState); 957 addState(mScanModeState, mDriverStartedState); 958 addState(mConnectModeState, mDriverStartedState); 959 addState(mL2ConnectedState, mConnectModeState); 960 addState(mObtainingIpState, mL2ConnectedState); 961 addState(mVerifyingLinkState, mL2ConnectedState); 962 addState(mConnectedState, mL2ConnectedState); 963 addState(mRoamingState, mL2ConnectedState); 964 addState(mDisconnectingState, mConnectModeState); 965 addState(mDisconnectedState, mConnectModeState); 966 addState(mWpsRunningState, mConnectModeState); 967 addState(mWaitForP2pDisableState, mSupplicantStartedState); 968 addState(mDriverStoppingState, mSupplicantStartedState); 969 addState(mDriverStoppedState, mSupplicantStartedState); 970 addState(mSupplicantStoppingState, mDefaultState); 971 addState(mSoftApStartingState, mDefaultState); 972 addState(mSoftApStartedState, mDefaultState); 973 addState(mTetheringState, mSoftApStartedState); 974 addState(mTetheredState, mSoftApStartedState); 975 addState(mUntetheringState, mSoftApStartedState); 976 977 setInitialState(mInitialState); 978 979 setLogRecSize(5000); 980 setLogOnlyTransitions(false); 981 if (VDBG) setDbg(true); 982 983 //start the state machine 984 start(); 985 986 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 987 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 988 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 989 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 990 } 991 992 private int mVerboseLoggingLevel = 0; 993 994 int getVerboseLoggingLevel() { 995 return mVerboseLoggingLevel; 996 } 997 998 void enableVerboseLogging(int verbose) { 999 mVerboseLoggingLevel = verbose; 1000 if (verbose > 0) { 1001 DBG = true; 1002 VDBG = true; 1003 PDBG = true; 1004 mLogMessages = true; 1005 mWifiNative.setSupplicantLogLevel("DEBUG"); 1006 } else { 1007 DBG = false; 1008 VDBG = false; 1009 PDBG = false; 1010 mLogMessages = false; 1011 mWifiNative.setSupplicantLogLevel("INFO"); 1012 } 1013 mWifiAutoJoinController.enableVerboseLogging(verbose); 1014 mWifiMonitor.enableVerboseLogging(verbose); 1015 mWifiNative.enableVerboseLogging(verbose); 1016 mWifiConfigStore.enableVerboseLogging(verbose); 1017 mSupplicantStateTracker.enableVerboseLogging(verbose); 1018 } 1019 1020 private int mAggressiveHandover = 0; 1021 1022 int getAggressiveHandover() { 1023 return mAggressiveHandover; 1024 } 1025 1026 void enableAggressiveHandover(int enabled) { 1027 mAggressiveHandover = enabled; 1028 } 1029 1030 private int mAllowScansWithTraffic = 0; 1031 1032 public void setAllowScansWithTraffic(int enabled) { 1033 mAllowScansWithTraffic = enabled; 1034 } 1035 1036 public int getAllowScansWithTraffic() { 1037 return mAllowScansWithTraffic; 1038 } 1039 1040 /* 1041 * 1042 * Framework scan control 1043 */ 1044 1045 private boolean mAlarmEnabled = false; 1046 /* This is set from the overlay config file or from a secure setting. 1047 * A value of 0 disables scanning in the framework. 1048 */ 1049 private long mFrameworkScanIntervalMs = 10000; 1050 1051 private long mCurrentScanAlarmMs = 10000; 1052 private void setScanAlarm(boolean enabled) { 1053 if (PDBG) { 1054 loge("setScanAlarm " + enabled + " period " + mCurrentScanAlarmMs); 1055 } 1056 if (mCurrentScanAlarmMs <= 0) enabled = false; 1057 if (enabled == mAlarmEnabled) return; 1058 if (enabled) { 1059 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 1060 System.currentTimeMillis() + mCurrentScanAlarmMs, 1061 mCurrentScanAlarmMs, 1062 mScanIntent); 1063 mAlarmEnabled = true; 1064 } else { 1065 mAlarmManager.cancel(mScanIntent); 1066 mAlarmEnabled = false; 1067 } 1068 } 1069 1070 /********************************************************* 1071 * Methods exposed for public use 1072 ********************************************************/ 1073 1074 public Messenger getMessenger() { 1075 return new Messenger(getHandler()); 1076 } 1077 1078 public WifiMonitor getWifiMonitor() { 1079 return mWifiMonitor; 1080 } 1081 1082 /** 1083 * TODO: doc 1084 */ 1085 public boolean syncPingSupplicant(AsyncChannel channel) { 1086 Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT); 1087 boolean result = (resultMsg.arg1 != FAILURE); 1088 resultMsg.recycle(); 1089 return result; 1090 } 1091 1092 public List<WifiChannel> syncGetChannelList(AsyncChannel channel) { 1093 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CAPABILITY_FREQ); 1094 List<WifiChannel> list = null; 1095 if (resultMsg.obj != null) { 1096 list = new ArrayList<WifiChannel>(); 1097 String freqs = (String) resultMsg.obj; 1098 String[] lines = freqs.split("\n"); 1099 for (String line : lines) 1100 if (line.contains("MHz")) { 1101 // line format: " 52 = 5260 MHz (NO_IBSS) (DFS)" 1102 WifiChannel c = new WifiChannel(); 1103 String[] prop = line.split(" "); 1104 if (prop.length < 5) continue; 1105 try { 1106 c.channelNum = Integer.parseInt(prop[1]); 1107 c.freqMHz = Integer.parseInt(prop[3]); 1108 } catch (NumberFormatException e) { } 1109 c.isDFS = line.contains("(DFS)"); 1110 list.add(c); 1111 } else if (line.contains("Mode[B] Channels:")) { 1112 // B channels are the same as G channels, skipped 1113 break; 1114 } 1115 } 1116 resultMsg.recycle(); 1117 return (list != null && list.size() > 0) ? list : null; 1118 } 1119 1120 1121 /** 1122 * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is 1123 * given to callingUid. 1124 * 1125 * @param callingUid The uid initiating the wifi scan. Blame will be given here unless 1126 * workSource is specified. 1127 * @param workSource If not null, blame is given to workSource. 1128 * @param settings Scan settings, see {@link ScanSettings}. 1129 */ 1130 public void startScan(int callingUid, ScanSettings settings, WorkSource workSource) { 1131 Bundle bundle = new Bundle(); 1132 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings); 1133 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1134 sendMessage(CMD_START_SCAN, callingUid, 0, bundle); 1135 } 1136 1137 /** 1138 * start or stop batched scanning using the given settings 1139 */ 1140 public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph, 1141 WorkSource workSource) { 1142 Bundle bundle = new Bundle(); 1143 bundle.putParcelable(BATCHED_SETTING, settings); 1144 bundle.putParcelable(BATCHED_WORKSOURCE, workSource); 1145 sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle); 1146 } 1147 1148 public List<BatchedScanResult> syncGetBatchedScanResultsList() { 1149 synchronized (mBatchedScanResults) { 1150 List<BatchedScanResult> batchedScanList = 1151 new ArrayList<BatchedScanResult>(mBatchedScanResults.size()); 1152 for(BatchedScanResult result: mBatchedScanResults) { 1153 batchedScanList.add(new BatchedScanResult(result)); 1154 } 1155 return batchedScanList; 1156 } 1157 } 1158 1159 public void requestBatchedScanPoll() { 1160 sendMessage(CMD_POLL_BATCHED_SCAN); 1161 } 1162 1163 private void startBatchedScan() { 1164 if (mBatchedScanSettings == null) return; 1165 1166 if (mDhcpActive) { 1167 if (DBG) log("not starting Batched Scans due to DHCP"); 1168 return; 1169 } 1170 1171 // first grab any existing data 1172 retrieveBatchedScanData(); 1173 1174 if (PDBG) loge("try starting Batched Scans due to DHCP"); 1175 1176 1177 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1178 1179 String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings); 1180 try { 1181 mExpectedBatchedScans = Integer.parseInt(scansExpected); 1182 setNextBatchedAlarm(mExpectedBatchedScans); 1183 if (mExpectedBatchedScans > 0) noteBatchedScanStart(); 1184 } catch (NumberFormatException e) { 1185 stopBatchedScan(); 1186 loge("Exception parsing WifiNative.setBatchedScanSettings response " + e); 1187 } 1188 } 1189 1190 // called from BroadcastListener 1191 private void startNextBatchedScanAsync() { 1192 sendMessage(CMD_START_NEXT_BATCHED_SCAN); 1193 } 1194 1195 private void startNextBatchedScan() { 1196 // first grab any existing data 1197 retrieveBatchedScanData(); 1198 1199 setNextBatchedAlarm(mExpectedBatchedScans); 1200 } 1201 1202 private void handleBatchedScanPollRequest() { 1203 if (DBG) { 1204 log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" + 1205 mBatchedScanMinPollTime + " , mBatchedScanSettings=" + 1206 mBatchedScanSettings); 1207 } 1208 // if there is no appropriate PollTime that's because we either aren't 1209 // batching or we've already set a time for a poll request 1210 if (mBatchedScanMinPollTime == 0) return; 1211 if (mBatchedScanSettings == null) return; 1212 1213 long now = System.currentTimeMillis(); 1214 1215 if (now > mBatchedScanMinPollTime) { 1216 // do the poll and reset our timers 1217 startNextBatchedScan(); 1218 } else { 1219 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime, 1220 mBatchedScanIntervalIntent); 1221 mBatchedScanMinPollTime = 0; 1222 } 1223 } 1224 1225 // return true if new/different 1226 private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) { 1227 BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING); 1228 WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE); 1229 1230 if (DBG) { 1231 log("set batched scan to " + settings + " for uid=" + responsibleUid + 1232 ", worksource=" + responsibleWorkSource); 1233 } 1234 if (settings != null) { 1235 if (settings.equals(mBatchedScanSettings)) return false; 1236 } else { 1237 if (mBatchedScanSettings == null) return false; 1238 } 1239 mBatchedScanSettings = settings; 1240 if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid); 1241 mBatchedScanWorkSource = responsibleWorkSource; 1242 mBatchedScanCsph = csph; 1243 return true; 1244 } 1245 1246 private void stopBatchedScan() { 1247 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1248 retrieveBatchedScanData(); 1249 mWifiNative.setBatchedScanSettings(null); 1250 noteBatchedScanStop(); 1251 } 1252 1253 private void setNextBatchedAlarm(int scansExpected) { 1254 1255 if (mBatchedScanSettings == null || scansExpected < 1) return; 1256 1257 mBatchedScanMinPollTime = System.currentTimeMillis() + 1258 mBatchedScanSettings.scanIntervalSec * 1000; 1259 1260 if (mBatchedScanSettings.maxScansPerBatch < scansExpected) { 1261 scansExpected = mBatchedScanSettings.maxScansPerBatch; 1262 } 1263 1264 int secToFull = mBatchedScanSettings.scanIntervalSec; 1265 secToFull *= scansExpected; 1266 1267 int debugPeriod = SystemProperties.getInt("wifi.batchedScan.pollPeriod", 0); 1268 if (debugPeriod > 0) secToFull = debugPeriod; 1269 1270 // set the alarm to do the next poll. We set it a little short as we'd rather 1271 // wake up wearly than miss a scan due to buffer overflow 1272 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 1273 + ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000), 1274 mBatchedScanIntervalIntent); 1275 } 1276 1277 /** 1278 * Start reading new scan data 1279 * Data comes in as: 1280 * "scancount=5\n" 1281 * "nextcount=5\n" 1282 * "apcount=3\n" 1283 * "trunc\n" (optional) 1284 * "bssid=...\n" 1285 * "ssid=...\n" 1286 * "freq=...\n" (in Mhz) 1287 * "level=...\n" 1288 * "dist=...\n" (in cm) 1289 * "distsd=...\n" (standard deviation, in cm) 1290 * "====" 1291 * "bssid=...\n" 1292 * etc 1293 * "====" 1294 * "bssid=...\n" 1295 * etc 1296 * "%%%%" 1297 * "apcount=2\n" 1298 * "bssid=...\n" 1299 * etc 1300 * "%%%% 1301 * etc 1302 * "----" 1303 */ 1304 private final static boolean DEBUG_PARSE = false; 1305 private void retrieveBatchedScanData() { 1306 String rawData = mWifiNative.getBatchedScanResults(); 1307 if (DEBUG_PARSE) log("rawData = " + rawData); 1308 mBatchedScanMinPollTime = 0; 1309 if (rawData == null || rawData.equalsIgnoreCase("OK")) { 1310 loge("Unexpected BatchedScanResults :" + rawData); 1311 return; 1312 } 1313 1314 int scanCount = 0; 1315 final String END_OF_BATCHES = "----"; 1316 final String SCANCOUNT = "scancount="; 1317 final String TRUNCATED = "trunc"; 1318 final String AGE = "age="; 1319 final String DIST = "dist="; 1320 final String DISTSD = "distSd="; 1321 1322 String splitData[] = rawData.split("\n"); 1323 int n = 0; 1324 if (splitData[n].startsWith(SCANCOUNT)) { 1325 try { 1326 scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length())); 1327 } catch (NumberFormatException e) { 1328 loge("scancount parseInt Exception from " + splitData[n]); 1329 } 1330 } else log("scancount not found"); 1331 if (scanCount == 0) { 1332 loge("scanCount==0 - aborting"); 1333 return; 1334 } 1335 1336 final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION); 1337 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1338 1339 synchronized (mBatchedScanResults) { 1340 mBatchedScanResults.clear(); 1341 BatchedScanResult batchedScanResult = new BatchedScanResult(); 1342 1343 String bssid = null; 1344 WifiSsid wifiSsid = null; 1345 int level = 0; 1346 int freq = 0; 1347 int dist, distSd; 1348 long tsf = 0; 1349 dist = distSd = ScanResult.UNSPECIFIED; 1350 final long now = SystemClock.elapsedRealtime(); 1351 final int bssidStrLen = BSSID_STR.length(); 1352 1353 while (true) { 1354 while (n < splitData.length) { 1355 if (DEBUG_PARSE) logd("parsing " + splitData[n]); 1356 if (splitData[n].equals(END_OF_BATCHES)) { 1357 if (n+1 != splitData.length) { 1358 loge("didn't consume " + (splitData.length-n)); 1359 } 1360 if (mBatchedScanResults.size() > 0) { 1361 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1362 } 1363 logd("retrieveBatchedScanResults X"); 1364 return; 1365 } 1366 if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) { 1367 if (bssid != null) { 1368 batchedScanResult.scanResults.add(new ScanResult( 1369 wifiSsid, bssid, "", level, freq, tsf, dist, distSd)); 1370 wifiSsid = null; 1371 bssid = null; 1372 level = 0; 1373 freq = 0; 1374 tsf = 0; 1375 dist = distSd = ScanResult.UNSPECIFIED; 1376 } 1377 if (splitData[n].equals(END_STR)) { 1378 if (batchedScanResult.scanResults.size() != 0) { 1379 mBatchedScanResults.add(batchedScanResult); 1380 batchedScanResult = new BatchedScanResult(); 1381 } else { 1382 logd("Found empty batch"); 1383 } 1384 } 1385 } else if (splitData[n].equals(TRUNCATED)) { 1386 batchedScanResult.truncated = true; 1387 } else if (splitData[n].startsWith(BSSID_STR)) { 1388 bssid = new String(splitData[n].getBytes(), bssidStrLen, 1389 splitData[n].length() - bssidStrLen); 1390 } else if (splitData[n].startsWith(FREQ_STR)) { 1391 try { 1392 freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length())); 1393 } catch (NumberFormatException e) { 1394 loge("Invalid freqency: " + splitData[n]); 1395 freq = 0; 1396 } 1397 } else if (splitData[n].startsWith(AGE)) { 1398 try { 1399 tsf = now - Long.parseLong(splitData[n].substring(AGE.length())); 1400 tsf *= 1000; // convert mS -> uS 1401 } catch (NumberFormatException e) { 1402 loge("Invalid timestamp: " + splitData[n]); 1403 tsf = 0; 1404 } 1405 } else if (splitData[n].startsWith(SSID_STR)) { 1406 wifiSsid = WifiSsid.createFromAsciiEncoded( 1407 splitData[n].substring(SSID_STR.length())); 1408 } else if (splitData[n].startsWith(LEVEL_STR)) { 1409 try { 1410 level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length())); 1411 if (level > 0) level -= 256; 1412 } catch (NumberFormatException e) { 1413 loge("Invalid level: " + splitData[n]); 1414 level = 0; 1415 } 1416 } else if (splitData[n].startsWith(DIST)) { 1417 try { 1418 dist = Integer.parseInt(splitData[n].substring(DIST.length())); 1419 } catch (NumberFormatException e) { 1420 loge("Invalid distance: " + splitData[n]); 1421 dist = ScanResult.UNSPECIFIED; 1422 } 1423 } else if (splitData[n].startsWith(DISTSD)) { 1424 try { 1425 distSd = Integer.parseInt(splitData[n].substring(DISTSD.length())); 1426 } catch (NumberFormatException e) { 1427 loge("Invalid distanceSd: " + splitData[n]); 1428 distSd = ScanResult.UNSPECIFIED; 1429 } 1430 } else { 1431 loge("Unable to parse batched scan result line: " + splitData[n]); 1432 } 1433 n++; 1434 } 1435 rawData = mWifiNative.getBatchedScanResults(); 1436 if (DEBUG_PARSE) log("reading more data:\n" + rawData); 1437 if (rawData == null) { 1438 loge("Unexpected null BatchedScanResults"); 1439 return; 1440 } 1441 splitData = rawData.split("\n"); 1442 if (splitData.length == 0 || splitData[0].equals("ok")) { 1443 loge("batch scan results just ended!"); 1444 if (mBatchedScanResults.size() > 0) { 1445 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1446 } 1447 return; 1448 } 1449 n = 0; 1450 } 1451 } 1452 } 1453 1454 //keeping track of scan requests 1455 private long lastStartScanTimeStamp = 0; 1456 private long lastScanDuration = 0; 1457 //last connect attempt is used to prevent scan requests: 1458 // - for a period of 10 seconds after attempting to connect 1459 private long lastConnectAttempt = 0; 1460 private String lastScanFreqs = null; 1461 1462 //TODO: this is used only to track connection attempts, however the link state and packet per 1463 //TODO: second logic should be folded into that 1464 private boolean isScanAllowed() { 1465 long now = System.currentTimeMillis(); 1466 if (lastConnectAttempt != 0 && (now - lastConnectAttempt) < 10000) { 1467 return false; 1468 } 1469 return true; 1470 } 1471 1472 // If workSource is not null, blame is given to it, otherwise blame is given to callingUid. 1473 private void noteScanStart(int callingUid, WorkSource workSource) { 1474 long now = System.currentTimeMillis(); 1475 lastStartScanTimeStamp = now; 1476 lastScanDuration = 0; 1477 if (DBG) { 1478 String ts = String.format("[%,d ms]", now); 1479 if (workSource != null) { 1480 loge(ts + " noteScanStart" + workSource.toString() 1481 + " uid " + Integer.toString(callingUid)); 1482 } else { 1483 loge(ts + " noteScanstart no scan source"); 1484 } 1485 } 1486 if (mScanWorkSource == null && ((callingUid != UNKNOWN_SCAN_SOURCE 1487 && callingUid != SCAN_ALARM_SOURCE) 1488 || workSource != null)) { 1489 mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid); 1490 try { 1491 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource); 1492 } catch (RemoteException e) { 1493 log(e.toString()); 1494 } 1495 } 1496 } 1497 1498 private void noteScanEnd() { 1499 long now = System.currentTimeMillis(); 1500 if (lastStartScanTimeStamp != 0) { 1501 lastScanDuration = now - lastStartScanTimeStamp; 1502 } 1503 lastStartScanTimeStamp = 0; 1504 if (DBG) { 1505 String ts = String.format("[%,d ms]", now); 1506 1507 if (mScanWorkSource != null) 1508 loge(ts + " noteScanEnd " + mScanWorkSource.toString()); 1509 else 1510 loge(ts + " noteScanEnd no scan source"); 1511 } 1512 if (mScanWorkSource != null) { 1513 try { 1514 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource); 1515 } catch (RemoteException e) { 1516 log(e.toString()); 1517 } finally { 1518 mScanWorkSource = null; 1519 } 1520 } 1521 } 1522 1523 private void noteBatchedScanStart() { 1524 if (PDBG) loge("noteBatchedScanstart()"); 1525 // note the end of a previous scan set 1526 if (mNotedBatchedScanWorkSource != null && 1527 (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false || 1528 mNotedBatchedScanCsph != mBatchedScanCsph)) { 1529 try { 1530 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1531 } catch (RemoteException e) { 1532 log(e.toString()); 1533 } finally { 1534 mNotedBatchedScanWorkSource = null; 1535 mNotedBatchedScanCsph = 0; 1536 } 1537 } 1538 // note the start of the new 1539 try { 1540 mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource, 1541 mBatchedScanCsph); 1542 mNotedBatchedScanWorkSource = mBatchedScanWorkSource; 1543 mNotedBatchedScanCsph = mBatchedScanCsph; 1544 } catch (RemoteException e) { 1545 log(e.toString()); 1546 } 1547 } 1548 1549 private void noteBatchedScanStop() { 1550 if (PDBG) loge("noteBatchedScanstop()"); 1551 1552 if (mNotedBatchedScanWorkSource != null) { 1553 try { 1554 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1555 } catch (RemoteException e) { 1556 log(e.toString()); 1557 } finally { 1558 mNotedBatchedScanWorkSource = null; 1559 mNotedBatchedScanCsph = 0; 1560 } 1561 } 1562 } 1563 1564 private void handleScanRequest(int type, Message message) { 1565 // unbundle parameters 1566 Bundle bundle = (Bundle) message.obj; 1567 ScanSettings settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING); 1568 WorkSource workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE); 1569 1570 // parse scan settings 1571 String freqs = null; 1572 if (settings != null && settings.channelSet != null) { 1573 StringBuilder sb = new StringBuilder(); 1574 boolean first = true; 1575 for (WifiChannel channel : settings.channelSet) { 1576 if (!first) sb.append(','); else first = false; 1577 sb.append(channel.freqMHz); 1578 } 1579 freqs = sb.toString(); 1580 } 1581 1582 // call wifi native to start the scan 1583 if (startScanNative(type, freqs)) { 1584 // only count battery consumption if scan request is accepted 1585 noteScanStart(message.arg1, workSource); 1586 // a full scan covers everything, clearing scan request buffer 1587 if (freqs == null) 1588 mBufferedScanMsg.clear(); 1589 return; 1590 } 1591 1592 // if reach here, scan request is rejected 1593 1594 if (!mIsScanOngoing) { 1595 // if rejection is NOT due to ongoing scan (e.g. bad scan parameters), 1596 // discard this request and pop up the next one 1597 if (mBufferedScanMsg.size() > 0) 1598 sendMessage(mBufferedScanMsg.remove()); 1599 } else if (!mIsFullScanOngoing) { 1600 // if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan, 1601 // buffer the scan request to make sure specified channels will be scanned eventually 1602 if (freqs == null) 1603 mBufferedScanMsg.clear(); 1604 if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) { 1605 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, 0, bundle); 1606 mBufferedScanMsg.add(msg); 1607 } else { 1608 // if too many requests in buffer, combine them into a single full scan 1609 bundle = new Bundle(); 1610 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null); 1611 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1612 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, 0, bundle); 1613 mBufferedScanMsg.clear(); 1614 mBufferedScanMsg.add(msg); 1615 } 1616 } 1617 } 1618 1619 1620 /** return true iff scan request is accepted */ 1621 private boolean startScanNative(int type, String freqs) { 1622 if (mWifiNative.scan(type, freqs)) { 1623 mIsScanOngoing = true; 1624 mIsFullScanOngoing = (freqs == null); 1625 lastScanFreqs = freqs; 1626 return true; 1627 } 1628 return false; 1629 } 1630 1631 /** 1632 * TODO: doc 1633 */ 1634 public void setSupplicantRunning(boolean enable) { 1635 if (enable) { 1636 sendMessage(CMD_START_SUPPLICANT); 1637 } else { 1638 sendMessage(CMD_STOP_SUPPLICANT); 1639 } 1640 } 1641 1642 /** 1643 * TODO: doc 1644 */ 1645 public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) { 1646 if (enable) { 1647 sendMessage(CMD_START_AP, wifiConfig); 1648 } else { 1649 sendMessage(CMD_STOP_AP); 1650 } 1651 } 1652 1653 public void setWifiApConfiguration(WifiConfiguration config) { 1654 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 1655 } 1656 1657 public WifiConfiguration syncGetWifiApConfiguration() { 1658 Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG); 1659 WifiConfiguration ret = (WifiConfiguration) resultMsg.obj; 1660 resultMsg.recycle(); 1661 return ret; 1662 } 1663 1664 /** 1665 * TODO: doc 1666 */ 1667 public int syncGetWifiState() { 1668 return mWifiState.get(); 1669 } 1670 1671 /** 1672 * TODO: doc 1673 */ 1674 public String syncGetWifiStateByName() { 1675 switch (mWifiState.get()) { 1676 case WIFI_STATE_DISABLING: 1677 return "disabling"; 1678 case WIFI_STATE_DISABLED: 1679 return "disabled"; 1680 case WIFI_STATE_ENABLING: 1681 return "enabling"; 1682 case WIFI_STATE_ENABLED: 1683 return "enabled"; 1684 case WIFI_STATE_UNKNOWN: 1685 return "unknown state"; 1686 default: 1687 return "[invalid state]"; 1688 } 1689 } 1690 1691 /** 1692 * TODO: doc 1693 */ 1694 public int syncGetWifiApState() { 1695 return mWifiApState.get(); 1696 } 1697 1698 /** 1699 * TODO: doc 1700 */ 1701 public String syncGetWifiApStateByName() { 1702 switch (mWifiApState.get()) { 1703 case WIFI_AP_STATE_DISABLING: 1704 return "disabling"; 1705 case WIFI_AP_STATE_DISABLED: 1706 return "disabled"; 1707 case WIFI_AP_STATE_ENABLING: 1708 return "enabling"; 1709 case WIFI_AP_STATE_ENABLED: 1710 return "enabled"; 1711 case WIFI_AP_STATE_FAILED: 1712 return "failed"; 1713 default: 1714 return "[invalid state]"; 1715 } 1716 } 1717 1718 /** 1719 * Get status information for the current connection, if any. 1720 * @return a {@link WifiInfo} object containing information about the current connection 1721 * 1722 */ 1723 public WifiInfo syncRequestConnectionInfo() { 1724 return mWifiInfo; 1725 } 1726 1727 public DhcpResults syncGetDhcpResults() { 1728 synchronized (mDhcpResultsLock) { 1729 return new DhcpResults(mDhcpResults); 1730 } 1731 } 1732 1733 /** 1734 * TODO: doc 1735 */ 1736 public void setDriverStart(boolean enable) { 1737 if (enable) { 1738 sendMessage(CMD_START_DRIVER); 1739 } else { 1740 sendMessage(CMD_STOP_DRIVER); 1741 } 1742 } 1743 1744 /** 1745 * TODO: doc 1746 */ 1747 public void setOperationalMode(int mode) { 1748 if (DBG) log("setting operational mode to " + String.valueOf(mode)); 1749 sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0); 1750 } 1751 1752 /** 1753 * TODO: doc 1754 */ 1755 public List<ScanResult> syncGetScanResultsList() { 1756 synchronized (mScanResultCache) { 1757 List<ScanResult> scanList = new ArrayList<ScanResult>(); 1758 for(ScanResult result: mScanResults) { 1759 scanList.add(new ScanResult(result)); 1760 } 1761 return scanList; 1762 } 1763 } 1764 1765 /** 1766 * Disconnect from Access Point 1767 */ 1768 public void disconnectCommand() { 1769 sendMessage(CMD_DISCONNECT); 1770 } 1771 1772 /** 1773 * Initiate a reconnection to AP 1774 */ 1775 public void reconnectCommand() { 1776 sendMessage(CMD_RECONNECT); 1777 } 1778 1779 /** 1780 * Initiate a re-association to AP 1781 */ 1782 public void reassociateCommand() { 1783 sendMessage(CMD_REASSOCIATE); 1784 } 1785 1786 /** 1787 * Reload networks and then reconnect; helps load correct data for TLS networks 1788 */ 1789 1790 public void reloadTlsNetworksAndReconnect() { 1791 sendMessage(CMD_RELOAD_TLS_AND_RECONNECT); 1792 } 1793 1794 /** 1795 * Add a network synchronously 1796 * 1797 * @return network id of the new network 1798 */ 1799 public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) { 1800 Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config); 1801 int result = resultMsg.arg1; 1802 resultMsg.recycle(); 1803 return result; 1804 } 1805 1806 /** 1807 * Get configured networks synchronously 1808 * @param channel 1809 * @return 1810 */ 1811 1812 public List<WifiConfiguration> syncGetConfiguredNetworks(AsyncChannel channel) { 1813 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS); 1814 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 1815 resultMsg.recycle(); 1816 return result; 1817 } 1818 1819 public List<WifiConfiguration> syncGetPrivilegedConfiguredNetwork(AsyncChannel channel) { 1820 Message resultMsg = channel.sendMessageSynchronously( 1821 CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS); 1822 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 1823 resultMsg.recycle(); 1824 return result; 1825 } 1826 1827 1828 /** 1829 * Get connection statistics synchronously 1830 * @param channel 1831 * @return 1832 */ 1833 1834 public WifiConnectionStatistics syncGetConnectionStatistics(AsyncChannel channel) { 1835 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONNECTION_STATISTICS); 1836 WifiConnectionStatistics result = (WifiConnectionStatistics) resultMsg.obj; 1837 resultMsg.recycle(); 1838 return result; 1839 } 1840 1841 /** 1842 * Get adaptors synchronously 1843 */ 1844 1845 public List<WifiAdapter> syncGetAdaptors(AsyncChannel channel) { 1846 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_ADAPTORS); 1847 List<WifiAdapter> result = (List<WifiAdapter>) resultMsg.obj; 1848 resultMsg.recycle(); 1849 return result; 1850 } 1851 1852 /** 1853 * Delete a network 1854 * 1855 * @param networkId id of the network to be removed 1856 */ 1857 public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) { 1858 Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId); 1859 boolean result = (resultMsg.arg1 != FAILURE); 1860 resultMsg.recycle(); 1861 return result; 1862 } 1863 1864 /** 1865 * Enable a network 1866 * 1867 * @param netId network id of the network 1868 * @param disableOthers true, if all other networks have to be disabled 1869 * @return {@code true} if the operation succeeds, {@code false} otherwise 1870 */ 1871 public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) { 1872 Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId, 1873 disableOthers ? 1 : 0); 1874 boolean result = (resultMsg.arg1 != FAILURE); 1875 resultMsg.recycle(); 1876 return result; 1877 } 1878 1879 /** 1880 * Disable a network 1881 * 1882 * @param netId network id of the network 1883 * @return {@code true} if the operation succeeds, {@code false} otherwise 1884 */ 1885 public boolean syncDisableNetwork(AsyncChannel channel, int netId) { 1886 Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId); 1887 boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED); 1888 resultMsg.recycle(); 1889 return result; 1890 } 1891 1892 /** 1893 * Retrieves a WPS-NFC configuration token for the specified network 1894 * @return a hex string representation of the WPS-NFC configuration token 1895 */ 1896 public String syncGetWpsNfcConfigurationToken(int netId) { 1897 return mWifiNative.getNfcWpsConfigurationToken(netId); 1898 } 1899 1900 /** 1901 * Blacklist a BSSID. This will avoid the AP if there are 1902 * alternate APs to connect 1903 * 1904 * @param bssid BSSID of the network 1905 */ 1906 public void addToBlacklist(String bssid) { 1907 sendMessage(CMD_BLACKLIST_NETWORK, bssid); 1908 } 1909 1910 /** 1911 * Clear the blacklist list 1912 * 1913 */ 1914 public void clearBlacklist() { 1915 sendMessage(CMD_CLEAR_BLACKLIST); 1916 } 1917 1918 public void enableRssiPolling(boolean enabled) { 1919 sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0); 1920 } 1921 1922 public void enableBackgroundScanCommand(boolean enabled) { 1923 sendMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0); 1924 } 1925 1926 public void enableAllNetworks() { 1927 sendMessage(CMD_ENABLE_ALL_NETWORKS); 1928 } 1929 1930 /** 1931 * Start filtering Multicast v4 packets 1932 */ 1933 public void startFilteringMulticastV4Packets() { 1934 mFilteringMulticastV4Packets.set(true); 1935 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0); 1936 } 1937 1938 /** 1939 * Stop filtering Multicast v4 packets 1940 */ 1941 public void stopFilteringMulticastV4Packets() { 1942 mFilteringMulticastV4Packets.set(false); 1943 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0); 1944 } 1945 1946 /** 1947 * Start filtering Multicast v4 packets 1948 */ 1949 public void startFilteringMulticastV6Packets() { 1950 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0); 1951 } 1952 1953 /** 1954 * Stop filtering Multicast v4 packets 1955 */ 1956 public void stopFilteringMulticastV6Packets() { 1957 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0); 1958 } 1959 1960 /** 1961 * Set high performance mode of operation. 1962 * Enabling would set active power mode and disable suspend optimizations; 1963 * disabling would set auto power mode and enable suspend optimizations 1964 * @param enable true if enable, false otherwise 1965 */ 1966 public void setHighPerfModeEnabled(boolean enable) { 1967 sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0); 1968 } 1969 1970 /** 1971 * Set the country code 1972 * @param countryCode following ISO 3166 format 1973 * @param persist {@code true} if the setting should be remembered. 1974 */ 1975 public void setCountryCode(String countryCode, boolean persist) { 1976 // If it's a good country code, apply after the current 1977 // wifi connection is terminated; ignore resetting of code 1978 // for now (it is unclear what the chipset should do when 1979 // country code is reset) 1980 int countryCodeSequence = mCountryCodeSequence.incrementAndGet(); 1981 if (TextUtils.isEmpty(countryCode)) { 1982 log("Ignoring resetting of country code"); 1983 } else { 1984 sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, countryCode); 1985 } 1986 } 1987 1988 /** 1989 * Set the operational frequency band 1990 * @param band 1991 * @param persist {@code true} if the setting should be remembered. 1992 */ 1993 public void setFrequencyBand(int band, boolean persist) { 1994 if (persist) { 1995 Settings.Global.putInt(mContext.getContentResolver(), 1996 Settings.Global.WIFI_FREQUENCY_BAND, 1997 band); 1998 } 1999 sendMessage(CMD_SET_FREQUENCY_BAND, band, 0); 2000 } 2001 2002 /** 2003 * Enable TDLS for a specific MAC address 2004 */ 2005 public void enableTdls(String remoteMacAddress, boolean enable) { 2006 int enabler = enable ? 1 : 0; 2007 sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress); 2008 } 2009 2010 /** 2011 * Returns the operational frequency band 2012 */ 2013 public int getFrequencyBand() { 2014 return mFrequencyBand.get(); 2015 } 2016 2017 /** 2018 * Returns the wifi configuration file 2019 */ 2020 public String getConfigFile() { 2021 return mWifiConfigStore.getConfigFile(); 2022 } 2023 2024 /** 2025 * Send a message indicating bluetooth adapter connection state changed 2026 */ 2027 public void sendBluetoothAdapterStateChange(int state) { 2028 sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0); 2029 } 2030 2031 /** 2032 * Save configuration on supplicant 2033 * 2034 * @return {@code true} if the operation succeeds, {@code false} otherwise 2035 * 2036 * TODO: deprecate this 2037 */ 2038 public boolean syncSaveConfig(AsyncChannel channel) { 2039 Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG); 2040 boolean result = (resultMsg.arg1 != FAILURE); 2041 resultMsg.recycle(); 2042 return result; 2043 } 2044 2045 public void updateBatteryWorkSource(WorkSource newSource) { 2046 synchronized (mRunningWifiUids) { 2047 try { 2048 if (newSource != null) { 2049 mRunningWifiUids.set(newSource); 2050 } 2051 if (mIsRunning) { 2052 if (mReportedRunning) { 2053 // If the work source has changed since last time, need 2054 // to remove old work from battery stats. 2055 if (mLastRunningWifiUids.diff(mRunningWifiUids)) { 2056 mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids, 2057 mRunningWifiUids); 2058 mLastRunningWifiUids.set(mRunningWifiUids); 2059 } 2060 } else { 2061 // Now being started, report it. 2062 mBatteryStats.noteWifiRunning(mRunningWifiUids); 2063 mLastRunningWifiUids.set(mRunningWifiUids); 2064 mReportedRunning = true; 2065 } 2066 } else { 2067 if (mReportedRunning) { 2068 // Last reported we were running, time to stop. 2069 mBatteryStats.noteWifiStopped(mLastRunningWifiUids); 2070 mLastRunningWifiUids.clear(); 2071 mReportedRunning = false; 2072 } 2073 } 2074 mWakeLock.setWorkSource(newSource); 2075 } catch (RemoteException ignore) { 2076 } 2077 } 2078 } 2079 2080 @Override 2081 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2082 super.dump(fd, pw, args); 2083 mSupplicantStateTracker.dump(fd, pw, args); 2084 pw.println("mLinkProperties " + mLinkProperties); 2085 pw.println("mWifiInfo " + mWifiInfo); 2086 pw.println("mDhcpResults " + mDhcpResults); 2087 pw.println("mNetworkInfo " + mNetworkInfo); 2088 pw.println("mLastSignalLevel " + mLastSignalLevel); 2089 pw.println("mLastBssid " + mLastBssid); 2090 pw.println("mLastNetworkId " + mLastNetworkId); 2091 pw.println("mOperationalMode " + mOperationalMode); 2092 pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt); 2093 pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 2094 pw.println("Supplicant status " + mWifiNative.status()); 2095 pw.println("mEnableBackgroundScan " + mEnableBackgroundScan); 2096 pw.println("mLastSetCountryCode " + mLastSetCountryCode); 2097 pw.println("mPersistedCountryCode " + mPersistedCountryCode); 2098 pw.println(); 2099 mWifiConfigStore.dump(fd, pw, args); 2100 } 2101 2102 /********************************************************* 2103 * Internal private functions 2104 ********************************************************/ 2105 2106 private void logStateAndMessage(Message message, String state) { 2107 if (mLogMessages) { 2108 //long now = SystemClock.elapsedRealtimeNanos(); 2109 //String ts = String.format("[%,d us]", now/1000); 2110 2111 loge( " " + state + " " + getLogRecString(message)); 2112 } 2113 } 2114 2115 /** 2116 * Return the additional string to be logged by LogRec, default 2117 * 2118 * @param msg that was processed 2119 * @return information to be logged as a String 2120 */ 2121 protected String getLogRecString(Message msg) { 2122 WifiConfiguration config; 2123 StringBuilder sb = new StringBuilder(); 2124 if (mScreenOn) { 2125 sb.append("!"); 2126 } 2127 sb.append(smToString(msg)); 2128 2129 switch (msg.what) { 2130 case CMD_START_SCAN: 2131 sb.append(" "); 2132 sb.append(Integer.toString(msg.arg1)); 2133 sb.append(" "); 2134 sb.append(Integer.toString(msg.arg2)); 2135 if (mIsScanOngoing) sb.append(" onGoing"); 2136 if (mIsFullScanOngoing) sb.append(" full"); 2137 if (lastStartScanTimeStamp != 0) { 2138 sb.append(" started:").append(lastStartScanTimeStamp); 2139 } 2140 if (lastScanDuration != 0) { 2141 sb.append(" dur:").append(lastScanDuration); 2142 } 2143 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2144 sb.append(" f=").append(mWifiInfo.getFrequency()); 2145 sb.append(" sc=").append(mWifiInfo.score); 2146 sb.append(" link=").append(mWifiInfo.getLinkSpeed()); 2147 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate)); 2148 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate)); 2149 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate)); 2150 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate)); 2151 if (lastScanFreqs != null) sb.append(" ").append(lastScanFreqs); 2152 break; 2153 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2154 sb.append(" "); 2155 sb.append(Integer.toString(msg.arg1)); 2156 sb.append(" "); 2157 sb.append(Integer.toString(msg.arg2)); 2158 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj; 2159 if (stateChangeResult != null) { 2160 sb.append(stateChangeResult.toString()); 2161 } 2162 break; 2163 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 2164 sb.append(" "); 2165 sb.append(Integer.toString(msg.arg1)); 2166 sb.append(" "); 2167 sb.append(Integer.toString(msg.arg2)); 2168 String bssid = (String)msg.obj; 2169 if (bssid != null && bssid.length()>0) { 2170 sb.append(" "); 2171 sb.append(bssid); 2172 } 2173 sb.append(" blacklist=" + Boolean.toString(didBlackListBSSID)); 2174 break; 2175 case WifiMonitor.SCAN_RESULTS_EVENT: 2176 sb.append(" "); 2177 sb.append(Integer.toString(msg.arg1)); 2178 sb.append(" "); 2179 sb.append(Integer.toString(msg.arg2)); 2180 if (mScanResults != null) { 2181 sb.append(mScanResults.size()); 2182 } 2183 if (lastScanDuration != 0) { 2184 sb.append(" dur:").append(lastScanDuration); 2185 } 2186 break; 2187 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2188 sb.append(" "); 2189 sb.append(Integer.toString(msg.arg1)); 2190 sb.append(" "); 2191 sb.append(Integer.toString(msg.arg2)); 2192 sb.append(" ").append(mLastBssid); 2193 sb.append(" nid=").append(mLastNetworkId); 2194 config = getCurrentWifiConfiguration(); 2195 if (config != null) { 2196 sb.append(" ").append(config.configKey()); 2197 } 2198 break; 2199 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2200 if (msg.obj != null) { 2201 sb.append(" ").append((String)msg.obj); 2202 } 2203 sb.append(" nid=").append(msg.arg1); 2204 sb.append(" reason=").append(msg.arg2); 2205 if (mLastBssid != null) { 2206 sb.append(" lastbssid=").append(mLastBssid); 2207 } 2208 if (mWifiInfo.getFrequency() != -1) { 2209 sb.append(" freq=").append(mWifiInfo.getFrequency()); 2210 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2211 } 2212 if (linkDebouncing) { 2213 sb.append(" debounce"); 2214 } 2215 break; 2216 case WifiMonitor.SSID_TEMP_DISABLED: 2217 case WifiMonitor.SSID_REENABLED: 2218 sb.append(" nid=").append(msg.arg1); 2219 if (msg.obj != null) { 2220 sb.append(" ").append((String)msg.obj); 2221 } 2222 break; 2223 case CMD_RSSI_POLL: 2224 case CMD_UNWANTED_NETWORK: 2225 case WifiManager.RSSI_PKTCNT_FETCH: 2226 sb.append(" "); 2227 sb.append(Integer.toString(msg.arg1)); 2228 sb.append(" "); 2229 sb.append(Integer.toString(msg.arg2)); 2230 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2231 sb.append(" f=").append(mWifiInfo.getFrequency()); 2232 sb.append(" sc=").append(mWifiInfo.score); 2233 sb.append(" link=").append(mWifiInfo.getLinkSpeed()); 2234 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate)); 2235 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate)); 2236 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate)); 2237 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate)); 2238 break; 2239 case CMD_AUTO_CONNECT: 2240 case WifiManager.CONNECT_NETWORK: 2241 sb.append(" "); 2242 sb.append(Integer.toString(msg.arg1)); 2243 sb.append(" "); 2244 sb.append(Integer.toString(msg.arg2)); 2245 config = (WifiConfiguration) msg.obj; 2246 if (config != null) { 2247 sb.append(" ").append(config.configKey()); 2248 if (config.visibility != null) { 2249 sb.append(" [").append(config.visibility.num24); 2250 sb.append(" ,").append(config.visibility.rssi24); 2251 sb.append(" ;").append(config.visibility.num5); 2252 sb.append(" ,").append(config.visibility.rssi5).append("]"); 2253 } 2254 } 2255 if (mTargetRoamBSSID != null) { 2256 sb.append(" ").append(mTargetRoamBSSID); 2257 } 2258 sb.append(" roam=").append(Integer.toString(mAutoRoaming)); 2259 break; 2260 case CMD_AUTO_ROAM: 2261 sb.append(" "); 2262 sb.append(Integer.toString(msg.arg1)); 2263 sb.append(" "); 2264 sb.append(Integer.toString(msg.arg2)); 2265 ScanResult result = (ScanResult)msg.obj; 2266 if (result != null) { 2267 sb.append(" rssi=").append(result.level); 2268 sb.append(" freq=").append(result.frequency); 2269 sb.append(" ").append(result.BSSID); 2270 } 2271 if (mTargetRoamBSSID != null) { 2272 sb.append(" ").append(mTargetRoamBSSID); 2273 } 2274 sb.append(" roam=").append(Integer.toString(mAutoRoaming)); 2275 break; 2276 case CMD_ENABLE_NETWORK: 2277 sb.append(" "); 2278 sb.append(Integer.toString(msg.arg1)); 2279 sb.append(" "); 2280 sb.append(Integer.toString(msg.arg2)); 2281 String key = mWifiConfigStore.getLastSelectedConfiguration(); 2282 if (key != null) { 2283 sb.append(" ").append(key); 2284 } 2285 break; 2286 case CMD_GET_CONFIGURED_NETWORKS: 2287 sb.append(" "); 2288 sb.append(Integer.toString(msg.arg1)); 2289 sb.append(" "); 2290 sb.append(Integer.toString(msg.arg2)); 2291 sb.append(" num=").append(mWifiConfigStore.getConfiguredNetworksSize()); 2292 break; 2293 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 2294 sb.append(" "); 2295 sb.append(Integer.toString(msg.arg1)); 2296 sb.append(" "); 2297 sb.append(Integer.toString(msg.arg2)); 2298 if (msg.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 2299 sb.append(" OK "); 2300 } else if (msg.arg1 == DhcpStateMachine.DHCP_FAILURE) { 2301 sb.append(" FAIL "); 2302 } 2303 if (mLinkProperties != null) { 2304 if (mLinkProperties.hasIPv4Address()) { 2305 sb.append(" v4"); 2306 } 2307 if (mLinkProperties.hasGlobalIPv6Address()) { 2308 sb.append(" v6"); 2309 } 2310 if (mLinkProperties.hasIPv4DefaultRoute()) { 2311 sb.append(" v4r"); 2312 } 2313 if (mLinkProperties.hasIPv6DefaultRoute()) { 2314 sb.append(" v6r"); 2315 } 2316 if (mLinkProperties.hasIPv4DnsServer()) { 2317 sb.append(" v4dns"); 2318 } 2319 if (mLinkProperties.hasIPv6DnsServer()) { 2320 sb.append(" v6dns"); 2321 } 2322 } 2323 break; 2324 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 2325 sb.append(" "); 2326 sb.append(Integer.toString(msg.arg1)); 2327 sb.append(" "); 2328 sb.append(Integer.toString(msg.arg2)); 2329 if (msg.obj != null) { 2330 NetworkInfo info = (NetworkInfo)msg.obj; 2331 NetworkInfo.State state = info.getState(); 2332 NetworkInfo.DetailedState detailedState = info.getDetailedState(); 2333 if (state != null) { 2334 sb.append(" st=").append(state); 2335 } 2336 if (detailedState != null) { 2337 sb.append("/").append(detailedState); 2338 } 2339 } 2340 break; 2341 case CMD_IP_CONFIGURATION_LOST: 2342 int count = -1; 2343 WifiConfiguration c = getCurrentWifiConfiguration(); 2344 if (c != null) count = c.numConnectionFailures; 2345 sb.append(" "); 2346 sb.append(Integer.toString(msg.arg1)); 2347 sb.append(" "); 2348 sb.append(Integer.toString(msg.arg2)); 2349 sb.append(" failures: "); 2350 sb.append(Integer.toString(count)); 2351 sb.append("/"); 2352 sb.append(Integer.toString(mWifiConfigStore.getMaxDhcpRetries())); 2353 break; 2354 case CMD_UPDATE_LINKPROPERTIES: 2355 sb.append(" "); 2356 sb.append(Integer.toString(msg.arg1)); 2357 sb.append(" "); 2358 sb.append(Integer.toString(msg.arg2)); 2359 if (mLinkProperties != null) { 2360 if (mLinkProperties.hasIPv4Address()) { 2361 sb.append(" v4"); 2362 } 2363 if (mLinkProperties.hasGlobalIPv6Address()) { 2364 sb.append(" v6"); 2365 } 2366 if (mLinkProperties.hasIPv4DefaultRoute()) { 2367 sb.append(" v4r"); 2368 } 2369 if (mLinkProperties.hasIPv6DefaultRoute()) { 2370 sb.append(" v6r"); 2371 } 2372 if (mLinkProperties.hasIPv4DnsServer()) { 2373 sb.append(" v4dns"); 2374 } 2375 if (mLinkProperties.hasIPv6DnsServer()) { 2376 sb.append(" v6dns"); 2377 } 2378 } 2379 break; 2380 default: 2381 sb.append(" "); 2382 sb.append(Integer.toString(msg.arg1)); 2383 sb.append(" "); 2384 sb.append(Integer.toString(msg.arg2)); 2385 break; 2386 } 2387 2388 return sb.toString(); 2389 } 2390 2391 private void handleScreenStateChanged(boolean screenOn) { 2392 mScreenOn = screenOn; 2393 if (PDBG) { 2394 loge(" handleScreenStateChanged Enter: screenOn=" + screenOn 2395 + "mCurrentScanAlarmMs = " + Long.toString(mCurrentScanAlarmMs) 2396 + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt 2397 + " autojoin " + mFrameworkAutoJoin 2398 + " state " + getCurrentState().getName() 2399 + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); 2400 } 2401 enableRssiPolling(screenOn); 2402 if (mBackgroundScanSupported) { 2403 enableBackgroundScanCommand(screenOn == false); 2404 } 2405 2406 if (screenOn) enableAllNetworks(); 2407 if (mUserWantsSuspendOpt.get()) { 2408 if (screenOn) { 2409 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0); 2410 } else { 2411 //Allow 2s for suspend optimizations to be set 2412 mSuspendWakeLock.acquire(2000); 2413 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0); 2414 } 2415 } 2416 mScreenBroadcastReceived.set(true); 2417 2418 if (screenOn) { 2419 fullBandConnectedTimeIntervalMilli = 20 * 1000; //start at 20 seconds interval 2420 if (mFrameworkAutoJoin.get()) { 2421 //start the scan alarm so as to enable autojoin 2422 if (getCurrentState() == mConnectedState) { 2423 mCurrentScanAlarmMs = mConnectedScanPeriodMs; 2424 } else if (getCurrentState() == mDisconnectedState) { 2425 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 2426 //kick a scan right now 2427 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 2428 } else if (getCurrentState() == mDisconnectingState) { 2429 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 2430 //kick a scan right now 2431 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 2432 } 2433 } 2434 setScanAlarm(true); 2435 2436 } else { 2437 setScanAlarm(false); 2438 } 2439 2440 if (DBG) log("handleScreenStateChanged Exit: " + screenOn); 2441 } 2442 2443 private void checkAndSetConnectivityInstance() { 2444 if (mCm == null) { 2445 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 2446 } 2447 } 2448 2449 private boolean startTethering(ArrayList<String> available) { 2450 2451 boolean wifiAvailable = false; 2452 2453 checkAndSetConnectivityInstance(); 2454 2455 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 2456 2457 for (String intf : available) { 2458 for (String regex : wifiRegexs) { 2459 if (intf.matches(regex)) { 2460 2461 InterfaceConfiguration ifcg = null; 2462 try { 2463 ifcg = mNwService.getInterfaceConfig(intf); 2464 if (ifcg != null) { 2465 /* IP/netmask: 192.168.43.1/255.255.255.0 */ 2466 ifcg.setLinkAddress(new LinkAddress( 2467 NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); 2468 ifcg.setInterfaceUp(); 2469 2470 mNwService.setInterfaceConfig(intf, ifcg); 2471 } 2472 } catch (Exception e) { 2473 loge("Error configuring interface " + intf + ", :" + e); 2474 return false; 2475 } 2476 2477 if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 2478 loge("Error tethering on " + intf); 2479 return false; 2480 } 2481 mTetherInterfaceName = intf; 2482 return true; 2483 } 2484 } 2485 } 2486 // We found no interfaces to tether 2487 return false; 2488 } 2489 2490 private void stopTethering() { 2491 2492 checkAndSetConnectivityInstance(); 2493 2494 /* Clear the interface config to allow dhcp correctly configure new 2495 ip settings */ 2496 InterfaceConfiguration ifcg = null; 2497 try { 2498 ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName); 2499 if (ifcg != null) { 2500 ifcg.setLinkAddress( 2501 new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); 2502 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg); 2503 } 2504 } catch (Exception e) { 2505 loge("Error resetting interface " + mTetherInterfaceName + ", :" + e); 2506 } 2507 2508 if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 2509 loge("Untether initiate failed!"); 2510 } 2511 } 2512 2513 private boolean isWifiTethered(ArrayList<String> active) { 2514 2515 checkAndSetConnectivityInstance(); 2516 2517 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 2518 for (String intf : active) { 2519 for (String regex : wifiRegexs) { 2520 if (intf.matches(regex)) { 2521 return true; 2522 } 2523 } 2524 } 2525 // We found no interfaces that are tethered 2526 return false; 2527 } 2528 2529 /** 2530 * Set the country code from the system setting value, if any. 2531 */ 2532 private void setCountryCode() { 2533 String countryCode = Settings.Global.getString(mContext.getContentResolver(), 2534 Settings.Global.WIFI_COUNTRY_CODE); 2535 if (countryCode != null && !countryCode.isEmpty()) { 2536 setCountryCode(countryCode, false); 2537 } else { 2538 //use driver default 2539 } 2540 } 2541 2542 /** 2543 * Set the frequency band from the system setting value, if any. 2544 */ 2545 private void setFrequencyBand() { 2546 int band = Settings.Global.getInt(mContext.getContentResolver(), 2547 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO); 2548 setFrequencyBand(band, false); 2549 } 2550 2551 private void setSuspendOptimizationsNative(int reason, boolean enabled) { 2552 if (DBG) { 2553 log("setSuspendOptimizationsNative: " + reason + " " + enabled 2554 + " -want " + mUserWantsSuspendOpt.get() 2555 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2556 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 2557 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 2558 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 2559 } 2560 //mWifiNative.setSuspendOptimizations(enabled); 2561 2562 if (enabled) { 2563 mSuspendOptNeedsDisabled &= ~reason; 2564 /* None of dhcp, screen or highperf need it disabled and user wants it enabled */ 2565 if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) { 2566 if (DBG) { 2567 log("setSuspendOptimizationsNative do it " + reason + " " + enabled 2568 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2569 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 2570 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 2571 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 2572 } 2573 mWifiNative.setSuspendOptimizations(true); 2574 } 2575 } else { 2576 mSuspendOptNeedsDisabled |= reason; 2577 mWifiNative.setSuspendOptimizations(false); 2578 } 2579 } 2580 2581 private void setSuspendOptimizations(int reason, boolean enabled) { 2582 if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled); 2583 if (enabled) { 2584 mSuspendOptNeedsDisabled &= ~reason; 2585 } else { 2586 mSuspendOptNeedsDisabled |= reason; 2587 } 2588 if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 2589 } 2590 2591 private void setWifiState(int wifiState) { 2592 final int previousWifiState = mWifiState.get(); 2593 2594 try { 2595 if (wifiState == WIFI_STATE_ENABLED) { 2596 mBatteryStats.noteWifiOn(); 2597 } else if (wifiState == WIFI_STATE_DISABLED) { 2598 mBatteryStats.noteWifiOff(); 2599 } 2600 } catch (RemoteException e) { 2601 loge("Failed to note battery stats in wifi"); 2602 } 2603 2604 mWifiState.set(wifiState); 2605 2606 if (DBG) log("setWifiState: " + syncGetWifiStateByName()); 2607 2608 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 2609 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2610 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 2611 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 2612 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2613 } 2614 2615 private void setWifiApState(int wifiApState) { 2616 final int previousWifiApState = mWifiApState.get(); 2617 2618 try { 2619 if (wifiApState == WIFI_AP_STATE_ENABLED) { 2620 mBatteryStats.noteWifiOn(); 2621 } else if (wifiApState == WIFI_AP_STATE_DISABLED) { 2622 mBatteryStats.noteWifiOff(); 2623 } 2624 } catch (RemoteException e) { 2625 loge("Failed to note battery stats in wifi"); 2626 } 2627 2628 // Update state 2629 mWifiApState.set(wifiApState); 2630 2631 if (DBG) log("setWifiApState: " + syncGetWifiApStateByName()); 2632 2633 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 2634 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2635 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); 2636 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); 2637 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2638 } 2639 2640 private static final String ID_STR = "id="; 2641 private static final String BSSID_STR = "bssid="; 2642 private static final String FREQ_STR = "freq="; 2643 private static final String LEVEL_STR = "level="; 2644 private static final String TSF_STR = "tsf="; 2645 private static final String FLAGS_STR = "flags="; 2646 private static final String SSID_STR = "ssid="; 2647 private static final String DELIMITER_STR = "===="; 2648 private static final String END_STR = "####"; 2649 2650 /** 2651 * Format: 2652 * 2653 * id=1 2654 * bssid=68:7f:76:d7:1a:6e 2655 * freq=2412 2656 * level=-44 2657 * tsf=1344626243700342 2658 * flags=[WPA2-PSK-CCMP][WPS][ESS] 2659 * ssid=zfdy 2660 * ==== 2661 * id=2 2662 * bssid=68:5f:74:d7:1a:6f 2663 * freq=5180 2664 * level=-73 2665 * tsf=1344626243700373 2666 * flags=[WPA2-PSK-CCMP][WPS][ESS] 2667 * ssid=zuby 2668 * ==== 2669 */ 2670 private void setScanResults() { 2671 String bssid = ""; 2672 int level = 0; 2673 int freq = 0; 2674 long tsf = 0; 2675 String flags = ""; 2676 WifiSsid wifiSsid = null; 2677 String scanResults; 2678 String tmpResults; 2679 StringBuffer scanResultsBuf = new StringBuffer(); 2680 int sid = 0; 2681 2682 while (true) { 2683 tmpResults = mWifiNative.scanResults(sid); 2684 if (TextUtils.isEmpty(tmpResults)) break; 2685 scanResultsBuf.append(tmpResults); 2686 scanResultsBuf.append("\n"); 2687 String[] lines = tmpResults.split("\n"); 2688 sid = -1; 2689 for (int i=lines.length - 1; i >= 0; i--) { 2690 if (lines[i].startsWith(END_STR)) { 2691 break; 2692 } else if (lines[i].startsWith(ID_STR)) { 2693 try { 2694 sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1; 2695 } catch (NumberFormatException e) { 2696 // Nothing to do 2697 } 2698 break; 2699 } 2700 } 2701 if (sid == -1) break; 2702 } 2703 2704 scanResults = scanResultsBuf.toString(); 2705 if (TextUtils.isEmpty(scanResults)) { 2706 return; 2707 } 2708 2709 // note that all these splits and substrings keep references to the original 2710 // huge string buffer while the amount we really want is generally pretty small 2711 // so make copies instead (one example b/11087956 wasted 400k of heap here). 2712 synchronized(mScanResultCache) { 2713 mScanResults = new ArrayList<ScanResult>(); 2714 String[] lines = scanResults.split("\n"); 2715 final int bssidStrLen = BSSID_STR.length(); 2716 final int flagLen = FLAGS_STR.length(); 2717 2718 for (String line : lines) { 2719 if (line.startsWith(BSSID_STR)) { 2720 bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen); 2721 } else if (line.startsWith(FREQ_STR)) { 2722 try { 2723 freq = Integer.parseInt(line.substring(FREQ_STR.length())); 2724 } catch (NumberFormatException e) { 2725 freq = 0; 2726 } 2727 } else if (line.startsWith(LEVEL_STR)) { 2728 try { 2729 level = Integer.parseInt(line.substring(LEVEL_STR.length())); 2730 /* some implementations avoid negative values by adding 256 2731 * so we need to adjust for that here. 2732 */ 2733 if (level > 0) level -= 256; 2734 } catch(NumberFormatException e) { 2735 level = 0; 2736 } 2737 } else if (line.startsWith(TSF_STR)) { 2738 try { 2739 tsf = Long.parseLong(line.substring(TSF_STR.length())); 2740 } catch (NumberFormatException e) { 2741 tsf = 0; 2742 } 2743 } else if (line.startsWith(FLAGS_STR)) { 2744 flags = new String(line.getBytes(), flagLen, line.length() - flagLen); 2745 } else if (line.startsWith(SSID_STR)) { 2746 wifiSsid = WifiSsid.createFromAsciiEncoded( 2747 line.substring(SSID_STR.length())); 2748 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) { 2749 if (bssid != null) { 2750 String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 2751 String key = bssid + ssid; 2752 ScanResult scanResult = mScanResultCache.get(key); 2753 if (scanResult != null) { 2754 scanResult.level = level; 2755 scanResult.wifiSsid = wifiSsid; 2756 // Keep existing API 2757 scanResult.SSID = (wifiSsid != null) ? wifiSsid.toString() : 2758 WifiSsid.NONE; 2759 scanResult.capabilities = flags; 2760 scanResult.frequency = freq; 2761 scanResult.timestamp = tsf; 2762 scanResult.seen = System.currentTimeMillis(); 2763 } else { 2764 scanResult = 2765 new ScanResult( 2766 wifiSsid, bssid, flags, level, freq, tsf); 2767 mScanResultCache.put(key, scanResult); 2768 } 2769 mScanResults.add(scanResult); 2770 } 2771 bssid = null; 2772 level = 0; 2773 freq = 0; 2774 tsf = 0; 2775 flags = ""; 2776 wifiSsid = null; 2777 } 2778 } 2779 } 2780 boolean attemptAutoJoin = true; 2781 if (getCurrentState() == mRoamingState 2782 || getCurrentState() == mObtainingIpState 2783 || linkDebouncing) { 2784 // Dont attempt auto-joining again while we are already attempting to join 2785 // and/or obtaining Ip address 2786 attemptAutoJoin = false; 2787 } 2788 mWifiAutoJoinController.newSupplicantResults(attemptAutoJoin); 2789 if (linkDebouncing) { 2790 // If debouncing, we dont re-select a SSID or BSSID hence 2791 // there is no need to call the network selection code 2792 // in WifiAutoJoinController, instead, 2793 // just try to reconnect to the same SSID by triggering a roam 2794 sendMessage(CMD_AUTO_ROAM, mLastNetworkId, 1, null); 2795 } 2796 } 2797 2798 /* 2799 * Fetch RSSI, linkspeed, and frequency on current connection 2800 */ 2801 private void fetchRssiLinkSpeedAndFrequencyNative() { 2802 int newRssi = -1; 2803 int newLinkSpeed = -1; 2804 int newFrequency = -1; 2805 2806 String signalPoll = mWifiNative.signalPoll(); 2807 2808 if (signalPoll != null) { 2809 String[] lines = signalPoll.split("\n"); 2810 for (String line : lines) { 2811 String[] prop = line.split("="); 2812 if (prop.length < 2) continue; 2813 try { 2814 if (prop[0].equals("RSSI")) { 2815 newRssi = Integer.parseInt(prop[1]); 2816 } else if (prop[0].equals("LINKSPEED")) { 2817 newLinkSpeed = Integer.parseInt(prop[1]); 2818 } else if (prop[0].equals("FREQUENCY")) { 2819 newFrequency = Integer.parseInt(prop[1]); 2820 } 2821 } catch (NumberFormatException e) { 2822 //Ignore, defaults on rssi and linkspeed are assigned 2823 } 2824 } 2825 } 2826 2827 if (PDBG) { 2828 loge("fetchRssiLinkSpeedAndFrequencyNative rssi=" 2829 + Integer.toString(newRssi) + " linkspeed=" 2830 + Integer.toString(newLinkSpeed)); 2831 } 2832 2833 if (newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) { 2834 // screen out invalid values 2835 /* some implementations avoid negative values by adding 256 2836 * so we need to adjust for that here. 2837 */ 2838 if (newRssi > 0) newRssi -= 256; 2839 mWifiInfo.setRssi(newRssi); 2840 /* 2841 * Rather then sending the raw RSSI out every time it 2842 * changes, we precalculate the signal level that would 2843 * be displayed in the status bar, and only send the 2844 * broadcast if that much more coarse-grained number 2845 * changes. This cuts down greatly on the number of 2846 * broadcasts, at the cost of not informing others 2847 * interested in RSSI of all the changes in signal 2848 * level. 2849 */ 2850 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); 2851 if (newSignalLevel != mLastSignalLevel) { 2852 sendRssiChangeBroadcast(newRssi); 2853 } 2854 mLastSignalLevel = newSignalLevel; 2855 } else { 2856 mWifiInfo.setRssi(WifiInfo.INVALID_RSSI); 2857 } 2858 2859 if (newLinkSpeed != -1) { 2860 mWifiInfo.setLinkSpeed(newLinkSpeed); 2861 } 2862 if (newFrequency > 0) { 2863 if (ScanResult.is24GHz(newFrequency)) { 2864 mWifiConnectionStatistics.num5GhzConnected++; 2865 } 2866 if (ScanResult.is24GHz(newFrequency)) { 2867 mWifiConnectionStatistics.num24GhzConnected++; 2868 } 2869 mWifiInfo.setFrequency(newFrequency); 2870 } 2871 mWifiConfigStore.updateConfiguration(mWifiInfo); 2872 } 2873 2874 /** 2875 * Determine if we need to switch network: 2876 * - the delta determine the urgency to switch and/or or the expected evilness of the disruption 2877 * - match the uregncy of the switch versus the packet usage at the interface 2878 */ 2879 boolean shouldSwitchNetwork(int networkDelta) { 2880 int delta; 2881 if (networkDelta <= 0) { 2882 return false; 2883 } 2884 delta = networkDelta; 2885 if (mWifiInfo != null) { 2886 if (!mWifiConfigStore.enableAutoJoinWhileAssociated 2887 && mWifiInfo.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 2888 // If AutoJoin while associated is not enabled, 2889 // we should never switch network when already associated 2890 delta = -1000; 2891 } else { 2892 // TODO: Look at per AC packet count, do not switch if VO/VI traffic is present 2893 // TODO: at the interface. We should also discriminate between ucast and mcast, 2894 // TODO: since the rxSuccessRate include all the bonjour and Ipv6 2895 // TODO: broadcasts 2896 if ((mWifiInfo.txSuccessRate > 20) || (mWifiInfo.rxSuccessRate > 80)) { 2897 delta -= 999; 2898 } else if ((mWifiInfo.txSuccessRate > 5) || (mWifiInfo.rxSuccessRate > 30)) { 2899 delta -= 6; 2900 } 2901 loge("WifiStateMachine shouldSwitchNetwork " 2902 + " txSuccessRate=" + String.format("%.2f", mWifiInfo.txSuccessRate) 2903 + " rxSuccessRate=" + String.format("%.2f", mWifiInfo.rxSuccessRate) 2904 + " delta " + networkDelta + " -> " + delta); 2905 } 2906 } else { 2907 loge("WifiStateMachine shouldSwitchNetwork " 2908 + " delta " + networkDelta + " -> " + delta); 2909 } 2910 if (delta > 0) { 2911 return true; 2912 } 2913 return false; 2914 } 2915 2916 private void calculateWifiScore(WifiLinkLayerStats stats) { 2917 2918 if (stats == null || mWifiLinkLayerStatsSupported <= 0) { 2919 long mTxPkts = TrafficStats.getTxPackets(mInterfaceName); 2920 long mRxPkts = TrafficStats.getRxPackets(mInterfaceName); 2921 mWifiInfo.updatePacketRates(mTxPkts, mRxPkts); 2922 2923 } else { 2924 mWifiInfo.updatePacketRates(stats); 2925 } 2926 int score = 56; //starting score, temporarily hardcoded in between 50 and 60 2927 boolean isBadLinkspeed = (mWifiInfo.is24GHz() 2928 && mWifiInfo.getLinkSpeed() < 6) 2929 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed() < 12); 2930 boolean isGoodLinkspeed = (mWifiInfo.is24GHz() 2931 && mWifiInfo.getLinkSpeed() >= 24) 2932 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed() >= 48); 2933 2934 2935 /** 2936 * We want to make sure that we use the 24GHz RSSI thresholds is 2937 * there are 2.4GHz scan results 2938 * otherwise we end up lowering the score based on 5GHz values 2939 * which may cause a switch to LTE before roaming has a chance to try 2.4GHz 2940 * We also might unblacklist the configuation based on 2.4GHz 2941 * thresholds but joining 5GHz anyhow, and failing over to 2.4GHz because 5GHz is not good 2942 */ 2943 boolean use24Thresholds = false; 2944 boolean homeNetworkBoost = false; 2945 WifiConfiguration currentConfiguration = getCurrentWifiConfiguration(); 2946 if (currentConfiguration != null 2947 && currentConfiguration.scanResultCache != null) { 2948 currentConfiguration.setVisibility(12000); 2949 if (currentConfiguration.visibility != null) { 2950 if (currentConfiguration.visibility.rssi24 != WifiConfiguration.INVALID_RSSI 2951 && currentConfiguration.visibility.rssi24 2952 >= (currentConfiguration.visibility.rssi5-2)) { 2953 use24Thresholds = true; 2954 } 2955 } 2956 if (currentConfiguration.scanResultCache.size() <= 4 2957 && currentConfiguration.allowedKeyManagement.cardinality() == 1 2958 && currentConfiguration.allowedKeyManagement. 2959 get(WifiConfiguration.KeyMgmt.WPA_PSK) == true) { 2960 // A PSK network with less than 4 known BSSIDs 2961 // This is most likely a home network and thus we want to stick to wifi more 2962 homeNetworkBoost = true; 2963 } 2964 } 2965 2966 int rssi = mWifiInfo.getRssi() - 6 * mAggressiveHandover 2967 + (homeNetworkBoost ? WifiConfiguration.HOME_NETWORK_RSSI_BOOST : 0); 2968 boolean is24GHz = use24Thresholds || mWifiInfo.is24GHz(); 2969 2970 boolean isBadRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdBadRssi24) 2971 || (!is24GHz && rssi < mWifiConfigStore.thresholdBadRssi5); 2972 boolean isLowRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdLowRssi24) 2973 || (!is24GHz && mWifiInfo.getRssi() < mWifiConfigStore.thresholdLowRssi5); 2974 boolean isHighRSSI = (is24GHz && rssi >= mWifiConfigStore.thresholdGoodRssi24) 2975 || (!is24GHz && mWifiInfo.getRssi() >= mWifiConfigStore.thresholdGoodRssi5); 2976 2977 if (PDBG) { 2978 String rssiStatus = ""; 2979 if (isBadRSSI) rssiStatus += " badRSSI "; 2980 else if (isHighRSSI) rssiStatus += " highRSSI "; 2981 else if (isLowRSSI) rssiStatus += " lowRSSI "; 2982 if (isBadLinkspeed) rssiStatus += " lowSpeed "; 2983 loge("calculateWifiScore freq=" + Integer.toString(mWifiInfo.getFrequency()) 2984 + " speed=" + Integer.toString(mWifiInfo.getLinkSpeed()) 2985 + " score=" + Integer.toString(mWifiInfo.score) 2986 + rssiStatus 2987 + " -> txbadrate=" + String.format( "%.2f", mWifiInfo.txBadRate ) 2988 + " txgoodrate=" + String.format("%.2f", mWifiInfo.txSuccessRate) 2989 + " txretriesrate=" + String.format("%.2f", mWifiInfo.txRetriesRate) 2990 + " rxrate=" + String.format("%.2f", mWifiInfo.rxSuccessRate) 2991 ); 2992 } 2993 2994 if ((mWifiInfo.txBadRate >= 1) && (mWifiInfo.txSuccessRate < 3) 2995 && (isBadRSSI || isLowRSSI)) { 2996 // Link is stuck 2997 if (mWifiInfo.linkStuckCount < 5) 2998 mWifiInfo.linkStuckCount += 1; 2999 if (PDBG) loge(" bad link -> stuck count =" 3000 + Integer.toString(mWifiInfo.linkStuckCount)); 3001 } else if (mWifiInfo.txSuccessRate > 2 || mWifiInfo.txBadRate < 0.1) { 3002 if (mWifiInfo.linkStuckCount > 0) 3003 mWifiInfo.linkStuckCount -= 1; 3004 if (PDBG) loge(" good link -> stuck count =" 3005 + Integer.toString(mWifiInfo.linkStuckCount)); 3006 } 3007 3008 if (mWifiInfo.linkStuckCount > 1) { 3009 // Once link gets stuck for more than 3 seconds, start reducing the score 3010 score = score - 2 * (mWifiInfo.linkStuckCount - 1); 3011 } 3012 3013 if (isBadLinkspeed) { 3014 score -= 4; 3015 if (PDBG) loge(" isBadLinkspeed ---> score=" + Integer.toString(score)); 3016 } else if ((isGoodLinkspeed) && (mWifiInfo.txSuccessRate > 5)) { 3017 score += 4; // So as bad rssi alone dont kill us 3018 } 3019 3020 if (isBadRSSI) { 3021 if (mWifiInfo.badRssiCount < 7) 3022 mWifiInfo.badRssiCount += 1; 3023 } else if (isLowRSSI) { 3024 mWifiInfo.lowRssiCount = 1; // Dont increment 3025 if (mWifiInfo.badRssiCount > 0) { 3026 mWifiInfo.badRssiCount -= 1; 3027 } 3028 } else { 3029 mWifiInfo.badRssiCount = 0; 3030 mWifiInfo.lowRssiCount = 0; 3031 } 3032 3033 score -= mWifiInfo.badRssiCount * 2 + mWifiInfo.lowRssiCount ; 3034 3035 if (PDBG) loge(" badRSSI count" + Integer.toString(mWifiInfo.badRssiCount) 3036 + " lowRSSI count" + Integer.toString(mWifiInfo.lowRssiCount) 3037 + " --> score " + Integer.toString(score)); 3038 3039 3040 if (isHighRSSI) { 3041 score += 5; 3042 if (PDBG) loge(" isHighRSSI ---> score=" + Integer.toString(score)); 3043 } 3044 3045 //sanitize boundaries 3046 if (score > NetworkAgent.WIFI_BASE_SCORE) 3047 score = NetworkAgent.WIFI_BASE_SCORE; 3048 if (score < 0) 3049 score = 0; 3050 3051 //report score 3052 if (score != mWifiInfo.score) { 3053 if (DBG) { 3054 loge("calculateWifiScore() report new score " + Integer.toString(score)); 3055 } 3056 mWifiInfo.score = score; 3057 if (mNetworkAgent != null) { 3058 mNetworkAgent.sendNetworkScore(score); 3059 } 3060 } 3061 } 3062 3063 public double getTxPacketRate() { 3064 if (mWifiInfo != null) { 3065 return mWifiInfo.txSuccessRate; 3066 } 3067 return -1; 3068 } 3069 3070 public double getRxPacketRate() { 3071 if (mWifiInfo != null) { 3072 return mWifiInfo.rxSuccessRate; 3073 } 3074 return -1; 3075 } 3076 3077 /** 3078 * Fetch TX packet counters on current connection 3079 */ 3080 private void fetchPktcntNative(RssiPacketCountInfo info) { 3081 String pktcntPoll = mWifiNative.pktcntPoll(); 3082 3083 if (pktcntPoll != null) { 3084 String[] lines = pktcntPoll.split("\n"); 3085 for (String line : lines) { 3086 String[] prop = line.split("="); 3087 if (prop.length < 2) continue; 3088 try { 3089 if (prop[0].equals("TXGOOD")) { 3090 info.txgood = Integer.parseInt(prop[1]); 3091 } else if (prop[0].equals("TXBAD")) { 3092 info.txbad = Integer.parseInt(prop[1]); 3093 } 3094 } catch (NumberFormatException e) { 3095 // Ignore 3096 } 3097 } 3098 } 3099 } 3100 3101 private boolean isProvisioned(LinkProperties lp) { 3102 // LinkProperties#isProvisioned returns true even if all we have is an IPv4 address and no 3103 // connectivity. This turns out not to be very useful, because we can't distinguish it from 3104 // a state where we have an IPv4 address assigned to the interface but are still running 3105 // DHCP. 3106 // TODO: Fix LinkProperties and remove this function. 3107 if (mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 3108 return lp.hasIPv4Address(); 3109 } else { 3110 return (lp.hasIPv4Address() && lp.hasIPv4DefaultRoute() && lp.hasIPv4DnsServer()) || 3111 (lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute() && lp.hasIPv6DnsServer()); 3112 } 3113 } 3114 3115 /** 3116 * Updates mLinkProperties by merging information from various sources. 3117 * 3118 * This is needed because the information in mLinkProperties comes from multiple sources (DHCP, 3119 * netlink, static configuration, ...). When one of these sources of information has updated 3120 * link properties, we can't just assign them to mLinkProperties or we'd lose track of the 3121 * information that came from other sources. Instead, when one of those sources has new 3122 * information, we update the object that tracks the information from that source and then 3123 * call this method to apply the change to mLinkProperties. 3124 * 3125 * The information in mLinkProperties is currently obtained as follows: 3126 * - Interface name: set in the constructor. 3127 * - IPv4 and IPv6 addresses: netlink, passed in by mNetlinkTracker. 3128 * - IPv4 routes, DNS servers, and domains: DHCP. 3129 * - IPv6 routes and DNS servers: netlink, passed in by mNetlinkTracker. 3130 * - HTTP proxy: the wifi config store. 3131 */ 3132 private void updateLinkProperties(int reason) { 3133 LinkProperties newLp = new LinkProperties(); 3134 3135 // Interface name and proxy are locally configured. 3136 newLp.setInterfaceName(mInterfaceName); 3137 newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); 3138 3139 // IPv4/v6 addresses, IPv6 routes and IPv6 DNS servers come from netlink. 3140 LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties(); 3141 newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses()); 3142 for (RouteInfo route : netlinkLinkProperties.getRoutes()) { 3143 newLp.addRoute(route); 3144 } 3145 for (InetAddress dns : netlinkLinkProperties.getDnsServers()) { 3146 newLp.addDnsServer(dns); 3147 } 3148 3149 // IPv4 routes, DNS servers and domains come from mDhcpResults. 3150 synchronized (mDhcpResultsLock) { 3151 // Even when we're using static configuration, we don't need to look at the config 3152 // store, because static IP configuration also populates mDhcpResults. 3153 if ((mDhcpResults != null)) { 3154 for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) { 3155 newLp.addRoute(route); 3156 } 3157 for (InetAddress dns : mDhcpResults.dnsServers) { 3158 newLp.addDnsServer(dns); 3159 } 3160 newLp.setDomains(mDhcpResults.domains); 3161 } 3162 } 3163 3164 final boolean linkChanged = !newLp.equals(mLinkProperties); 3165 final boolean wasProvisioned = isProvisioned(mLinkProperties); 3166 final boolean isProvisioned = isProvisioned(newLp); 3167 final DetailedState detailedState = getNetworkDetailedState(); 3168 3169 if (linkChanged) { 3170 if (DBG) { 3171 log("Link configuration changed for netId: " + mLastNetworkId 3172 + " old: " + mLinkProperties + " new: " + newLp); 3173 } 3174 mLinkProperties = newLp; 3175 mLinkProperties.setTcpBufferSizes(TCP_BUFFER_SIZES_WIFI); 3176 if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); 3177 } 3178 3179 if (DBG) { 3180 StringBuilder sb = new StringBuilder(); 3181 sb.append("updateLinkProperties nid: " + mLastNetworkId); 3182 sb.append(" state: " + detailedState); 3183 sb.append(" reason: " + smToString(reason)); 3184 3185 if (mLinkProperties != null) { 3186 if (mLinkProperties.hasIPv4Address()) { 3187 sb.append(" v4"); 3188 } 3189 if (mLinkProperties.hasGlobalIPv6Address()) { 3190 sb.append(" v6"); 3191 } 3192 if (mLinkProperties.hasIPv4DefaultRoute()) { 3193 sb.append(" v4r"); 3194 } 3195 if (mLinkProperties.hasIPv6DefaultRoute()) { 3196 sb.append(" v6r"); 3197 } 3198 if (mLinkProperties.hasIPv4DnsServer()) { 3199 sb.append(" v4dns"); 3200 } 3201 if (mLinkProperties.hasIPv6DnsServer()) { 3202 sb.append(" v6dns"); 3203 } 3204 if (isProvisioned) { 3205 sb.append(" isprov"); 3206 } 3207 } 3208 loge(sb.toString()); 3209 } 3210 3211 // If we just configured or lost IP configuration, do the needful. 3212 // We don't just call handleSuccessfulIpConfiguration() or handleIpConfigurationLost() 3213 // here because those should only be called if we're attempting to connect or already 3214 // connected, whereas updateLinkProperties can be called at any time. 3215 switch (reason) { 3216 case DhcpStateMachine.DHCP_SUCCESS: 3217 case CMD_STATIC_IP_SUCCESS: 3218 // IPv4 provisioning succeded. Advance to connected state. 3219 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 3220 if (!isProvisioned) { 3221 // Can never happen unless DHCP reports success but isProvisioned thinks the 3222 // resulting configuration is invalid (e.g., no IPv4 address, or the state in 3223 // mLinkProperties is out of sync with reality, or there's a bug in this code). 3224 // TODO: disconnect here instead. If our configuration is not usable, there's no 3225 // point in staying connected, and if mLinkProperties is out of sync with 3226 // reality, that will cause problems in the future. 3227 loge("IPv4 config succeeded, but not provisioned"); 3228 } 3229 break; 3230 3231 case DhcpStateMachine.DHCP_FAILURE: 3232 // DHCP failed. If we're not already provisioned, give up and disconnect. 3233 // If we're already provisioned (e.g., IPv6-only network), stay connected. 3234 if (!isProvisioned) { 3235 sendMessage(CMD_IP_CONFIGURATION_LOST); 3236 } else { 3237 // DHCP failed, but we're provisioned (e.g., if we're on an IPv6-only network). 3238 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 3239 3240 // To be sure we don't get stuck with a non-working network if all we had is 3241 // IPv4, remove the IPv4 address from the interface (since we're using DHCP, 3242 // and DHCP failed). If we had an IPv4 address before, the deletion of the 3243 // address will cause a CMD_UPDATE_LINKPROPERTIES. If the IPv4 address was 3244 // necessary for provisioning, its deletion will cause us to disconnect. 3245 // 3246 // This should never happen, because a DHCP failure will have empty DhcpResults 3247 // and thus empty LinkProperties, and isProvisioned will not return true if 3248 // we're using DHCP and don't have an IPv4 default route. So for now it's only 3249 // here for extra redundancy. However, it will increase robustness if we move 3250 // to getting IPv4 routes from netlink as well. 3251 loge("DHCP failure: provisioned, should not happen! Clearing IPv4 address."); 3252 try { 3253 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 3254 ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0")); 3255 ifcg.setInterfaceUp(); 3256 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 3257 } catch (RemoteException e) { 3258 sendMessage(CMD_IP_CONFIGURATION_LOST); 3259 } 3260 } 3261 break; 3262 3263 case CMD_STATIC_IP_FAILURE: 3264 // Static configuration was invalid, or an error occurred in applying it. Give up. 3265 sendMessage(CMD_IP_CONFIGURATION_LOST); 3266 break; 3267 3268 case CMD_UPDATE_LINKPROPERTIES: 3269 // IP addresses, DNS servers, etc. changed. Act accordingly. 3270 if (wasProvisioned && !isProvisioned) { 3271 // We no longer have a usable network configuration. Disconnect. 3272 sendMessage(CMD_IP_CONFIGURATION_LOST); 3273 } else if (!wasProvisioned && isProvisioned) { 3274 // We have a usable IPv6-only config. Advance to connected state. 3275 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 3276 } 3277 if (linkChanged && getNetworkDetailedState() == DetailedState.CONNECTED) { 3278 // If anything has changed and we're already connected, send out a notification. 3279 sendLinkConfigurationChangedBroadcast(); 3280 } 3281 break; 3282 } 3283 } 3284 3285 /** 3286 * Clears all our link properties. 3287 */ 3288 private void clearLinkProperties() { 3289 // Clear the link properties obtained from DHCP and netlink. 3290 synchronized (mDhcpResultsLock) { 3291 if (mDhcpResults != null) { 3292 mDhcpResults.clear(); 3293 } 3294 } 3295 mNetlinkTracker.clearLinkProperties(); 3296 3297 // Now clear the merged link properties. 3298 mLinkProperties.clear(); 3299 if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); 3300 } 3301 3302 /** 3303 * try to update default route MAC address. 3304 */ 3305 private String updateDefaultRouteMacAddress(int timeout) { 3306 String address = null; 3307 for (RouteInfo route : mLinkProperties.getRoutes()) { 3308 if (route.isDefaultRoute() && route.hasGateway()) { 3309 InetAddress gateway = route.getGateway(); 3310 if (gateway instanceof Inet4Address) { 3311 if (PDBG) { 3312 loge("updateDefaultRouteMacAddress found Ipv4 default :" 3313 + gateway.getHostAddress()); 3314 } 3315 address = macAddressFromRoute(gateway.getHostAddress()); 3316 /* The gateway's MAC address is known */ 3317 if ((address == null) && (timeout > 0)) { 3318 boolean reachable = false; 3319 try { 3320 reachable = gateway.isReachable(timeout); 3321 } catch (Exception e) { 3322 loge("updateDefaultRouteMacAddress exception reaching :" 3323 + gateway.getHostAddress()); 3324 3325 } finally { 3326 if (reachable == true) { 3327 3328 address = macAddressFromRoute(gateway.getHostAddress()); 3329 if (PDBG) { 3330 loge("updateDefaultRouteMacAddress reachable (tried again) :" 3331 + gateway.getHostAddress() + " found " + address); 3332 } 3333 } 3334 } 3335 } 3336 if (address != null) { 3337 mWifiConfigStore.setDefaultGwMacAddress(mLastNetworkId, address); 3338 } 3339 } 3340 } 3341 } 3342 return address; 3343 } 3344 3345 private void sendScanResultsAvailableBroadcast() { 3346 noteScanEnd(); 3347 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 3348 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3349 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 3350 } 3351 3352 private void sendRssiChangeBroadcast(final int newRssi) { 3353 try { 3354 mBatteryStats.noteWifiRssiChanged(newRssi); 3355 } catch (RemoteException e) { 3356 // Won't happen. 3357 } 3358 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); 3359 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3360 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); 3361 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3362 } 3363 3364 private void sendNetworkStateChangeBroadcast(String bssid) { 3365 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); 3366 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3367 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 3368 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties)); 3369 if (bssid != null) 3370 intent.putExtra(WifiManager.EXTRA_BSSID, bssid); 3371 if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK || 3372 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { 3373 intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo)); 3374 } 3375 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3376 } 3377 3378 private void sendLinkConfigurationChangedBroadcast() { 3379 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); 3380 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3381 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); 3382 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 3383 } 3384 3385 private void sendSupplicantConnectionChangedBroadcast(boolean connected) { 3386 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 3387 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3388 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); 3389 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 3390 } 3391 3392 /** 3393 * Record the detailed state of a network. 3394 * @param state the new {@code DetailedState} 3395 */ 3396 private void setNetworkDetailedState(NetworkInfo.DetailedState state) { 3397 boolean hidden = false; 3398 3399 if (linkDebouncing || isRoaming()) { 3400 // There is generally a confusion in the system about colluding 3401 // WiFi Layer 2 state (as reported by supplicant) and the Network state 3402 // which leads to multiple confusion. 3403 // 3404 // If link is de-bouncing or roaming, we already have an IP address 3405 // as well we were connected and are doing L2 cycles of 3406 // reconnecting or renewing IP address to check that we still have it 3407 // This L2 link flapping should ne be reflected into the Network state 3408 // which is the state of the WiFi Network visible to Layer 3 and applications 3409 // Note that once debouncing and roaming are completed, we will 3410 // set the Network state to where it should be, or leave it as unchanged 3411 // 3412 hidden = true; 3413 } 3414 if (DBG) { 3415 log("setDetailed state, old =" 3416 + mNetworkInfo.getDetailedState() + " and new state=" + state 3417 + " hidden=" + hidden); 3418 } 3419 if (hidden == true) return; 3420 3421 if (state != mNetworkInfo.getDetailedState()) { 3422 mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); 3423 if (mNetworkAgent != null) { 3424 mNetworkAgent.sendNetworkInfo(mNetworkInfo); 3425 } 3426 } 3427 } 3428 3429 private DetailedState getNetworkDetailedState() { 3430 return mNetworkInfo.getDetailedState(); 3431 } 3432 3433 3434 private SupplicantState handleSupplicantStateChange(Message message) { 3435 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 3436 SupplicantState state = stateChangeResult.state; 3437 // Supplicant state change 3438 // [31-13] Reserved for future use 3439 // [8 - 0] Supplicant state (as defined in SupplicantState.java) 3440 // 50023 supplicant_state_changed (custom|1|5) 3441 mWifiInfo.setSupplicantState(state); 3442 // Network id is only valid when we start connecting 3443 if (SupplicantState.isConnecting(state)) { 3444 mWifiInfo.setNetworkId(stateChangeResult.networkId); 3445 } else { 3446 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 3447 } 3448 3449 mWifiInfo.setBSSID(stateChangeResult.BSSID); 3450 mWifiInfo.setSSID(stateChangeResult.wifiSsid); 3451 3452 mSupplicantStateTracker.sendMessage(Message.obtain(message)); 3453 3454 return state; 3455 } 3456 3457 /** 3458 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 3459 * using the interface, stopping DHCP & disabling interface 3460 */ 3461 private void handleNetworkDisconnect() { 3462 if (DBG) log("handleNetworkDisconnect: Stopping DHCP and clearing IP" 3463 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 3464 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 3465 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 3466 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 3467 3468 stopDhcp(); 3469 3470 try { 3471 mNwService.clearInterfaceAddresses(mInterfaceName); 3472 mNwService.disableIpv6(mInterfaceName); 3473 } catch (Exception e) { 3474 loge("Failed to clear addresses or disable ipv6" + e); 3475 } 3476 3477 /* Reset data structures */ 3478 mWifiInfo.reset(); 3479 linkDebouncing = false; 3480 /* Reset roaming parameters */ 3481 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 3482 fullBandConnectedTimeIntervalMilli = 20 * 1000; // Start scans at 20 seconds interval 3483 3484 setNetworkDetailedState(DetailedState.DISCONNECTED); 3485 if (mNetworkAgent != null) { 3486 mNetworkAgent.sendNetworkInfo(mNetworkInfo); 3487 mNetworkAgent = null; 3488 } 3489 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 3490 3491 /* Clear network properties */ 3492 clearLinkProperties(); 3493 3494 /* Cend event to CM & network change broadcast */ 3495 sendNetworkStateChangeBroadcast(mLastBssid); 3496 3497 /* Cancel auto roam requests */ 3498 autoRoamSetBSSID(mLastNetworkId, "any"); 3499 3500 mLastBssid= null; 3501 registerDisconnected(); 3502 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 3503 } 3504 3505 private void handleSupplicantConnectionLoss() { 3506 /* Socket connection can be lost when we do a graceful shutdown 3507 * or when the driver is hung. Ensure supplicant is stopped here. 3508 */ 3509 mWifiMonitor.killSupplicant(mP2pSupported); 3510 mWifiNative.closeSupplicantConnection(); 3511 sendSupplicantConnectionChangedBroadcast(false); 3512 setWifiState(WIFI_STATE_DISABLED); 3513 } 3514 3515 void handlePreDhcpSetup() { 3516 mDhcpActive = true; 3517 if (!mBluetoothConnectionActive) { 3518 /* 3519 * There are problems setting the Wi-Fi driver's power 3520 * mode to active when bluetooth coexistence mode is 3521 * enabled or sense. 3522 * <p> 3523 * We set Wi-Fi to active mode when 3524 * obtaining an IP address because we've found 3525 * compatibility issues with some routers with low power 3526 * mode. 3527 * <p> 3528 * In order for this active power mode to properly be set, 3529 * we disable coexistence mode until we're done with 3530 * obtaining an IP address. One exception is if we 3531 * are currently connected to a headset, since disabling 3532 * coexistence would interrupt that connection. 3533 */ 3534 // Disable the coexistence mode 3535 mWifiNative.setBluetoothCoexistenceMode( 3536 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); 3537 } 3538 3539 // Disable power save and suspend optimizations during DHCP 3540 // Note: The order here is important for now. Brcm driver changes 3541 // power settings when we control suspend mode optimizations. 3542 // TODO: Remove this comment when the driver is fixed. 3543 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false); 3544 mWifiNative.setPowerSave(false); 3545 3546 stopBatchedScan(); 3547 WifiNative.pauseScan(); 3548 3549 /* P2p discovery breaks dhcp, shut it down in order to get through this */ 3550 Message msg = new Message(); 3551 msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY; 3552 msg.arg1 = WifiP2pServiceImpl.ENABLED; 3553 msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE; 3554 msg.obj = mDhcpStateMachine; 3555 mWifiP2pChannel.sendMessage(msg); 3556 } 3557 3558 3559 void startDhcp() { 3560 if (mDhcpStateMachine == null) { 3561 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 3562 mContext, WifiStateMachine.this, mInterfaceName); 3563 3564 } 3565 mDhcpStateMachine.registerForPreDhcpNotification(); 3566 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); 3567 } 3568 3569 void renewDhcp() { 3570 if (mDhcpStateMachine == null) { 3571 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 3572 mContext, WifiStateMachine.this, mInterfaceName); 3573 3574 } 3575 mDhcpStateMachine.registerForPreDhcpNotification(); 3576 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_RENEW_DHCP); 3577 } 3578 3579 void stopDhcp() { 3580 if (mDhcpStateMachine != null) { 3581 /* In case we were in middle of DHCP operation restore back powermode */ 3582 handlePostDhcpSetup(); 3583 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); 3584 } 3585 } 3586 3587 void handlePostDhcpSetup() { 3588 /* Restore power save and suspend optimizations */ 3589 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true); 3590 mWifiNative.setPowerSave(true); 3591 3592 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED); 3593 3594 // Set the coexistence mode back to its default value 3595 mWifiNative.setBluetoothCoexistenceMode( 3596 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); 3597 3598 mDhcpActive = false; 3599 3600 startBatchedScan(); 3601 WifiNative.restartScan(); 3602 } 3603 3604 private void handleIPv4Success(DhcpResults dhcpResults, int reason) { 3605 3606 if (PDBG) { 3607 loge("wifistatemachine handleIPv4Success <" + dhcpResults.toString() + ">"); 3608 loge("link address " + dhcpResults.ipAddress); 3609 } 3610 3611 synchronized (mDhcpResultsLock) { 3612 mDhcpResults = dhcpResults; 3613 } 3614 3615 Inet4Address addr = (Inet4Address) dhcpResults.ipAddress.getAddress(); 3616 if (isRoaming()) { 3617 if (addr instanceof Inet4Address) { 3618 int previousAddress = mWifiInfo.getIpAddress(); 3619 int newAddress = NetworkUtils.inetAddressToInt(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) { 3650 mDhcpResults.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 private static final String TCP_BUFFER_SIZES_WIFI = 5647 "524288,1048576,2097152,262144,524288,1048576"; 5648 5649 class L2ConnectedState extends State { 5650 @Override 5651 public void enter() { 5652 mRssiPollToken++; 5653 if (mEnableRssiPolling) { 5654 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0); 5655 } 5656 if (mNetworkAgent != null) { 5657 loge("Have NetworkAgent when entering L2Connected"); 5658 setNetworkDetailedState(DetailedState.DISCONNECTED); 5659 } 5660 setNetworkDetailedState(DetailedState.CONNECTING); 5661 mLinkProperties.setTcpBufferSizes(TCP_BUFFER_SIZES_WIFI); 5662 5663 mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext, 5664 "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter, 5665 mLinkProperties, 60); 5666 } 5667 5668 @Override 5669 public void exit() { 5670 // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState 5671 // Bug: 15347363 5672 // For paranoia's sake, call handleNetworkDisconnect 5673 // only if BSSID is null or last networkId 5674 // is not invalid. 5675 if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 5676 handleNetworkDisconnect(); 5677 } 5678 } 5679 5680 @Override 5681 public boolean processMessage(Message message) { 5682 logStateAndMessage(message, getClass().getSimpleName()); 5683 5684 switch (message.what) { 5685 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 5686 handlePreDhcpSetup(); 5687 break; 5688 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 5689 handlePostDhcpSetup(); 5690 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 5691 if (DBG) log("WifiStateMachine DHCP successful"); 5692 handleIPv4Success((DhcpResults) message.obj, DhcpStateMachine.DHCP_SUCCESS); 5693 // We advance to mVerifyingLinkState because handleIPv4Success will call 5694 // updateLinkProperties, which then sends CMD_IP_CONFIGURATION_SUCCESSFUL. 5695 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { 5696 if (DBG) { 5697 int count = -1; 5698 WifiConfiguration config = getCurrentWifiConfiguration(); 5699 if (config != null) { 5700 count = config.numConnectionFailures; 5701 } 5702 log("WifiStateMachine DHCP failure count=" + count); 5703 } 5704 handleIPv4Failure(DhcpStateMachine.DHCP_FAILURE); 5705 // As above, we transition to mDisconnectingState via updateLinkProperties. 5706 } 5707 break; 5708 case CMD_IP_CONFIGURATION_SUCCESSFUL: 5709 handleSuccessfulIpConfiguration(); 5710 sendConnectedState(); 5711 transitionTo(mConnectedState); 5712 break; 5713 case CMD_IP_CONFIGURATION_LOST: 5714 handleIpConfigurationLost(); 5715 transitionTo(mDisconnectingState); 5716 break; 5717 case CMD_DISCONNECT: 5718 mWifiNative.disconnect(); 5719 transitionTo(mDisconnectingState); 5720 break; 5721 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 5722 if (message.arg1 == 1) { 5723 mWifiNative.disconnect(); 5724 mTemporarilyDisconnectWifi = true; 5725 transitionTo(mDisconnectingState); 5726 } 5727 break; 5728 case CMD_SET_OPERATIONAL_MODE: 5729 if (message.arg1 != CONNECT_MODE) { 5730 sendMessage(CMD_DISCONNECT); 5731 deferMessage(message); 5732 } 5733 break; 5734 case CMD_SET_COUNTRY_CODE: 5735 deferMessage(message); 5736 break; 5737 case CMD_START_SCAN: 5738 if (DBG) { 5739 loge("WifiStateMachine CMD_START_SCAN source " + message.arg1 5740 + " txSuccessRate="+String.format( "%.2f", mWifiInfo.txSuccessRate) 5741 + " rxSuccessRate="+String.format( "%.2f", mWifiInfo.rxSuccessRate) 5742 + " BSSID=" + mTargetRoamBSSID 5743 + " RSSI=" + mWifiInfo.getRssi()); 5744 } 5745 if (message.arg1 == SCAN_ALARM_SOURCE) { 5746 boolean tryFullBandScan = false; 5747 boolean restrictChannelList = false; 5748 long now_ms = System.currentTimeMillis(); 5749 if (mWifiInfo != null) { 5750 if ((now_ms - lastFullBandConnectedTimeMilli) 5751 > fullBandConnectedTimeIntervalMilli) { 5752 if (DBG) { 5753 loge("WifiStateMachine CMD_START_SCAN try full band scan age=" 5754 + Long.toString(now_ms - lastFullBandConnectedTimeMilli) 5755 + " interval=" + fullBandConnectedTimeIntervalMilli); 5756 } 5757 tryFullBandScan = true; 5758 } 5759 5760 if (mWifiInfo.txSuccessRate > 5 || mWifiInfo.rxSuccessRate > 30) { 5761 // Too much traffic at the interface, hence no full band scan 5762 if (DBG) { 5763 loge("WifiStateMachine CMD_START_SCAN " + 5764 "prevent full band scan due to pkt rate"); 5765 } 5766 tryFullBandScan = false; 5767 } 5768 5769 if (mWifiInfo.txSuccessRate > 5770 mWifiConfigStore.maxTxPacketForNetworkSwitching 5771 || mWifiInfo.rxSuccessRate > 5772 mWifiConfigStore.maxRxPacketForNetworkSwitching) { 5773 // Don't scan if lots of packets are being sent 5774 restrictChannelList = true; 5775 if (mAllowScansWithTraffic == 0) { 5776 if (DBG) { 5777 loge("WifiStateMachine CMD_START_SCAN source " + message.arg1 5778 + " ...and ignore scans" 5779 + " tx=" + String.format("%.2f", mWifiInfo.txSuccessRate) 5780 + " rx=" + String.format("%.2f", mWifiInfo.rxSuccessRate)); 5781 } 5782 return HANDLED; 5783 } 5784 } 5785 } 5786 5787 WifiConfiguration currentConfiguration = getCurrentWifiConfiguration(); 5788 if (currentConfiguration != null) { 5789 if (tryFullBandScan) { 5790 lastFullBandConnectedTimeMilli = now_ms; 5791 if (fullBandConnectedTimeIntervalMilli < 20 * 1000) { 5792 // Paranoia, make sure interval is not less than 20 seconds 5793 fullBandConnectedTimeIntervalMilli = 20 * 1000; 5794 } 5795 if (fullBandConnectedTimeIntervalMilli 5796 < maxFullBandConnectedTimeIntervalMilli) { 5797 // Increase the interval 5798 fullBandConnectedTimeIntervalMilli 5799 = fullBandConnectedTimeIntervalMilli * 3 / 2; 5800 } 5801 handleScanRequest( 5802 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 5803 } else { 5804 if (!startScanForConfiguration( 5805 currentConfiguration, restrictChannelList)) { 5806 if (DBG) { 5807 loge("WifiStateMachine starting scan, " + 5808 " did not find channels"); 5809 handleScanRequest( 5810 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 5811 } 5812 } 5813 } 5814 } 5815 } else { 5816 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 5817 } 5818 break; 5819 /* Ignore connection to same network */ 5820 case WifiManager.CONNECT_NETWORK: 5821 int netId = message.arg1; 5822 if (mWifiInfo.getNetworkId() == netId) { 5823 break; 5824 } 5825 return NOT_HANDLED; 5826 case WifiManager.SAVE_NETWORK: 5827 WifiConfiguration config = (WifiConfiguration) message.obj; 5828 int nid = config.networkId; 5829 if (config == null) { 5830 loge("SAVE_NETWORK-L2 id=" + Integer.toString(nid) 5831 + " " + mSupplicantStateTracker.getSupplicantStateName() 5832 + " my state " + getCurrentState().getName()); 5833 } else { 5834 loge("SAVE_NETWORK-L2 id=" + Integer.toString(nid) 5835 + " SSID=" + config.SSID 5836 + " cnid=" + config.networkId 5837 + " autojoin=" + Integer.toString(config.autoJoinStatus) 5838 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 5839 + " my state " + getCurrentState().getName() 5840 + " uid " + Integer.toString(config.creatorUid)); 5841 } 5842 5843 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 5844 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 5845 if (result.hasIpChanged()) { 5846 // We switched from DHCP to static or from static to DHCP, or the 5847 // static IP address has changed. 5848 log("Reconfiguring IP on connection"); 5849 // TODO: clear addresses and disable IPv6 to simplify obtainingIpState. 5850 transitionTo(mObtainingIpState); 5851 } 5852 if (result.hasProxyChanged()) { 5853 log("Reconfiguring proxy on connection"); 5854 updateLinkProperties(CMD_UPDATE_LINKPROPERTIES); 5855 } 5856 } 5857 5858 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 5859 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 5860 if (VDBG) { 5861 loge("Success save network l2 nid=" 5862 + Integer.toString(result.getNetworkId()) 5863 + " autojoin " + mFrameworkAutoJoin.get()); 5864 } 5865 if (mFrameworkAutoJoin.get()) { 5866 /** 5867 * Tell autojoin the user did try to modify and save that network. 5868 * and interpret the SAVE network 5869 * command as a manual request to connect 5870 * */ 5871 mWifiAutoJoinController.updateConfigurationHistory(config.networkId, 5872 true, true); 5873 mWifiAutoJoinController.attemptAutoJoin(); 5874 } 5875 } else { 5876 loge("Failed to save network"); 5877 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 5878 WifiManager.ERROR); 5879 } 5880 break; 5881 /* Ignore */ 5882 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5883 break; 5884 case CMD_RSSI_POLL: 5885 if (message.arg1 == mRssiPollToken) { 5886 WifiLinkLayerStats stats = null; 5887 // Try a reading L2 stats a couple of time, allow for a few failures 5888 // in case the HAL/drivers are not completely initialized once we get there 5889 if (mWifiLinkLayerStatsSupported > 0) { 5890 stats = mWifiNative.getWifiLinkLayerStats(); 5891 if (stats == null && mWifiLinkLayerStatsSupported > 0) { 5892 mWifiLinkLayerStatsSupported -= 1; 5893 } 5894 } 5895 // Get Info and continue polling 5896 fetchRssiLinkSpeedAndFrequencyNative(); 5897 calculateWifiScore(stats); 5898 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 5899 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 5900 } else { 5901 // Polling has completed 5902 } 5903 break; 5904 case CMD_ENABLE_RSSI_POLL: 5905 mEnableRssiPolling = (message.arg1 == 1); 5906 mRssiPollToken++; 5907 if (mEnableRssiPolling) { 5908 // First poll 5909 fetchRssiLinkSpeedAndFrequencyNative(); 5910 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 5911 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 5912 } 5913 break; 5914 case WifiManager.RSSI_PKTCNT_FETCH: 5915 RssiPacketCountInfo info = new RssiPacketCountInfo(); 5916 fetchRssiLinkSpeedAndFrequencyNative(); 5917 info.rssi = mWifiInfo.getRssi(); 5918 fetchPktcntNative(info); 5919 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info); 5920 break; 5921 case CMD_UNWANTED_NETWORK: 5922 // mWifiConfigStore.handleBadNetworkDisconnectReport(mLastNetworkId, mWifiInfo); 5923 // disconnecting is probably too rough and reduce the chance we recover quickly. 5924 // we should not have to disconnect, instead rely on network stack to send data 5925 // traffic somewhere else but remember that this network is roamable with a 5926 // low wifi score threshold 5927 sendMessage(CMD_DISCONNECT); 5928 break; 5929 case CMD_DELAYED_NETWORK_DISCONNECT: 5930 if (!linkDebouncing) { 5931 // Ignore if we are not debouncing 5932 loge("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore " 5933 + message.arg1); 5934 return HANDLED; 5935 } else { 5936 loge("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect " 5937 + message.arg1); 5938 5939 linkDebouncing = false; 5940 // If we are still debouncing while this message comes, 5941 // it means we were not able to reconnect within the alloted time 5942 // = LINK_FLAPPING_DEBOUNCE_MSEC 5943 // and thus, trigger a real disconnect 5944 handleNetworkDisconnect(); 5945 transitionTo(mDisconnectedState); 5946 } 5947 break; 5948 default: 5949 return NOT_HANDLED; 5950 } 5951 5952 return HANDLED; 5953 } 5954 } 5955 5956 class ObtainingIpState extends State { 5957 @Override 5958 public void enter() { 5959 if (DBG) { 5960 String key = ""; 5961 if (getCurrentWifiConfiguration() != null) { 5962 key = getCurrentWifiConfiguration().configKey(); 5963 } 5964 log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId) 5965 + " " + key + " " 5966 + " roam=" + mAutoRoaming 5967 + " static=" + mWifiConfigStore.isUsingStaticIp(mLastNetworkId) 5968 + " watchdog= " + obtainingIpWatchdogCount); 5969 } 5970 5971 // Reset link Debouncing, indicating we have successfully re-connected to the AP 5972 // We might still be roaming 5973 linkDebouncing = false; 5974 5975 try { 5976 mNwService.enableIpv6(mInterfaceName); 5977 } catch (RemoteException re) { 5978 loge("Failed to enable IPv6: " + re); 5979 } catch (IllegalStateException e) { 5980 loge("Failed to enable IPv6: " + e); 5981 } 5982 5983 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 5984 if (isRoaming()) { 5985 renewDhcp(); 5986 } else { 5987 // Remove any IP address on the interface in case we're switching from static 5988 // IP configuration to DHCP. This is safe because if we get here when not 5989 // roaming, we don't have a usable address. 5990 startDhcp(); 5991 } 5992 obtainingIpWatchdogCount++; 5993 loge("Start Dhcp Watchdog " + obtainingIpWatchdogCount); 5994 sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER, 5995 obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC); 5996 } else { 5997 // stop any running dhcp before assigning static IP 5998 stopDhcp(); 5999 StaticIpConfiguration config = mWifiConfigStore.getStaticIpConfiguration( 6000 mLastNetworkId); 6001 if (config.ipAddress == null) { 6002 loge("Static IP lacks address"); 6003 sendMessage(CMD_STATIC_IP_FAILURE); 6004 } else { 6005 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 6006 ifcg.setLinkAddress(config.ipAddress); 6007 ifcg.setInterfaceUp(); 6008 try { 6009 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 6010 if (DBG) log("Static IP configuration succeeded"); 6011 DhcpResults dhcpResults = new DhcpResults(config); 6012 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults); 6013 } catch (RemoteException re) { 6014 loge("Static IP configuration failed: " + re); 6015 sendMessage(CMD_STATIC_IP_FAILURE); 6016 } catch (IllegalStateException e) { 6017 loge("Static IP configuration failed: " + e); 6018 sendMessage(CMD_STATIC_IP_FAILURE); 6019 } 6020 } 6021 } 6022 } 6023 @Override 6024 public boolean processMessage(Message message) { 6025 logStateAndMessage(message, getClass().getSimpleName()); 6026 6027 switch(message.what) { 6028 case CMD_STATIC_IP_SUCCESS: 6029 handleIPv4Success((DhcpResults) message.obj, CMD_STATIC_IP_SUCCESS); 6030 break; 6031 case CMD_STATIC_IP_FAILURE: 6032 handleIPv4Failure(CMD_STATIC_IP_FAILURE); 6033 break; 6034 case CMD_AUTO_CONNECT: 6035 case CMD_AUTO_ROAM: 6036 break; 6037 case WifiManager.SAVE_NETWORK: 6038 deferMessage(message); 6039 break; 6040 /* Defer any power mode changes since we must keep active power mode at DHCP */ 6041 case CMD_SET_HIGH_PERF_MODE: 6042 deferMessage(message); 6043 break; 6044 /* Defer scan request since we should not switch to other channels at DHCP */ 6045 case CMD_START_SCAN: 6046 deferMessage(message); 6047 break; 6048 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: 6049 if (message.arg1 == obtainingIpWatchdogCount) { 6050 loge("ObtainingIpAddress: Watchdog Triggered, count=" 6051 + obtainingIpWatchdogCount); 6052 handleIpConfigurationLost(); 6053 transitionTo(mDisconnectingState); 6054 break; 6055 } 6056 default: 6057 return NOT_HANDLED; 6058 } 6059 return HANDLED; 6060 } 6061 } 6062 6063 class VerifyingLinkState extends State { 6064 @Override 6065 public void enter() { 6066 log(getName() + " enter"); 6067 setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); 6068 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); 6069 sendNetworkStateChangeBroadcast(mLastBssid); 6070 // End roaming 6071 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 6072 } 6073 @Override 6074 public boolean processMessage(Message message) { 6075 logStateAndMessage(message, getClass().getSimpleName()); 6076 6077 switch (message.what) { 6078 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 6079 // Stay here 6080 log(getName() + " POOR_LINK_DETECTED: no transition"); 6081 break; 6082 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 6083 log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); 6084 6085 log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED"); 6086 sendConnectedState(); 6087 transitionTo(mConnectedState); 6088 break; 6089 case CMD_START_SCAN: 6090 deferMessage(message); 6091 break; 6092 default: 6093 if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); 6094 return NOT_HANDLED; 6095 } 6096 return HANDLED; 6097 } 6098 } 6099 6100 private void sendConnectedState() { 6101 // Send out a broadcast with the CAPTIVE_PORTAL_CHECK to preserve 6102 // existing behaviour. The captive portal check really happens after we 6103 // transition into DetailedState.CONNECTED. 6104 setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); 6105 mWifiConfigStore.updateStatus(mLastNetworkId, 6106 DetailedState.CAPTIVE_PORTAL_CHECK); 6107 sendNetworkStateChangeBroadcast(mLastBssid); 6108 6109 setNetworkDetailedState(DetailedState.CONNECTED); 6110 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); 6111 sendNetworkStateChangeBroadcast(mLastBssid); 6112 } 6113 6114 class RoamingState extends State { 6115 @Override 6116 public void enter() { 6117 if (DBG) { 6118 log("RoamingState Enter" 6119 + " mScreenOn=" + mScreenOn ); 6120 } 6121 setScanAlarm(false); 6122 //TODO: actually implement an alarm, but so as to disconnect if roaming fails 6123 } 6124 @Override 6125 public boolean processMessage(Message message) { 6126 logStateAndMessage(message, getClass().getSimpleName()); 6127 6128 switch (message.what) { 6129 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 6130 if (DBG) log("Roaming and Watchdog reports poor link -> ignore"); 6131 return HANDLED; 6132 case CMD_UNWANTED_NETWORK: 6133 if (DBG) log("Roaming and CS doesnt want the network -> ignore"); 6134 return HANDLED; 6135 case CMD_SET_OPERATIONAL_MODE: 6136 if (message.arg1 != CONNECT_MODE) { 6137 deferMessage(message); 6138 } 6139 break; 6140 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6141 /** 6142 * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT 6143 * before NETWORK_DISCONNECTION_EVENT 6144 * And there is an associated BSSID corresponding to our target BSSID, then 6145 * we have missed the network disconnection, transition to mDisconnectedState 6146 * and handle the rest of the events there. 6147 */ 6148 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 6149 if (stateChangeResult.state == SupplicantState.DISCONNECTED 6150 || stateChangeResult.state == SupplicantState.INACTIVE 6151 || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) { 6152 if (DBG) { 6153 log("STATE_CHANGE_EVENT in roaming state " 6154 + stateChangeResult.toString() ); 6155 } 6156 if (stateChangeResult.BSSID != null 6157 && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) { 6158 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 6159 handleNetworkDisconnect(); 6160 } 6161 } 6162 break; 6163 case WifiMonitor.NETWORK_CONNECTION_EVENT: 6164 if (DBG) log("roaming and Network connection established"); 6165 mLastNetworkId = message.arg1; 6166 mLastBssid = (String) message.obj; 6167 mWifiInfo.setBSSID(mLastBssid); 6168 mWifiInfo.setNetworkId(mLastNetworkId); 6169 mWifiConfigStore.handleBSSIDBlackList(mLastNetworkId, mLastBssid, true); 6170 /** 6171 * We already have an IP address, we are going to the ObtainingIpAddress 6172 * state to renew it. Other parts of the system interpret an 6173 * ObtainingIpState change as not having IP address anymore, 6174 * hence, don't send the state change there. */ 6175 // setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 6176 // sendNetworkStateChangeBroadcast(mLastBssid); 6177 transitionTo(mObtainingIpState); 6178 break; 6179 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 6180 // Throw away but only if it correspond to the network we're roaming to 6181 String bssid = (String)message.obj; 6182 if (true) { 6183 String target = ""; 6184 if (mTargetRoamBSSID != null) target = mTargetRoamBSSID; 6185 log("NETWORK_DISCONNECTION_EVENT in roaming state" 6186 + " BSSID=" + bssid 6187 + " target=" + target); 6188 } 6189 if (bssid != null && bssid.equals(mTargetRoamBSSID)) { 6190 handleNetworkDisconnect(); 6191 transitionTo(mDisconnectedState); 6192 } 6193 break; 6194 case WifiMonitor.SSID_TEMP_DISABLED: 6195 // Auth error while roaming 6196 loge("SSID_TEMP_DISABLED nid=" + Integer.toString(mLastNetworkId) 6197 + " id=" + Integer.toString(message.arg1) 6198 + " isRoaming=" + isRoaming() 6199 + " roam=" + Integer.toString(mAutoRoaming)); 6200 if (message.arg1 == mLastNetworkId) { 6201 handleNetworkDisconnect(); 6202 transitionTo(mDisconnectingState); 6203 } 6204 return NOT_HANDLED; 6205 case CMD_START_SCAN: 6206 deferMessage(message); 6207 break; 6208 default: 6209 return NOT_HANDLED; 6210 } 6211 return HANDLED; 6212 } 6213 6214 @Override 6215 public void exit() { 6216 loge("WifiStateMachine: Leaving Roaming state"); 6217 } 6218 } 6219 6220 class ConnectedState extends State { 6221 @Override 6222 public void enter() { 6223 String address; 6224 updateDefaultRouteMacAddress(1000); 6225 if (DBG) { 6226 log("ConnectedState Enter autojoin=" + mFrameworkAutoJoin.get() 6227 + " mScreenOn=" + mScreenOn 6228 + " scanperiod=" + Integer.toString(mConnectedScanPeriodMs) ); 6229 } 6230 if (mFrameworkAutoJoin.get() && mScreenOn) { 6231 mCurrentScanAlarmMs = mConnectedScanPeriodMs; 6232 setScanAlarm(true); 6233 } else { 6234 mCurrentScanAlarmMs = 0; 6235 } 6236 registerConnected(); 6237 lastConnectAttempt = 0; 6238 targetWificonfiguration = null; 6239 // Paranoia 6240 linkDebouncing = false; 6241 6242 // Not roaming anymore 6243 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 6244 6245 if (testNetworkDisconnect) { 6246 testNetworkDisconnectCounter++; 6247 loge("ConnectedState Enter start disconnect test " + 6248 testNetworkDisconnectCounter); 6249 sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT, 6250 testNetworkDisconnectCounter, 0), 15000); 6251 } 6252 } 6253 @Override 6254 public boolean processMessage(Message message) { 6255 logStateAndMessage(message, getClass().getSimpleName()); 6256 6257 switch (message.what) { 6258 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 6259 if (DBG) log("Watchdog reports poor link"); 6260 transitionTo(mVerifyingLinkState); 6261 break; 6262 case CMD_UNWANTED_NETWORK: 6263 mWifiConfigStore.handleBadNetworkDisconnectReport(mLastNetworkId, mWifiInfo); 6264 mWifiNative.disconnect(); 6265 transitionTo(mDisconnectingState); 6266 return HANDLED; 6267 case CMD_TEST_NETWORK_DISCONNECT: 6268 // Force a disconnect 6269 if (message.arg1 == testNetworkDisconnectCounter) { 6270 mWifiNative.disconnect(); 6271 } 6272 break; 6273 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 6274 if (!linkDebouncing && ( 6275 (ScanResult.is24GHz(mWifiInfo.getFrequency()) 6276 && mWifiInfo.getRssi() > 6277 WifiConfiguration.BAD_RSSI_24) 6278 || (ScanResult.is5GHz(mWifiInfo.getFrequency()) 6279 && mWifiInfo.getRssi() > 6280 WifiConfiguration.BAD_RSSI_5))) { 6281 // Start de-bouncing the L2 disconnection: 6282 // this L2 disconnection might be spurious. 6283 // Hence we allow 7 seconds for the state machine to try 6284 // to reconnect, go thru the 6285 // roaming cycle and enter Obtaining IP address 6286 // before signalling the disconnect to ConnectivityService and L3 6287 startScanForConfiguration(getCurrentWifiConfiguration(), false); 6288 linkDebouncing = true; 6289 6290 sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT, 6291 0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC); 6292 if (DBG) { 6293 log("NETWORK_DISCONNECTION_EVENT in connected state" 6294 + " BSSID=" + mWifiInfo.getBSSID() 6295 + " RSSI=" + mWifiInfo.getRssi() 6296 + " freq=" + mWifiInfo.getFrequency() 6297 + " -> debounce"); 6298 } 6299 return HANDLED; 6300 } else { 6301 if (DBG) { 6302 log("NETWORK_DISCONNECTION_EVENT in connected state" 6303 + " BSSID=" + mWifiInfo.getBSSID() 6304 + " RSSI=" + mWifiInfo.getRssi() 6305 + " freq=" + mWifiInfo.getFrequency() 6306 + " was debouncing=" + linkDebouncing); 6307 } 6308 } 6309 break; 6310 case CMD_AUTO_ROAM: 6311 /* This will happen similarly to an Auto_CONNECT, except we specify the BSSID */ 6312 /* Work Around: wpa_supplicant can get in a bad state where it returns a non 6313 * associated status thus the STATUS command but somehow-someplace still thinks 6314 * it is associated and thus will ignore select/reconnect command with 6315 * following message: 6316 * "Already associated with the selected network - do nothing" 6317 * 6318 * Hence, sends a disconnect to supplicant first. 6319 */ 6320 //mWifiNative.disconnect(); 6321 6322 /* Connect command coming from auto-join */ 6323 ScanResult candidate = (ScanResult)message.obj; 6324 String bssid = "any"; 6325 if (candidate != null) { 6326 bssid = candidate.BSSID; 6327 } 6328 int netId = mLastNetworkId; 6329 WifiConfiguration config = getCurrentWifiConfiguration(); 6330 6331 loge("CMD_AUTO_ROAM sup state " 6332 + mSupplicantStateTracker.getSupplicantStateName() 6333 + " my state " + getCurrentState().getName() 6334 + " nid=" + Integer.toString(netId) 6335 + " roam=" + Integer.toString(message.arg2) 6336 + bssid); 6337 if (config == null) { 6338 loge("AUTO_ROAM and no config, bail out..."); 6339 break; 6340 } 6341 6342 /* Save the BSSID so as to lock it @ firmware */ 6343 autoRoamSetBSSID(config, bssid); 6344 6345 /* Save the network config */ 6346 loge("CMD_AUTO_ROAM will save config -> " + config.SSID 6347 + " nid=" + Integer.toString(netId)); 6348 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 6349 netId = result.getNetworkId(); 6350 loge("CMD_AUTO_ROAM did save config -> " 6351 + " nid=" + Integer.toString(netId)); 6352 6353 if (mWifiConfigStore.selectNetwork(netId) && 6354 mWifiNative.reassociate()) { 6355 lastConnectAttempt = System.currentTimeMillis(); 6356 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 6357 6358 // replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 6359 mAutoRoaming = message.arg2; 6360 transitionTo(mRoamingState); 6361 6362 } else { 6363 loge("Failed to connect config: " + config + " netId: " + netId); 6364 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 6365 WifiManager.ERROR); 6366 break; 6367 } 6368 break; 6369 default: 6370 return NOT_HANDLED; 6371 } 6372 return HANDLED; 6373 } 6374 6375 @Override 6376 public void exit() { 6377 loge("WifiStateMachine: Leaving Connected state"); 6378 setScanAlarm(false); 6379 } 6380 } 6381 6382 class DisconnectingState extends State { 6383 6384 @Override 6385 public void enter() { 6386 if (mFrameworkAutoJoin.get()) { 6387 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 6388 } else { 6389 6390 mCurrentScanAlarmMs = mFrameworkScanIntervalMs; 6391 } 6392 6393 if (PDBG) { 6394 loge(" Enter DisconnectingState State scan interval " + mFrameworkScanIntervalMs 6395 + " mEnableBackgroundScan= " + mEnableBackgroundScan 6396 + " screenOn=" + mScreenOn); 6397 } 6398 if (mScreenOn) 6399 setScanAlarm(true); 6400 } 6401 6402 @Override 6403 public boolean processMessage(Message message) { 6404 logStateAndMessage(message, getClass().getSimpleName()); 6405 switch (message.what) { 6406 case CMD_SET_OPERATIONAL_MODE: 6407 if (message.arg1 != CONNECT_MODE) { 6408 deferMessage(message); 6409 } 6410 break; 6411 case CMD_START_SCAN: 6412 // Ignore scans while disconnecting 6413 return HANDLED; 6414 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6415 /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT 6416 * we have missed the network disconnection, transition to mDisconnectedState 6417 * and handle the rest of the events there 6418 */ 6419 deferMessage(message); 6420 handleNetworkDisconnect(); 6421 transitionTo(mDisconnectedState); 6422 break; 6423 default: 6424 return NOT_HANDLED; 6425 } 6426 return HANDLED; 6427 } 6428 6429 @Override 6430 public void exit() { 6431 mCurrentScanAlarmMs = 0; 6432 } 6433 } 6434 6435 class DisconnectedState extends State { 6436 @Override 6437 public void enter() { 6438 // We dont scan frequently if this is a temporary disconnect 6439 // due to p2p 6440 if (mTemporarilyDisconnectWifi) { 6441 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 6442 return; 6443 } 6444 6445 // Loose the last selection choice 6446 // mWifiAutoJoinController.setLastSelectedConfiguration 6447 // (WifiConfiguration.INVALID_NETWORK_ID); 6448 6449 mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 6450 Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS, 6451 mDefaultFrameworkScanIntervalMs); 6452 6453 if (mFrameworkAutoJoin.get()) { 6454 if (mScreenOn) 6455 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 6456 } else { 6457 mCurrentScanAlarmMs = mFrameworkScanIntervalMs; 6458 } 6459 6460 if (PDBG) { 6461 loge(" Enter disconnected State scan interval " + mFrameworkScanIntervalMs 6462 + " mEnableBackgroundScan= " + mEnableBackgroundScan 6463 + " screenOn=" + mScreenOn); 6464 } 6465 6466 /** clear the roaming state, if we were roaming, we failed */ 6467 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 6468 6469 /** 6470 * mFrameworkAutoJoin is False: We initiate background scanning if it is enabled, 6471 * otherwise we initiate an infrequent scan that wakes up the device to ensure 6472 * a user connects to an access point on the move 6473 * 6474 * mFrameworkAutoJoin is True: 6475 * - screen dark and PNO supported => scan alarm disabled 6476 * - everything else => scan alarm enabled with mDefaultFrameworkScanIntervalMs period 6477 */ 6478 if ((mScreenOn == false) && mEnableBackgroundScan) { //mEnableBackgroundScan) { 6479 /* If a regular scan result is pending, do not initiate background 6480 * scan until the scan results are returned. This is needed because 6481 * initiating a background scan will cancel the regular scan and 6482 * scan results will not be returned until background scanning is 6483 * cleared 6484 */ 6485 if (!mIsScanOngoing) { 6486 mWifiNative.enableBackgroundScan(true); 6487 } 6488 } else { 6489 setScanAlarm(true); 6490 } 6491 6492 if (mFrameworkAutoJoin.get() && mScreenOn && isScanAllowed()) { 6493 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 6494 } 6495 6496 /** 6497 * If we have no networks saved, the supplicant stops doing the periodic scan. 6498 * The scans are useful to notify the user of the presence of an open network. 6499 * Note that these are not wake up scans. 6500 */ 6501 if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) { 6502 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 6503 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 6504 } 6505 } 6506 @Override 6507 public boolean processMessage(Message message) { 6508 boolean ret = HANDLED; 6509 6510 logStateAndMessage(message, getClass().getSimpleName()); 6511 6512 switch (message.what) { 6513 case CMD_NO_NETWORKS_PERIODIC_SCAN: 6514 if (mP2pConnected.get()) break; 6515 if (message.arg1 == mPeriodicScanToken && 6516 mWifiConfigStore.getConfiguredNetworks().size() == 0) { 6517 startScan(UNKNOWN_SCAN_SOURCE, null, null); 6518 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 6519 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 6520 } 6521 break; 6522 case WifiManager.FORGET_NETWORK: 6523 case CMD_REMOVE_NETWORK: 6524 // Set up a delayed message here. After the forget/remove is handled 6525 // the handled delayed message will determine if there is a need to 6526 // scan and continue 6527 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 6528 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 6529 ret = NOT_HANDLED; 6530 break; 6531 case CMD_SET_OPERATIONAL_MODE: 6532 if (message.arg1 != CONNECT_MODE) { 6533 mOperationalMode = message.arg1; 6534 6535 mWifiConfigStore.disableAllNetworks(); 6536 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 6537 mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); 6538 setWifiState(WIFI_STATE_DISABLED); 6539 } 6540 6541 transitionTo(mScanModeState); 6542 } 6543 break; 6544 case CMD_ENABLE_BACKGROUND_SCAN: 6545 mEnableBackgroundScan = (message.arg1 == 1); 6546 loge("enableBackgroundScanCommand enabled=" + mEnableBackgroundScan 6547 + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); 6548 6549 if (mEnableBackgroundScan) { 6550 mWifiNative.enableBackgroundScan(true); 6551 setScanAlarm(false); 6552 } else { 6553 if (mFrameworkAutoJoin.get()) { 6554 // Tell supplicant to disconnect so as it doesnt start scanning 6555 // for connection upon disabling background scan 6556 mWifiNative.disconnect(); 6557 } 6558 mWifiNative.enableBackgroundScan(false); 6559 setScanAlarm(true); 6560 } 6561 break; 6562 /* Ignore network disconnect */ 6563 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 6564 break; 6565 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6566 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 6567 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 6568 /* ConnectModeState does the rest of the handling */ 6569 ret = NOT_HANDLED; 6570 break; 6571 case CMD_START_SCAN: 6572 if (!isScanAllowed()) { 6573 // Ignore the scan request 6574 return HANDLED; 6575 } 6576 /* Disable background scan temporarily during a regular scan */ 6577 if (mEnableBackgroundScan) { 6578 mWifiNative.enableBackgroundScan(false); 6579 } 6580 /* Handled in parent state */ 6581 ret = NOT_HANDLED; 6582 break; 6583 case WifiMonitor.SCAN_RESULTS_EVENT: 6584 /* Re-enable background scan when a pending scan result is received */ 6585 if (mEnableBackgroundScan && mIsScanOngoing) { 6586 mWifiNative.enableBackgroundScan(true); 6587 } 6588 /* Handled in parent state */ 6589 ret = NOT_HANDLED; 6590 break; 6591 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 6592 NetworkInfo info = (NetworkInfo) message.obj; 6593 mP2pConnected.set(info.isConnected()); 6594 if (mP2pConnected.get()) { 6595 int defaultInterval = mContext.getResources().getInteger( 6596 R.integer.config_wifi_scan_interval_p2p_connected); 6597 long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 6598 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 6599 defaultInterval); 6600 mWifiNative.setScanInterval((int) scanIntervalMs/1000); 6601 } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { 6602 if (DBG) log("Turn on scanning after p2p disconnected"); 6603 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 6604 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 6605 } 6606 case CMD_RECONNECT: 6607 case CMD_REASSOCIATE: 6608 if (mTemporarilyDisconnectWifi) { 6609 // Drop a third party reconnect/reassociate if STA is 6610 // temporarily disconnected for p2p 6611 break; 6612 } else { 6613 // ConnectModeState handles it 6614 ret = NOT_HANDLED; 6615 } 6616 break; 6617 default: 6618 ret = NOT_HANDLED; 6619 } 6620 return ret; 6621 } 6622 6623 @Override 6624 public void exit() { 6625 /* No need for a background scan upon exit from a disconnected state */ 6626 if (mEnableBackgroundScan) { 6627 mWifiNative.enableBackgroundScan(false); 6628 } 6629 mCurrentScanAlarmMs = 0; 6630 setScanAlarm(false); 6631 } 6632 } 6633 6634 class WpsRunningState extends State { 6635 // Tracks the source to provide a reply 6636 private Message mSourceMessage; 6637 @Override 6638 public void enter() { 6639 mSourceMessage = Message.obtain(getCurrentMessage()); 6640 } 6641 @Override 6642 public boolean processMessage(Message message) { 6643 logStateAndMessage(message, getClass().getSimpleName()); 6644 6645 switch (message.what) { 6646 case WifiMonitor.WPS_SUCCESS_EVENT: 6647 // Ignore intermediate success, wait for full connection 6648 break; 6649 case WifiMonitor.NETWORK_CONNECTION_EVENT: 6650 replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED); 6651 mSourceMessage.recycle(); 6652 mSourceMessage = null; 6653 deferMessage(message); 6654 transitionTo(mDisconnectedState); 6655 break; 6656 case WifiMonitor.WPS_OVERLAP_EVENT: 6657 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 6658 WifiManager.WPS_OVERLAP_ERROR); 6659 mSourceMessage.recycle(); 6660 mSourceMessage = null; 6661 transitionTo(mDisconnectedState); 6662 break; 6663 case WifiMonitor.WPS_FAIL_EVENT: 6664 // Arg1 has the reason for the failure 6665 if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) { 6666 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1); 6667 mSourceMessage.recycle(); 6668 mSourceMessage = null; 6669 transitionTo(mDisconnectedState); 6670 } else { 6671 if (DBG) log("Ignore unspecified fail event during WPS connection"); 6672 } 6673 break; 6674 case WifiMonitor.WPS_TIMEOUT_EVENT: 6675 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 6676 WifiManager.WPS_TIMED_OUT); 6677 mSourceMessage.recycle(); 6678 mSourceMessage = null; 6679 transitionTo(mDisconnectedState); 6680 break; 6681 case WifiManager.START_WPS: 6682 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS); 6683 break; 6684 case WifiManager.CANCEL_WPS: 6685 if (mWifiNative.cancelWps()) { 6686 replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED); 6687 } else { 6688 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR); 6689 } 6690 transitionTo(mDisconnectedState); 6691 break; 6692 /** 6693 * Defer all commands that can cause connections to a different network 6694 * or put the state machine out of connect mode 6695 */ 6696 case CMD_STOP_DRIVER: 6697 case CMD_SET_OPERATIONAL_MODE: 6698 case WifiManager.CONNECT_NETWORK: 6699 case CMD_ENABLE_NETWORK: 6700 case CMD_RECONNECT: 6701 case CMD_REASSOCIATE: 6702 deferMessage(message); 6703 break; 6704 case CMD_AUTO_CONNECT: 6705 case CMD_AUTO_ROAM: 6706 case CMD_START_SCAN: 6707 return HANDLED; 6708 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 6709 if (DBG) log("Network connection lost"); 6710 handleNetworkDisconnect(); 6711 break; 6712 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 6713 if (DBG) log("Ignore Assoc reject event during WPS Connection"); 6714 break; 6715 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 6716 // Disregard auth failure events during WPS connection. The 6717 // EAP sequence is retried several times, and there might be 6718 // failures (especially for wps pin). We will get a WPS_XXX 6719 // event at the end of the sequence anyway. 6720 if (DBG) log("Ignore auth failure during WPS connection"); 6721 break; 6722 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6723 // Throw away supplicant state changes when WPS is running. 6724 // We will start getting supplicant state changes once we get 6725 // a WPS success or failure 6726 break; 6727 default: 6728 return NOT_HANDLED; 6729 } 6730 return HANDLED; 6731 } 6732 6733 @Override 6734 public void exit() { 6735 mWifiConfigStore.enableAllNetworks(); 6736 mWifiConfigStore.loadConfiguredNetworks(); 6737 } 6738 } 6739 6740 class SoftApStartingState extends State { 6741 @Override 6742 public void enter() { 6743 final Message message = getCurrentMessage(); 6744 if (message.what == CMD_START_AP) { 6745 final WifiConfiguration config = (WifiConfiguration) message.obj; 6746 6747 if (config == null) { 6748 mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); 6749 } else { 6750 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 6751 startSoftApWithConfig(config); 6752 } 6753 } else { 6754 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); 6755 } 6756 } 6757 @Override 6758 public boolean processMessage(Message message) { 6759 logStateAndMessage(message, getClass().getSimpleName()); 6760 6761 switch(message.what) { 6762 case CMD_START_SUPPLICANT: 6763 case CMD_STOP_SUPPLICANT: 6764 case CMD_START_AP: 6765 case CMD_STOP_AP: 6766 case CMD_START_DRIVER: 6767 case CMD_STOP_DRIVER: 6768 case CMD_SET_OPERATIONAL_MODE: 6769 case CMD_SET_COUNTRY_CODE: 6770 case CMD_SET_FREQUENCY_BAND: 6771 case CMD_START_PACKET_FILTERING: 6772 case CMD_STOP_PACKET_FILTERING: 6773 case CMD_TETHER_STATE_CHANGE: 6774 deferMessage(message); 6775 break; 6776 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: 6777 WifiConfiguration config = (WifiConfiguration) message.obj; 6778 if (config != null) { 6779 startSoftApWithConfig(config); 6780 } else { 6781 loge("Softap config is null!"); 6782 sendMessage(CMD_START_AP_FAILURE); 6783 } 6784 break; 6785 case CMD_START_AP_SUCCESS: 6786 setWifiApState(WIFI_AP_STATE_ENABLED); 6787 transitionTo(mSoftApStartedState); 6788 break; 6789 case CMD_START_AP_FAILURE: 6790 setWifiApState(WIFI_AP_STATE_FAILED); 6791 transitionTo(mInitialState); 6792 break; 6793 default: 6794 return NOT_HANDLED; 6795 } 6796 return HANDLED; 6797 } 6798 } 6799 6800 class SoftApStartedState extends State { 6801 @Override 6802 public boolean processMessage(Message message) { 6803 logStateAndMessage(message, getClass().getSimpleName()); 6804 6805 switch(message.what) { 6806 case CMD_STOP_AP: 6807 if (DBG) log("Stopping Soft AP"); 6808 /* We have not tethered at this point, so we just shutdown soft Ap */ 6809 try { 6810 mNwService.stopAccessPoint(mInterfaceName); 6811 } catch(Exception e) { 6812 loge("Exception in stopAccessPoint()"); 6813 } 6814 setWifiApState(WIFI_AP_STATE_DISABLED); 6815 transitionTo(mInitialState); 6816 break; 6817 case CMD_START_AP: 6818 // Ignore a start on a running access point 6819 break; 6820 // Fail client mode operation when soft AP is enabled 6821 case CMD_START_SUPPLICANT: 6822 loge("Cannot start supplicant with a running soft AP"); 6823 setWifiState(WIFI_STATE_UNKNOWN); 6824 break; 6825 case CMD_TETHER_STATE_CHANGE: 6826 TetherStateChange stateChange = (TetherStateChange) message.obj; 6827 if (startTethering(stateChange.available)) { 6828 transitionTo(mTetheringState); 6829 } 6830 break; 6831 default: 6832 return NOT_HANDLED; 6833 } 6834 return HANDLED; 6835 } 6836 } 6837 6838 class TetheringState extends State { 6839 @Override 6840 public void enter() { 6841 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 6842 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 6843 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 6844 } 6845 @Override 6846 public boolean processMessage(Message message) { 6847 logStateAndMessage(message, getClass().getSimpleName()); 6848 6849 switch(message.what) { 6850 case CMD_TETHER_STATE_CHANGE: 6851 TetherStateChange stateChange = (TetherStateChange) message.obj; 6852 if (isWifiTethered(stateChange.active)) { 6853 transitionTo(mTetheredState); 6854 } 6855 return HANDLED; 6856 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 6857 if (message.arg1 == mTetherToken) { 6858 loge("Failed to get tether update, shutdown soft access point"); 6859 transitionTo(mSoftApStartedState); 6860 // Needs to be first thing handled 6861 sendMessageAtFrontOfQueue(CMD_STOP_AP); 6862 } 6863 break; 6864 case CMD_START_SUPPLICANT: 6865 case CMD_STOP_SUPPLICANT: 6866 case CMD_START_AP: 6867 case CMD_STOP_AP: 6868 case CMD_START_DRIVER: 6869 case CMD_STOP_DRIVER: 6870 case CMD_SET_OPERATIONAL_MODE: 6871 case CMD_SET_COUNTRY_CODE: 6872 case CMD_SET_FREQUENCY_BAND: 6873 case CMD_START_PACKET_FILTERING: 6874 case CMD_STOP_PACKET_FILTERING: 6875 deferMessage(message); 6876 break; 6877 default: 6878 return NOT_HANDLED; 6879 } 6880 return HANDLED; 6881 } 6882 } 6883 6884 class TetheredState extends State { 6885 @Override 6886 public boolean processMessage(Message message) { 6887 logStateAndMessage(message, getClass().getSimpleName()); 6888 6889 switch(message.what) { 6890 case CMD_TETHER_STATE_CHANGE: 6891 TetherStateChange stateChange = (TetherStateChange) message.obj; 6892 if (!isWifiTethered(stateChange.active)) { 6893 loge("Tethering reports wifi as untethered!, shut down soft Ap"); 6894 setHostApRunning(null, false); 6895 setHostApRunning(null, true); 6896 } 6897 return HANDLED; 6898 case CMD_STOP_AP: 6899 if (DBG) log("Untethering before stopping AP"); 6900 setWifiApState(WIFI_AP_STATE_DISABLING); 6901 stopTethering(); 6902 transitionTo(mUntetheringState); 6903 // More work to do after untethering 6904 deferMessage(message); 6905 break; 6906 default: 6907 return NOT_HANDLED; 6908 } 6909 return HANDLED; 6910 } 6911 } 6912 6913 class UntetheringState extends State { 6914 @Override 6915 public void enter() { 6916 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 6917 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 6918 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 6919 6920 } 6921 @Override 6922 public boolean processMessage(Message message) { 6923 logStateAndMessage(message, getClass().getSimpleName()); 6924 6925 switch(message.what) { 6926 case CMD_TETHER_STATE_CHANGE: 6927 TetherStateChange stateChange = (TetherStateChange) message.obj; 6928 6929 /* Wait till wifi is untethered */ 6930 if (isWifiTethered(stateChange.active)) break; 6931 6932 transitionTo(mSoftApStartedState); 6933 break; 6934 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 6935 if (message.arg1 == mTetherToken) { 6936 loge("Failed to get tether update, force stop access point"); 6937 transitionTo(mSoftApStartedState); 6938 } 6939 break; 6940 case CMD_START_SUPPLICANT: 6941 case CMD_STOP_SUPPLICANT: 6942 case CMD_START_AP: 6943 case CMD_STOP_AP: 6944 case CMD_START_DRIVER: 6945 case CMD_STOP_DRIVER: 6946 case CMD_SET_OPERATIONAL_MODE: 6947 case CMD_SET_COUNTRY_CODE: 6948 case CMD_SET_FREQUENCY_BAND: 6949 case CMD_START_PACKET_FILTERING: 6950 case CMD_STOP_PACKET_FILTERING: 6951 deferMessage(message); 6952 break; 6953 default: 6954 return NOT_HANDLED; 6955 } 6956 return HANDLED; 6957 } 6958 } 6959 6960 //State machine initiated requests can have replyTo set to null indicating 6961 //there are no recepients, we ignore those reply actions 6962 private void replyToMessage(Message msg, int what) { 6963 if (msg.replyTo == null) return; 6964 Message dstMsg = obtainMessageWithArg2(msg); 6965 dstMsg.what = what; 6966 mReplyChannel.replyToMessage(msg, dstMsg); 6967 } 6968 6969 private void replyToMessage(Message msg, int what, int arg1) { 6970 if (msg.replyTo == null) return; 6971 Message dstMsg = obtainMessageWithArg2(msg); 6972 dstMsg.what = what; 6973 dstMsg.arg1 = arg1; 6974 mReplyChannel.replyToMessage(msg, dstMsg); 6975 } 6976 6977 private void replyToMessage(Message msg, int what, Object obj) { 6978 if (msg.replyTo == null) return; 6979 Message dstMsg = obtainMessageWithArg2(msg); 6980 dstMsg.what = what; 6981 dstMsg.obj = obj; 6982 mReplyChannel.replyToMessage(msg, dstMsg); 6983 } 6984 6985 /** 6986 * arg2 on the source message has a unique id that needs to be retained in replies 6987 * to match the request 6988 6989 * see WifiManager for details 6990 */ 6991 private Message obtainMessageWithArg2(Message srcMsg) { 6992 Message msg = Message.obtain(); 6993 msg.arg2 = srcMsg.arg2; 6994 return msg; 6995 } 6996 6997 private static int parseHex(char ch) { 6998 if ('0' <= ch && ch <= '9') { 6999 return ch - '0'; 7000 } else if ('a' <= ch && ch <= 'f') { 7001 return ch - 'a' + 10; 7002 } else if ('A' <= ch && ch <= 'F') { 7003 return ch - 'A' + 10; 7004 } else { 7005 throw new NumberFormatException("" + ch + " is not a valid hex digit"); 7006 } 7007 } 7008 7009 private byte[] parseHex(String hex) { 7010 /* This only works for good input; don't throw bad data at it */ 7011 if (hex == null) { 7012 return new byte[0]; 7013 } 7014 7015 if (hex.length() % 2 != 0) { 7016 throw new NumberFormatException(hex + " is not a valid hex string"); 7017 } 7018 7019 byte[] result = new byte[(hex.length())/2 + 1]; 7020 result[0] = (byte) ((hex.length())/2); 7021 for (int i = 0, j = 1; i < hex.length(); i += 2, j++) { 7022 int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i+1)); 7023 byte b = (byte) (val & 0xFF); 7024 result[j] = b; 7025 } 7026 7027 return result; 7028 } 7029 7030 private static String makeHex(byte[] bytes) { 7031 StringBuilder sb = new StringBuilder(); 7032 for (byte b : bytes) { 7033 sb.append(String.format("%02x", b)); 7034 } 7035 return sb.toString(); 7036 } 7037 7038 private static String makeHex(byte[] bytes, int from, int len) { 7039 StringBuilder sb = new StringBuilder(); 7040 for (int i = 0; i < len; i++) { 7041 sb.append(String.format("%02x", bytes[from+i])); 7042 } 7043 return sb.toString(); 7044 } 7045 7046 7047 private static byte[] concat(byte[] array1, byte[] array2, byte[] array3) { 7048 7049 int len = array1.length + array2.length + array3.length; 7050 7051 if (array1.length != 0) { 7052 len++; /* add another byte for size */ 7053 } 7054 7055 if (array2.length != 0) { 7056 len++; /* add another byte for size */ 7057 } 7058 7059 if (array3.length != 0) { 7060 len++; /* add another byte for size */ 7061 } 7062 7063 byte[] result = new byte[len]; 7064 7065 int index = 0; 7066 if (array1.length != 0) { 7067 result[index] = (byte) (array1.length & 0xFF); 7068 index++; 7069 for (byte b : array1) { 7070 result[index] = b; 7071 index++; 7072 } 7073 } 7074 7075 if (array2.length != 0) { 7076 result[index] = (byte) (array2.length & 0xFF); 7077 index++; 7078 for (byte b : array2) { 7079 result[index] = b; 7080 index++; 7081 } 7082 } 7083 7084 if (array3.length != 0) { 7085 result[index] = (byte) (array3.length & 0xFF); 7086 index++; 7087 for (byte b : array3) { 7088 result[index] = b; 7089 index++; 7090 } 7091 } 7092 return result; 7093 } 7094 7095 void handleGsmAuthRequest(SimAuthRequestData requestData) { 7096 if (targetWificonfiguration == null 7097 || targetWificonfiguration.networkId == requestData.networkId) { 7098 logd("id matches targetWifiConfiguration"); 7099 } else { 7100 logd("id does not match targetWifiConfiguration"); 7101 return; 7102 } 7103 7104 TelephonyManager tm = (TelephonyManager) 7105 mContext.getSystemService(Context.TELEPHONY_SERVICE); 7106 7107 if (tm != null) { 7108 StringBuilder sb = new StringBuilder(); 7109 for (String challenge : requestData.challenges) { 7110 7111 logd("RAND = " + challenge); 7112 7113 byte[] rand = null; 7114 try { 7115 rand = parseHex(challenge); 7116 } catch (NumberFormatException e) { 7117 loge("malformed challenge"); 7118 continue; 7119 } 7120 7121 String base64Challenge = android.util.Base64.encodeToString( 7122 rand, android.util.Base64.NO_WRAP); 7123 /* 7124 * appType = 1 => SIM, 2 => USIM according to 7125 * com.android.internal.telephony.PhoneConstants#APPTYPE_xxx 7126 */ 7127 int appType = 2; 7128 String tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge); 7129 logv("Raw Response - " + tmResponse); 7130 7131 if (tmResponse != null && tmResponse.length() > 4) { 7132 byte[] result = android.util.Base64.decode(tmResponse, 7133 android.util.Base64.DEFAULT); 7134 logv("Hex Response -" + makeHex(result)); 7135 int sres_len = result[0]; 7136 String sres = makeHex(result, 1, sres_len); 7137 int kc_offset = 1+sres_len; 7138 int kc_len = result[kc_offset]; 7139 String kc = makeHex(result, 1+kc_offset, kc_len); 7140 sb.append(":" + kc + ":" + sres); 7141 logv("kc:" + kc + " sres:" + sres); 7142 } else { 7143 loge("bad response - " + tmResponse); 7144 } 7145 } 7146 7147 String response = sb.toString(); 7148 logv("Supplicant Response -" + response); 7149 mWifiNative.simAuthResponse(requestData.networkId, response); 7150 } else { 7151 loge("could not get telephony manager"); 7152 } 7153 } 7154 7155 void handle3GAuthRequest(SimAuthRequestData requestData) { 7156 7157 } 7158} 7159