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