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 17 package android.net.wifi; 18 19 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; 20 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; 21 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; 22 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; 23 import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; 24 25 /** 26 * TODO: 27 * Deprecate WIFI_STATE_UNKNOWN 28 */ 29 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; 30 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; 31 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; 32 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; 33 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; 34 35 import android.app.AlarmManager; 36 import android.app.PendingIntent; 37 import android.app.backup.IBackupManager; 38 import android.bluetooth.BluetoothAdapter; 39 import android.content.BroadcastReceiver; 40 import android.content.Context; 41 import android.content.Intent; 42 import android.content.IntentFilter; 43 import android.content.pm.PackageManager; 44 import android.database.ContentObserver; 45 import android.net.ConnectivityManager; 46 import android.net.DhcpResults; 47 import android.net.DhcpStateMachine; 48 import android.net.InterfaceConfiguration; 49 import android.net.LinkAddress; 50 import android.net.LinkProperties; 51 import android.net.NetworkInfo; 52 import android.net.NetworkInfo.DetailedState; 53 import android.net.NetworkUtils; 54 import android.net.RouteInfo; 55 import android.net.wifi.WpsResult.Status; 56 import android.net.wifi.p2p.WifiP2pManager; 57 import android.net.wifi.p2p.WifiP2pService; 58 import android.os.BatteryStats; 59 import android.os.Binder; 60 import android.os.Bundle; 61 import android.os.IBinder; 62 import android.os.INetworkManagementService; 63 import android.os.Message; 64 import android.os.Messenger; 65 import android.os.PowerManager; 66 import android.os.Process; 67 import android.os.RemoteException; 68 import android.os.ServiceManager; 69 import android.os.SystemClock; 70 import android.os.SystemProperties; 71 import android.os.UserHandle; 72 import android.os.WorkSource; 73 import android.provider.Settings; 74 import android.util.Log; 75 import android.util.LruCache; 76 import android.text.TextUtils; 77 78 import com.android.internal.R; 79 import com.android.internal.app.IBatteryStats; 80 import com.android.internal.util.AsyncChannel; 81 import com.android.internal.util.Protocol; 82 import com.android.internal.util.State; 83 import com.android.internal.util.StateMachine; 84 85 import com.android.server.net.BaseNetworkObserver; 86 87 import java.io.FileDescriptor; 88 import java.io.PrintWriter; 89 import java.net.InetAddress; 90 import java.net.Inet6Address; 91 import java.util.ArrayList; 92 import java.util.List; 93 import java.util.Locale; 94 import java.util.concurrent.atomic.AtomicInteger; 95 import java.util.concurrent.atomic.AtomicBoolean; 96 import java.util.Iterator; 97 import java.util.regex.Pattern; 98 99 /** 100 * Track the state of Wifi connectivity. All event handling is done here, 101 * and all changes in connectivity state are initiated here. 102 * 103 * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p 104 * In the current implementation, we support concurrent wifi p2p and wifi operation. 105 * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService 106 * handles p2p operation. 107 * 108 * @hide 109 */ 110 public class WifiStateMachine extends StateMachine { 111 112 private static final String NETWORKTYPE = "WIFI"; 113 private static final boolean DBG = false; 114 115 private WifiMonitor mWifiMonitor; 116 private WifiNative mWifiNative; 117 private WifiConfigStore mWifiConfigStore; 118 private INetworkManagementService mNwService; 119 private ConnectivityManager mCm; 120 121 private final boolean mP2pSupported; 122 private final AtomicBoolean mP2pConnected = new AtomicBoolean(false); 123 private boolean mTemporarilyDisconnectWifi = false; 124 private final String mPrimaryDeviceType; 125 126 /* Scan results handling */ 127 private List<ScanResult> mScanResults = new ArrayList<ScanResult>(); 128 private static final Pattern scanResultPattern = Pattern.compile("\t+"); 129 private static final int SCAN_RESULT_CACHE_SIZE = 80; 130 private final LruCache<String, ScanResult> mScanResultCache; 131 132 /* Batch scan results */ 133 private final List<BatchedScanResult> mBatchedScanResults = 134 new ArrayList<BatchedScanResult>(); 135 private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE; 136 private int mExpectedBatchedScans = 0; 137 private long mBatchedScanMinPollTime = 0; 138 139 /* Chipset supports background scan */ 140 private final boolean mBackgroundScanSupported; 141 142 private String mInterfaceName; 143 /* Tethering interface could be separate from wlan interface */ 144 private String mTetherInterfaceName; 145 146 private int mLastSignalLevel = -1; 147 private String mLastBssid; 148 private int mLastNetworkId; 149 private boolean mEnableRssiPolling = false; 150 private boolean mEnableBackgroundScan = false; 151 private int mRssiPollToken = 0; 152 private int mReconnectCount = 0; 153 /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE 154 * In CONNECT_MODE, the STA can scan and connect to an access point 155 * In SCAN_ONLY_MODE, the STA can only scan for access points 156 * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off 157 */ 158 private int mOperationalMode = CONNECT_MODE; 159 private boolean mScanResultIsPending = false; 160 private WorkSource mScanWorkSource = null; 161 private static final int UNKNOWN_SCAN_SOURCE = -1; 162 /* Tracks if state machine has received any screen state change broadcast yet. 163 * We can miss one of these at boot. 164 */ 165 private AtomicBoolean mScreenBroadcastReceived = new AtomicBoolean(false); 166 167 private boolean mBluetoothConnectionActive = false; 168 169 private PowerManager.WakeLock mSuspendWakeLock; 170 171 /** 172 * Interval in milliseconds between polling for RSSI 173 * and linkspeed information 174 */ 175 private static final int POLL_RSSI_INTERVAL_MSECS = 3000; 176 177 /** 178 * Delay between supplicant restarts upon failure to establish connection 179 */ 180 private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000; 181 182 /** 183 * Number of times we attempt to restart supplicant 184 */ 185 private static final int SUPPLICANT_RESTART_TRIES = 5; 186 187 private int mSupplicantRestartCount = 0; 188 /* Tracks sequence number on stop failure message */ 189 private int mSupplicantStopFailureToken = 0; 190 191 /** 192 * Tether state change notification time out 193 */ 194 private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000; 195 196 /* Tracks sequence number on a tether notification time out */ 197 private int mTetherToken = 0; 198 199 /** 200 * Driver start time out. 201 */ 202 private static final int DRIVER_START_TIME_OUT_MSECS = 10000; 203 204 /* Tracks sequence number on a driver time out */ 205 private int mDriverStartToken = 0; 206 207 /** 208 * The link properties of the wifi interface. 209 * Do not modify this directly; use updateLinkProperties instead. 210 */ 211 private LinkProperties mLinkProperties; 212 213 /** 214 * Subset of link properties coming from netlink. 215 * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers 216 * and domains obtained from router advertisements (RFC 6106). 217 */ 218 private final LinkProperties mNetlinkLinkProperties; 219 220 /* Tracks sequence number on a periodic scan message */ 221 private int mPeriodicScanToken = 0; 222 223 // Wakelock held during wifi start/stop and driver load/unload 224 private PowerManager.WakeLock mWakeLock; 225 226 private Context mContext; 227 228 private final Object mDhcpResultsLock = new Object(); 229 private DhcpResults mDhcpResults; 230 private WifiInfo mWifiInfo; 231 private NetworkInfo mNetworkInfo; 232 private SupplicantStateTracker mSupplicantStateTracker; 233 private DhcpStateMachine mDhcpStateMachine; 234 private boolean mDhcpActive = false; 235 236 private final AtomicInteger mCountryCodeSequence = new AtomicInteger(); 237 238 private class InterfaceObserver extends BaseNetworkObserver { 239 private WifiStateMachine mWifiStateMachine; 240 241 InterfaceObserver(WifiStateMachine wifiStateMachine) { 242 super(); 243 mWifiStateMachine = wifiStateMachine; 244 } 245 246 @Override 247 public void addressUpdated(String address, String iface, int flags, int scope) { 248 if (mWifiStateMachine.mInterfaceName.equals(iface)) { 249 if (DBG) { 250 log("addressUpdated: " + address + " on " + iface + 251 " flags " + flags + " scope " + scope); 252 } 253 mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_UPDATED, new LinkAddress(address)); 254 } 255 } 256 257 @Override 258 public void addressRemoved(String address, String iface, int flags, int scope) { 259 if (mWifiStateMachine.mInterfaceName.equals(iface)) { 260 if (DBG) { 261 log("addressRemoved: " + address + " on " + iface + 262 " flags " + flags + " scope " + scope); 263 } 264 mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_REMOVED, new LinkAddress(address)); 265 } 266 } 267 } 268 269 private InterfaceObserver mInterfaceObserver; 270 271 private AlarmManager mAlarmManager; 272 private PendingIntent mScanIntent; 273 private PendingIntent mDriverStopIntent; 274 private PendingIntent mBatchedScanIntervalIntent; 275 276 /* Tracks current frequency mode */ 277 private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO); 278 279 /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */ 280 private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true); 281 282 // Channel for sending replies. 283 private AsyncChannel mReplyChannel = new AsyncChannel(); 284 285 private WifiP2pManager mWifiP2pManager; 286 //Used to initiate a connection with WifiP2pService 287 private AsyncChannel mWifiP2pChannel; 288 private AsyncChannel mWifiApConfigChannel; 289 290 /* The base for wifi message types */ 291 static final int BASE = Protocol.BASE_WIFI; 292 /* Start the supplicant */ 293 static final int CMD_START_SUPPLICANT = BASE + 11; 294 /* Stop the supplicant */ 295 static final int CMD_STOP_SUPPLICANT = BASE + 12; 296 /* Start the driver */ 297 static final int CMD_START_DRIVER = BASE + 13; 298 /* Stop the driver */ 299 static final int CMD_STOP_DRIVER = BASE + 14; 300 /* Indicates Static IP succeeded */ 301 static final int CMD_STATIC_IP_SUCCESS = BASE + 15; 302 /* Indicates Static IP failed */ 303 static final int CMD_STATIC_IP_FAILURE = BASE + 16; 304 /* Indicates supplicant stop failed */ 305 static final int CMD_STOP_SUPPLICANT_FAILED = BASE + 17; 306 /* Delayed stop to avoid shutting down driver too quick*/ 307 static final int CMD_DELAYED_STOP_DRIVER = BASE + 18; 308 /* A delayed message sent to start driver when it fail to come up */ 309 static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19; 310 /* Ready to switch to network as default */ 311 static final int CMD_CAPTIVE_CHECK_COMPLETE = BASE + 20; 312 313 /* Start the soft access point */ 314 static final int CMD_START_AP = BASE + 21; 315 /* Indicates soft ap start succeeded */ 316 static final int CMD_START_AP_SUCCESS = BASE + 22; 317 /* Indicates soft ap start failed */ 318 static final int CMD_START_AP_FAILURE = BASE + 23; 319 /* Stop the soft access point */ 320 static final int CMD_STOP_AP = BASE + 24; 321 /* Set the soft access point configuration */ 322 static final int CMD_SET_AP_CONFIG = BASE + 25; 323 /* Soft access point configuration set completed */ 324 static final int CMD_SET_AP_CONFIG_COMPLETED = BASE + 26; 325 /* Request the soft access point configuration */ 326 static final int CMD_REQUEST_AP_CONFIG = BASE + 27; 327 /* Response to access point configuration request */ 328 static final int CMD_RESPONSE_AP_CONFIG = BASE + 28; 329 /* Invoked when getting a tether state change notification */ 330 static final int CMD_TETHER_STATE_CHANGE = BASE + 29; 331 /* A delayed message sent to indicate tether state change failed to arrive */ 332 static final int CMD_TETHER_NOTIFICATION_TIMED_OUT = BASE + 30; 333 334 static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31; 335 336 /* Supplicant commands */ 337 /* Is supplicant alive ? */ 338 static final int CMD_PING_SUPPLICANT = BASE + 51; 339 /* Add/update a network configuration */ 340 static final int CMD_ADD_OR_UPDATE_NETWORK = BASE + 52; 341 /* Delete a network */ 342 static final int CMD_REMOVE_NETWORK = BASE + 53; 343 /* Enable a network. The device will attempt a connection to the given network. */ 344 static final int CMD_ENABLE_NETWORK = BASE + 54; 345 /* Enable all networks */ 346 static final int CMD_ENABLE_ALL_NETWORKS = BASE + 55; 347 /* Blacklist network. De-prioritizes the given BSSID for connection. */ 348 static final int CMD_BLACKLIST_NETWORK = BASE + 56; 349 /* Clear the blacklist network list */ 350 static final int CMD_CLEAR_BLACKLIST = BASE + 57; 351 /* Save configuration */ 352 static final int CMD_SAVE_CONFIG = BASE + 58; 353 /* Get configured networks*/ 354 static final int CMD_GET_CONFIGURED_NETWORKS = BASE + 59; 355 356 /* Supplicant commands after driver start*/ 357 /* Initiate a scan */ 358 static final int CMD_START_SCAN = BASE + 71; 359 /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */ 360 static final int CMD_SET_OPERATIONAL_MODE = BASE + 72; 361 /* Disconnect from a network */ 362 static final int CMD_DISCONNECT = BASE + 73; 363 /* Reconnect to a network */ 364 static final int CMD_RECONNECT = BASE + 74; 365 /* Reassociate to a network */ 366 static final int CMD_REASSOCIATE = BASE + 75; 367 /* Controls suspend mode optimizations 368 * 369 * When high perf mode is enabled, suspend mode optimizations are disabled 370 * 371 * When high perf mode is disabled, suspend mode optimizations are enabled 372 * 373 * Suspend mode optimizations include: 374 * - packet filtering 375 * - turn off roaming 376 * - DTIM wake up settings 377 */ 378 static final int CMD_SET_HIGH_PERF_MODE = BASE + 77; 379 /* Set the country code */ 380 static final int CMD_SET_COUNTRY_CODE = BASE + 80; 381 /* Enables RSSI poll */ 382 static final int CMD_ENABLE_RSSI_POLL = BASE + 82; 383 /* RSSI poll */ 384 static final int CMD_RSSI_POLL = BASE + 83; 385 /* Set up packet filtering */ 386 static final int CMD_START_PACKET_FILTERING = BASE + 84; 387 /* Clear packet filter */ 388 static final int CMD_STOP_PACKET_FILTERING = BASE + 85; 389 /* Enable suspend mode optimizations in the driver */ 390 static final int CMD_SET_SUSPEND_OPT_ENABLED = BASE + 86; 391 /* When there are no saved networks, we do a periodic scan to notify user of 392 * an open network */ 393 static final int CMD_NO_NETWORKS_PERIODIC_SCAN = BASE + 88; 394 395 /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */ 396 static final int MULTICAST_V6 = 1; 397 static final int MULTICAST_V4 = 0; 398 399 /* Set the frequency band */ 400 static final int CMD_SET_FREQUENCY_BAND = BASE + 90; 401 /* Enable background scan for configured networks */ 402 static final int CMD_ENABLE_BACKGROUND_SCAN = BASE + 91; 403 /* Enable TDLS on a specific MAC address */ 404 static final int CMD_ENABLE_TDLS = BASE + 92; 405 406 /* Commands from/to the SupplicantStateTracker */ 407 /* Reset the supplicant state tracker */ 408 static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111; 409 410 /* P2p commands */ 411 /* We are ok with no response here since we wont do much with it anyway */ 412 public static final int CMD_ENABLE_P2P = BASE + 131; 413 /* In order to shut down supplicant cleanly, we wait till p2p has 414 * been disabled */ 415 public static final int CMD_DISABLE_P2P_REQ = BASE + 132; 416 public static final int CMD_DISABLE_P2P_RSP = BASE + 133; 417 418 public static final int CMD_BOOT_COMPLETED = BASE + 134; 419 420 /* change the batch scan settings. 421 * arg1 = responsible UID 422 * arg2 = csph (channel scans per hour) 423 * obj = bundle with the new settings and the optional worksource 424 */ 425 public static final int CMD_SET_BATCHED_SCAN = BASE + 135; 426 public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136; 427 public static final int CMD_POLL_BATCHED_SCAN = BASE + 137; 428 429 /* Link configuration (IP address, DNS, ...) changes */ 430 /* An new IP address was added to our interface, or an existing IP address was updated */ 431 static final int CMD_IP_ADDRESS_UPDATED = BASE + 140; 432 /* An IP address was removed from our interface */ 433 static final int CMD_IP_ADDRESS_REMOVED = BASE + 141; 434 /* Reload all networks and reconnect */ 435 static final int CMD_RELOAD_TLS_AND_RECONNECT = BASE + 142; 436 437 /* Wifi state machine modes of operation */ 438 /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ 439 public static final int CONNECT_MODE = 1; 440 /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */ 441 public static final int SCAN_ONLY_MODE = 2; 442 /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */ 443 public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3; 444 445 private static final int SUCCESS = 1; 446 private static final int FAILURE = -1; 447 448 /** 449 * The maximum number of times we will retry a connection to an access point 450 * for which we have failed in acquiring an IP address from DHCP. A value of 451 * N means that we will make N+1 connection attempts in all. 452 * <p> 453 * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default 454 * value if a Settings value is not present. 455 */ 456 private static final int DEFAULT_MAX_DHCP_RETRIES = 9; 457 458 /* Tracks if suspend optimizations need to be disabled by DHCP, 459 * screen or due to high perf mode. 460 * When any of them needs to disable it, we keep the suspend optimizations 461 * disabled 462 */ 463 private int mSuspendOptNeedsDisabled = 0; 464 465 private static final int SUSPEND_DUE_TO_DHCP = 1; 466 private static final int SUSPEND_DUE_TO_HIGH_PERF = 1<<1; 467 private static final int SUSPEND_DUE_TO_SCREEN = 1<<2; 468 469 /* Tracks if user has enabled suspend optimizations through settings */ 470 private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true); 471 472 /** 473 * Default framework scan interval in milliseconds. This is used in the scenario in which 474 * wifi chipset does not support background scanning to set up a 475 * periodic wake up scan so that the device can connect to a new access 476 * point on the move. {@link Settings.Global#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can 477 * override this. 478 */ 479 private final int mDefaultFrameworkScanIntervalMs; 480 481 /** 482 * Supplicant scan interval in milliseconds. 483 * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or 484 * from the default config if the setting is not set 485 */ 486 private long mSupplicantScanIntervalMs; 487 488 /** 489 * Minimum time interval between enabling all networks. 490 * A device can end up repeatedly connecting to a bad network on screen on/off toggle 491 * due to enabling every time. We add a threshold to avoid this. 492 */ 493 private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */ 494 private long mLastEnableAllNetworksTime; 495 496 /** 497 * Starting and shutting down driver too quick causes problems leading to driver 498 * being in a bad state. Delay driver stop. 499 */ 500 private final int mDriverStopDelayMs; 501 private int mDelayedStopCounter; 502 private boolean mInDelayedStop = false; 503 504 // sometimes telephony gives us this data before boot is complete and we can't store it 505 // until after, so the write is deferred 506 private volatile String mPersistedCountryCode; 507 508 // Supplicant doesn't like setting the same country code multiple times (it may drop 509 // currently connected network), so we save the country code here to avoid redundency 510 private String mLastSetCountryCode; 511 512 private static final int MIN_RSSI = -200; 513 private static final int MAX_RSSI = 256; 514 515 /* Default parent state */ 516 private State mDefaultState = new DefaultState(); 517 /* Temporary initial state */ 518 private State mInitialState = new InitialState(); 519 /* Driver loaded, waiting for supplicant to start */ 520 private State mSupplicantStartingState = new SupplicantStartingState(); 521 /* Driver loaded and supplicant ready */ 522 private State mSupplicantStartedState = new SupplicantStartedState(); 523 /* Waiting for supplicant to stop and monitor to exit */ 524 private State mSupplicantStoppingState = new SupplicantStoppingState(); 525 /* Driver start issued, waiting for completed event */ 526 private State mDriverStartingState = new DriverStartingState(); 527 /* Driver started */ 528 private State mDriverStartedState = new DriverStartedState(); 529 /* Wait until p2p is disabled 530 * This is a special state which is entered right after we exit out of DriverStartedState 531 * before transitioning to another state. 532 */ 533 private State mWaitForP2pDisableState = new WaitForP2pDisableState(); 534 /* Driver stopping */ 535 private State mDriverStoppingState = new DriverStoppingState(); 536 /* Driver stopped */ 537 private State mDriverStoppedState = new DriverStoppedState(); 538 /* Scan for networks, no connection will be established */ 539 private State mScanModeState = new ScanModeState(); 540 /* Connecting to an access point */ 541 private State mConnectModeState = new ConnectModeState(); 542 /* Connected at 802.11 (L2) level */ 543 private State mL2ConnectedState = new L2ConnectedState(); 544 /* fetching IP after connection to access point (assoc+auth complete) */ 545 private State mObtainingIpState = new ObtainingIpState(); 546 /* Waiting for link quality verification to be complete */ 547 private State mVerifyingLinkState = new VerifyingLinkState(); 548 /* Waiting for captive portal check to be complete */ 549 private State mCaptivePortalCheckState = new CaptivePortalCheckState(); 550 /* Connected with IP addr */ 551 private State mConnectedState = new ConnectedState(); 552 /* disconnect issued, waiting for network disconnect confirmation */ 553 private State mDisconnectingState = new DisconnectingState(); 554 /* Network is not connected, supplicant assoc+auth is not complete */ 555 private State mDisconnectedState = new DisconnectedState(); 556 /* Waiting for WPS to be completed*/ 557 private State mWpsRunningState = new WpsRunningState(); 558 559 /* Soft ap is starting up */ 560 private State mSoftApStartingState = new SoftApStartingState(); 561 /* Soft ap is running */ 562 private State mSoftApStartedState = new SoftApStartedState(); 563 /* Soft ap is running and we are waiting for tether notification */ 564 private State mTetheringState = new TetheringState(); 565 /* Soft ap is running and we are tethered through connectivity service */ 566 private State mTetheredState = new TetheredState(); 567 /* Waiting for untether confirmation before stopping soft Ap */ 568 private State mUntetheringState = new UntetheringState(); 569 570 private class TetherStateChange { 571 ArrayList<String> available; 572 ArrayList<String> active; 573 TetherStateChange(ArrayList<String> av, ArrayList<String> ac) { 574 available = av; 575 active = ac; 576 } 577 } 578 579 580 /** 581 * One of {@link WifiManager#WIFI_STATE_DISABLED}, 582 * {@link WifiManager#WIFI_STATE_DISABLING}, 583 * {@link WifiManager#WIFI_STATE_ENABLED}, 584 * {@link WifiManager#WIFI_STATE_ENABLING}, 585 * {@link WifiManager#WIFI_STATE_UNKNOWN} 586 * 587 */ 588 private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED); 589 590 /** 591 * One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 592 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 593 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 594 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 595 * {@link WifiManager#WIFI_AP_STATE_FAILED} 596 * 597 */ 598 private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED); 599 600 private static final int SCAN_REQUEST = 0; 601 private static final String ACTION_START_SCAN = 602 "com.android.server.WifiManager.action.START_SCAN"; 603 604 private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter"; 605 private static final int DRIVER_STOP_REQUEST = 0; 606 private static final String ACTION_DELAYED_DRIVER_STOP = 607 "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP"; 608 609 private static final String ACTION_REFRESH_BATCHED_SCAN = 610 "com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN"; 611 /** 612 * Keep track of whether WIFI is running. 613 */ 614 private boolean mIsRunning = false; 615 616 /** 617 * Keep track of whether we last told the battery stats we had started. 618 */ 619 private boolean mReportedRunning = false; 620 621 /** 622 * Most recently set source of starting WIFI. 623 */ 624 private final WorkSource mRunningWifiUids = new WorkSource(); 625 626 /** 627 * The last reported UIDs that were responsible for starting WIFI. 628 */ 629 private final WorkSource mLastRunningWifiUids = new WorkSource(); 630 631 private final IBatteryStats mBatteryStats; 632 633 private BatchedScanSettings mBatchedScanSettings = null; 634 635 /** 636 * Track the worksource/cost of the current settings and track what's been noted 637 * to the battery stats, so we can mark the end of the previous when changing. 638 */ 639 private WorkSource mBatchedScanWorkSource = null; 640 private int mBatchedScanCsph = 0; 641 private WorkSource mNotedBatchedScanWorkSource = null; 642 private int mNotedBatchedScanCsph = 0; 643 644 645 public WifiStateMachine(Context context, String wlanInterface) { 646 super("WifiStateMachine"); 647 mContext = context; 648 mInterfaceName = wlanInterface; 649 650 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); 651 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 652 BatteryStats.SERVICE_NAME)); 653 654 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 655 mNwService = INetworkManagementService.Stub.asInterface(b); 656 657 mP2pSupported = mContext.getPackageManager().hasSystemFeature( 658 PackageManager.FEATURE_WIFI_DIRECT); 659 660 mWifiNative = new WifiNative(mInterfaceName); 661 mWifiConfigStore = new WifiConfigStore(context, mWifiNative); 662 mWifiMonitor = new WifiMonitor(this, mWifiNative); 663 mWifiInfo = new WifiInfo(); 664 mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, 665 getHandler()); 666 mLinkProperties = new LinkProperties(); 667 mNetlinkLinkProperties = new LinkProperties(); 668 669 mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE); 670 671 mNetworkInfo.setIsAvailable(false); 672 mLastBssid = null; 673 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 674 mLastSignalLevel = -1; 675 676 mInterfaceObserver = new InterfaceObserver(this); 677 try { 678 mNwService.registerObserver(mInterfaceObserver); 679 } catch (RemoteException e) { 680 loge("Couldn't register interface observer: " + e.toString()); 681 } 682 683 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 684 Intent scanIntent = new Intent(ACTION_START_SCAN, null); 685 mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0); 686 687 Intent batchedIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null); 688 mBatchedScanIntervalIntent = PendingIntent.getBroadcast(mContext, 0, batchedIntent, 0); 689 690 mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger( 691 R.integer.config_wifi_framework_scan_interval); 692 693 mDriverStopDelayMs = mContext.getResources().getInteger( 694 R.integer.config_wifi_driver_stop_delay); 695 696 mBackgroundScanSupported = mContext.getResources().getBoolean( 697 R.bool.config_wifi_background_scan_support); 698 699 mPrimaryDeviceType = mContext.getResources().getString( 700 R.string.config_wifi_p2p_device_type); 701 702 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 703 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 704 705 mContext.registerReceiver( 706 new BroadcastReceiver() { 707 @Override 708 public void onReceive(Context context, Intent intent) { 709 ArrayList<String> available = intent.getStringArrayListExtra( 710 ConnectivityManager.EXTRA_AVAILABLE_TETHER); 711 ArrayList<String> active = intent.getStringArrayListExtra( 712 ConnectivityManager.EXTRA_ACTIVE_TETHER); 713 sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active)); 714 } 715 },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); 716 717 mContext.registerReceiver( 718 new BroadcastReceiver() { 719 @Override 720 public void onReceive(Context context, Intent intent) { 721 final WorkSource workSource = null; 722 startScan(UNKNOWN_SCAN_SOURCE, workSource); 723 } 724 }, 725 new IntentFilter(ACTION_START_SCAN)); 726 727 IntentFilter filter = new IntentFilter(); 728 filter.addAction(Intent.ACTION_SCREEN_ON); 729 filter.addAction(Intent.ACTION_SCREEN_OFF); 730 filter.addAction(ACTION_REFRESH_BATCHED_SCAN); 731 mContext.registerReceiver( 732 new BroadcastReceiver() { 733 @Override 734 public void onReceive(Context context, Intent intent) { 735 String action = intent.getAction(); 736 737 if (action.equals(Intent.ACTION_SCREEN_ON)) { 738 handleScreenStateChanged(true); 739 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 740 handleScreenStateChanged(false); 741 } else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) { 742 startNextBatchedScanAsync(); 743 } 744 } 745 }, filter); 746 747 mContext.registerReceiver( 748 new BroadcastReceiver() { 749 @Override 750 public void onReceive(Context context, Intent intent) { 751 int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0); 752 sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0); 753 } 754 }, 755 new IntentFilter(ACTION_DELAYED_DRIVER_STOP)); 756 757 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 758 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false, 759 new ContentObserver(getHandler()) { 760 @Override 761 public void onChange(boolean selfChange) { 762 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 763 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 764 } 765 }); 766 767 mContext.registerReceiver( 768 new BroadcastReceiver() { 769 @Override 770 public void onReceive(Context context, Intent intent) { 771 sendMessage(CMD_BOOT_COMPLETED); 772 } 773 }, 774 new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); 775 776 mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE); 777 778 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 779 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName()); 780 781 mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend"); 782 mSuspendWakeLock.setReferenceCounted(false); 783 784 addState(mDefaultState); 785 addState(mInitialState, mDefaultState); 786 addState(mSupplicantStartingState, mDefaultState); 787 addState(mSupplicantStartedState, mDefaultState); 788 addState(mDriverStartingState, mSupplicantStartedState); 789 addState(mDriverStartedState, mSupplicantStartedState); 790 addState(mScanModeState, mDriverStartedState); 791 addState(mConnectModeState, mDriverStartedState); 792 addState(mL2ConnectedState, mConnectModeState); 793 addState(mObtainingIpState, mL2ConnectedState); 794 addState(mVerifyingLinkState, mL2ConnectedState); 795 addState(mCaptivePortalCheckState, mL2ConnectedState); 796 addState(mConnectedState, mL2ConnectedState); 797 addState(mDisconnectingState, mConnectModeState); 798 addState(mDisconnectedState, mConnectModeState); 799 addState(mWpsRunningState, mConnectModeState); 800 addState(mWaitForP2pDisableState, mSupplicantStartedState); 801 addState(mDriverStoppingState, mSupplicantStartedState); 802 addState(mDriverStoppedState, mSupplicantStartedState); 803 addState(mSupplicantStoppingState, mDefaultState); 804 addState(mSoftApStartingState, mDefaultState); 805 addState(mSoftApStartedState, mDefaultState); 806 addState(mTetheringState, mSoftApStartedState); 807 addState(mTetheredState, mSoftApStartedState); 808 addState(mUntetheringState, mSoftApStartedState); 809 810 setInitialState(mInitialState); 811 812 setLogRecSize(2000); 813 setLogOnlyTransitions(false); 814 if (DBG) setDbg(true); 815 816 //start the state machine 817 start(); 818 819 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 820 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 821 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 822 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 823 } 824 825 /********************************************************* 826 * Methods exposed for public use 827 ********************************************************/ 828 829 public Messenger getMessenger() { 830 return new Messenger(getHandler()); 831 } 832 /** 833 * TODO: doc 834 */ 835 public boolean syncPingSupplicant(AsyncChannel channel) { 836 Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT); 837 boolean result = (resultMsg.arg1 != FAILURE); 838 resultMsg.recycle(); 839 return result; 840 } 841 842 /** 843 * Initiate a wifi scan. If workSource is not null, blame is given to it, 844 * otherwise blame is given to callingUid. 845 * 846 * @param callingUid The uid initiating the wifi scan. Blame will be given 847 * here unless workSource is specified. 848 * @param workSource If not null, blame is given to workSource. 849 */ 850 public void startScan(int callingUid, WorkSource workSource) { 851 sendMessage(CMD_START_SCAN, callingUid, 0, workSource); 852 } 853 854 /** 855 * start or stop batched scanning using the given settings 856 */ 857 private static final String BATCHED_SETTING = "batched_settings"; 858 private static final String BATCHED_WORKSOURCE = "batched_worksource"; 859 public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph, 860 WorkSource workSource) { 861 Bundle bundle = new Bundle(); 862 bundle.putParcelable(BATCHED_SETTING, settings); 863 bundle.putParcelable(BATCHED_WORKSOURCE, workSource); 864 sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle); 865 } 866 867 public List<BatchedScanResult> syncGetBatchedScanResultsList() { 868 synchronized (mBatchedScanResults) { 869 List<BatchedScanResult> batchedScanList = 870 new ArrayList<BatchedScanResult>(mBatchedScanResults.size()); 871 for(BatchedScanResult result: mBatchedScanResults) { 872 batchedScanList.add(new BatchedScanResult(result)); 873 } 874 return batchedScanList; 875 } 876 } 877 878 public void requestBatchedScanPoll() { 879 sendMessage(CMD_POLL_BATCHED_SCAN); 880 } 881 882 private void startBatchedScan() { 883 if (mBatchedScanSettings == null) return; 884 885 if (mDhcpActive) { 886 if (DBG) log("not starting Batched Scans due to DHCP"); 887 return; 888 } 889 890 // first grab any existing data 891 retrieveBatchedScanData(); 892 893 mAlarmManager.cancel(mBatchedScanIntervalIntent); 894 895 String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings); 896 try { 897 mExpectedBatchedScans = Integer.parseInt(scansExpected); 898 setNextBatchedAlarm(mExpectedBatchedScans); 899 if (mExpectedBatchedScans > 0) noteBatchedScanStart(); 900 } catch (NumberFormatException e) { 901 stopBatchedScan(); 902 loge("Exception parsing WifiNative.setBatchedScanSettings response " + e); 903 } 904 } 905 906 // called from BroadcastListener 907 private void startNextBatchedScanAsync() { 908 sendMessage(CMD_START_NEXT_BATCHED_SCAN); 909 } 910 911 private void startNextBatchedScan() { 912 // first grab any existing data 913 retrieveBatchedScanData(); 914 915 setNextBatchedAlarm(mExpectedBatchedScans); 916 } 917 918 private void handleBatchedScanPollRequest() { 919 if (DBG) { 920 log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" + 921 mBatchedScanMinPollTime + " , mBatchedScanSettings=" + 922 mBatchedScanSettings); 923 } 924 // if there is no appropriate PollTime that's because we either aren't 925 // batching or we've already set a time for a poll request 926 if (mBatchedScanMinPollTime == 0) return; 927 if (mBatchedScanSettings == null) return; 928 929 long now = System.currentTimeMillis(); 930 931 if (now > mBatchedScanMinPollTime) { 932 // do the poll and reset our timers 933 startNextBatchedScan(); 934 } else { 935 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime, 936 mBatchedScanIntervalIntent); 937 mBatchedScanMinPollTime = 0; 938 } 939 } 940 941 // return true if new/different 942 private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) { 943 BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING); 944 WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE); 945 946 if (DBG) { 947 log("set batched scan to " + settings + " for uid=" + responsibleUid + 948 ", worksource=" + responsibleWorkSource); 949 } 950 if (settings != null) { 951 if (settings.equals(mBatchedScanSettings)) return false; 952 } else { 953 if (mBatchedScanSettings == null) return false; 954 } 955 mBatchedScanSettings = settings; 956 if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid); 957 mBatchedScanWorkSource = responsibleWorkSource; 958 mBatchedScanCsph = csph; 959 return true; 960 } 961 962 private void stopBatchedScan() { 963 mAlarmManager.cancel(mBatchedScanIntervalIntent); 964 retrieveBatchedScanData(); 965 mWifiNative.setBatchedScanSettings(null); 966 noteBatchedScanStop(); 967 } 968 969 private void setNextBatchedAlarm(int scansExpected) { 970 971 if (mBatchedScanSettings == null || scansExpected < 1) return; 972 973 mBatchedScanMinPollTime = System.currentTimeMillis() + 974 mBatchedScanSettings.scanIntervalSec * 1000; 975 976 if (mBatchedScanSettings.maxScansPerBatch < scansExpected) { 977 scansExpected = mBatchedScanSettings.maxScansPerBatch; 978 } 979 980 int secToFull = mBatchedScanSettings.scanIntervalSec; 981 secToFull *= scansExpected; 982 983 int debugPeriod = SystemProperties.getInt("wifi.batchedScan.pollPeriod", 0); 984 if (debugPeriod > 0) secToFull = debugPeriod; 985 986 // set the alarm to do the next poll. We set it a little short as we'd rather 987 // wake up wearly than miss a scan due to buffer overflow 988 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 989 + ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000), 990 mBatchedScanIntervalIntent); 991 } 992 993 /** 994 * Start reading new scan data 995 * Data comes in as: 996 * "scancount=5\n" 997 * "nextcount=5\n" 998 * "apcount=3\n" 999 * "trunc\n" (optional) 1000 * "bssid=...\n" 1001 * "ssid=...\n" 1002 * "freq=...\n" (in Mhz) 1003 * "level=...\n" 1004 * "dist=...\n" (in cm) 1005 * "distsd=...\n" (standard deviation, in cm) 1006 * "====" 1007 * "bssid=...\n" 1008 * etc 1009 * "====" 1010 * "bssid=...\n" 1011 * etc 1012 * "%%%%" 1013 * "apcount=2\n" 1014 * "bssid=...\n" 1015 * etc 1016 * "%%%% 1017 * etc 1018 * "----" 1019 */ 1020 private final static boolean DEBUG_PARSE = false; 1021 private void retrieveBatchedScanData() { 1022 String rawData = mWifiNative.getBatchedScanResults(); 1023 if (DEBUG_PARSE) log("rawData = " + rawData); 1024 mBatchedScanMinPollTime = 0; 1025 if (rawData == null || rawData.equalsIgnoreCase("OK")) { 1026 loge("Unexpected BatchedScanResults :" + rawData); 1027 return; 1028 } 1029 1030 int scanCount = 0; 1031 final String END_OF_BATCHES = "----"; 1032 final String SCANCOUNT = "scancount="; 1033 final String TRUNCATED = "trunc"; 1034 final String AGE = "age="; 1035 final String DIST = "dist="; 1036 final String DISTSD = "distSd="; 1037 1038 String splitData[] = rawData.split("\n"); 1039 int n = 0; 1040 if (splitData[n].startsWith(SCANCOUNT)) { 1041 try { 1042 scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length())); 1043 } catch (NumberFormatException e) { 1044 loge("scancount parseInt Exception from " + splitData[n]); 1045 } 1046 } else log("scancount not found"); 1047 if (scanCount == 0) { 1048 loge("scanCount==0 - aborting"); 1049 return; 1050 } 1051 1052 final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION); 1053 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1054 1055 synchronized (mBatchedScanResults) { 1056 mBatchedScanResults.clear(); 1057 BatchedScanResult batchedScanResult = new BatchedScanResult(); 1058 1059 String bssid = null; 1060 WifiSsid wifiSsid = null; 1061 int level = 0; 1062 int freq = 0; 1063 int dist, distSd; 1064 long tsf = 0; 1065 dist = distSd = ScanResult.UNSPECIFIED; 1066 final long now = SystemClock.elapsedRealtime(); 1067 final int bssidStrLen = BSSID_STR.length(); 1068 1069 while (true) { 1070 while (n < splitData.length) { 1071 if (DEBUG_PARSE) logd("parsing " + splitData[n]); 1072 if (splitData[n].equals(END_OF_BATCHES)) { 1073 if (n+1 != splitData.length) { 1074 loge("didn't consume " + (splitData.length-n)); 1075 } 1076 if (mBatchedScanResults.size() > 0) { 1077 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1078 } 1079 logd("retrieveBatchedScanResults X"); 1080 return; 1081 } 1082 if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) { 1083 if (bssid != null) { 1084 batchedScanResult.scanResults.add(new ScanResult( 1085 wifiSsid, bssid, "", level, freq, tsf, dist, distSd)); 1086 wifiSsid = null; 1087 bssid = null; 1088 level = 0; 1089 freq = 0; 1090 tsf = 0; 1091 dist = distSd = ScanResult.UNSPECIFIED; 1092 } 1093 if (splitData[n].equals(END_STR)) { 1094 if (batchedScanResult.scanResults.size() != 0) { 1095 mBatchedScanResults.add(batchedScanResult); 1096 batchedScanResult = new BatchedScanResult(); 1097 } else { 1098 logd("Found empty batch"); 1099 } 1100 } 1101 } else if (splitData[n].equals(TRUNCATED)) { 1102 batchedScanResult.truncated = true; 1103 } else if (splitData[n].startsWith(BSSID_STR)) { 1104 bssid = new String(splitData[n].getBytes(), bssidStrLen, 1105 splitData[n].length() - bssidStrLen); 1106 } else if (splitData[n].startsWith(FREQ_STR)) { 1107 try { 1108 freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length())); 1109 } catch (NumberFormatException e) { 1110 loge("Invalid freqency: " + splitData[n]); 1111 freq = 0; 1112 } 1113 } else if (splitData[n].startsWith(AGE)) { 1114 try { 1115 tsf = now - Long.parseLong(splitData[n].substring(AGE.length())); 1116 tsf *= 1000; // convert mS -> uS 1117 } catch (NumberFormatException e) { 1118 loge("Invalid timestamp: " + splitData[n]); 1119 tsf = 0; 1120 } 1121 } else if (splitData[n].startsWith(SSID_STR)) { 1122 wifiSsid = WifiSsid.createFromAsciiEncoded( 1123 splitData[n].substring(SSID_STR.length())); 1124 } else if (splitData[n].startsWith(LEVEL_STR)) { 1125 try { 1126 level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length())); 1127 if (level > 0) level -= 256; 1128 } catch (NumberFormatException e) { 1129 loge("Invalid level: " + splitData[n]); 1130 level = 0; 1131 } 1132 } else if (splitData[n].startsWith(DIST)) { 1133 try { 1134 dist = Integer.parseInt(splitData[n].substring(DIST.length())); 1135 } catch (NumberFormatException e) { 1136 loge("Invalid distance: " + splitData[n]); 1137 dist = ScanResult.UNSPECIFIED; 1138 } 1139 } else if (splitData[n].startsWith(DISTSD)) { 1140 try { 1141 distSd = Integer.parseInt(splitData[n].substring(DISTSD.length())); 1142 } catch (NumberFormatException e) { 1143 loge("Invalid distanceSd: " + splitData[n]); 1144 distSd = ScanResult.UNSPECIFIED; 1145 } 1146 } else { 1147 loge("Unable to parse batched scan result line: " + splitData[n]); 1148 } 1149 n++; 1150 } 1151 rawData = mWifiNative.getBatchedScanResults(); 1152 if (DEBUG_PARSE) log("reading more data:\n" + rawData); 1153 if (rawData == null) { 1154 loge("Unexpected null BatchedScanResults"); 1155 return; 1156 } 1157 splitData = rawData.split("\n"); 1158 if (splitData.length == 0 || splitData[0].equals("ok")) { 1159 loge("batch scan results just ended!"); 1160 if (mBatchedScanResults.size() > 0) { 1161 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1162 } 1163 return; 1164 } 1165 n = 0; 1166 } 1167 } 1168 } 1169 1170 // If workSource is not null, blame is given to it, otherwise blame is given to callingUid. 1171 private void noteScanStart(int callingUid, WorkSource workSource) { 1172 if (mScanWorkSource == null && (callingUid != UNKNOWN_SCAN_SOURCE || workSource != null)) { 1173 mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid); 1174 try { 1175 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource); 1176 } catch (RemoteException e) { 1177 log(e.toString()); 1178 } 1179 } 1180 } 1181 1182 private void noteScanEnd() { 1183 if (mScanWorkSource != null) { 1184 try { 1185 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource); 1186 } catch (RemoteException e) { 1187 log(e.toString()); 1188 } finally { 1189 mScanWorkSource = null; 1190 } 1191 } 1192 } 1193 1194 private void noteBatchedScanStart() { 1195 // note the end of a previous scan set 1196 if (mNotedBatchedScanWorkSource != null && 1197 (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false || 1198 mNotedBatchedScanCsph != mBatchedScanCsph)) { 1199 try { 1200 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1201 } catch (RemoteException e) { 1202 log(e.toString()); 1203 } finally { 1204 mNotedBatchedScanWorkSource = null; 1205 mNotedBatchedScanCsph = 0; 1206 } 1207 } 1208 // note the start of the new 1209 try { 1210 mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource, 1211 mBatchedScanCsph); 1212 mNotedBatchedScanWorkSource = mBatchedScanWorkSource; 1213 mNotedBatchedScanCsph = mBatchedScanCsph; 1214 } catch (RemoteException e) { 1215 log(e.toString()); 1216 } 1217 } 1218 1219 private void noteBatchedScanStop() { 1220 if (mNotedBatchedScanWorkSource != null) { 1221 try { 1222 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1223 } catch (RemoteException e) { 1224 log(e.toString()); 1225 } finally { 1226 mNotedBatchedScanWorkSource = null; 1227 mNotedBatchedScanCsph = 0; 1228 } 1229 } 1230 } 1231 1232 private void startScanNative(int type) { 1233 mWifiNative.scan(type); 1234 mScanResultIsPending = true; 1235 } 1236 1237 /** 1238 * TODO: doc 1239 */ 1240 public void setSupplicantRunning(boolean enable) { 1241 if (enable) { 1242 sendMessage(CMD_START_SUPPLICANT); 1243 } else { 1244 sendMessage(CMD_STOP_SUPPLICANT); 1245 } 1246 } 1247 1248 /** 1249 * TODO: doc 1250 */ 1251 public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) { 1252 if (enable) { 1253 sendMessage(CMD_START_AP, wifiConfig); 1254 } else { 1255 sendMessage(CMD_STOP_AP); 1256 } 1257 } 1258 1259 public void setWifiApConfiguration(WifiConfiguration config) { 1260 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 1261 } 1262 1263 public WifiConfiguration syncGetWifiApConfiguration() { 1264 Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG); 1265 WifiConfiguration ret = (WifiConfiguration) resultMsg.obj; 1266 resultMsg.recycle(); 1267 return ret; 1268 } 1269 1270 /** 1271 * TODO: doc 1272 */ 1273 public int syncGetWifiState() { 1274 return mWifiState.get(); 1275 } 1276 1277 /** 1278 * TODO: doc 1279 */ 1280 public String syncGetWifiStateByName() { 1281 switch (mWifiState.get()) { 1282 case WIFI_STATE_DISABLING: 1283 return "disabling"; 1284 case WIFI_STATE_DISABLED: 1285 return "disabled"; 1286 case WIFI_STATE_ENABLING: 1287 return "enabling"; 1288 case WIFI_STATE_ENABLED: 1289 return "enabled"; 1290 case WIFI_STATE_UNKNOWN: 1291 return "unknown state"; 1292 default: 1293 return "[invalid state]"; 1294 } 1295 } 1296 1297 /** 1298 * TODO: doc 1299 */ 1300 public int syncGetWifiApState() { 1301 return mWifiApState.get(); 1302 } 1303 1304 /** 1305 * TODO: doc 1306 */ 1307 public String syncGetWifiApStateByName() { 1308 switch (mWifiApState.get()) { 1309 case WIFI_AP_STATE_DISABLING: 1310 return "disabling"; 1311 case WIFI_AP_STATE_DISABLED: 1312 return "disabled"; 1313 case WIFI_AP_STATE_ENABLING: 1314 return "enabling"; 1315 case WIFI_AP_STATE_ENABLED: 1316 return "enabled"; 1317 case WIFI_AP_STATE_FAILED: 1318 return "failed"; 1319 default: 1320 return "[invalid state]"; 1321 } 1322 } 1323 1324 /** 1325 * Get status information for the current connection, if any. 1326 * @return a {@link WifiInfo} object containing information about the current connection 1327 * 1328 */ 1329 public WifiInfo syncRequestConnectionInfo() { 1330 return mWifiInfo; 1331 } 1332 1333 public DhcpResults syncGetDhcpResults() { 1334 synchronized (mDhcpResultsLock) { 1335 return new DhcpResults(mDhcpResults); 1336 } 1337 } 1338 1339 /** 1340 * TODO: doc 1341 */ 1342 public void setDriverStart(boolean enable) { 1343 if (enable) { 1344 sendMessage(CMD_START_DRIVER); 1345 } else { 1346 sendMessage(CMD_STOP_DRIVER); 1347 } 1348 } 1349 1350 public void captivePortalCheckComplete() { 1351 sendMessage(CMD_CAPTIVE_CHECK_COMPLETE); 1352 } 1353 1354 /** 1355 * TODO: doc 1356 */ 1357 public void setOperationalMode(int mode) { 1358 if (DBG) log("setting operational mode to " + String.valueOf(mode)); 1359 sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0); 1360 } 1361 1362 /** 1363 * TODO: doc 1364 */ 1365 public List<ScanResult> syncGetScanResultsList() { 1366 synchronized (mScanResultCache) { 1367 List<ScanResult> scanList = new ArrayList<ScanResult>(); 1368 for(ScanResult result: mScanResults) { 1369 scanList.add(new ScanResult(result)); 1370 } 1371 return scanList; 1372 } 1373 } 1374 1375 /** 1376 * Disconnect from Access Point 1377 */ 1378 public void disconnectCommand() { 1379 sendMessage(CMD_DISCONNECT); 1380 } 1381 1382 /** 1383 * Initiate a reconnection to AP 1384 */ 1385 public void reconnectCommand() { 1386 sendMessage(CMD_RECONNECT); 1387 } 1388 1389 /** 1390 * Initiate a re-association to AP 1391 */ 1392 public void reassociateCommand() { 1393 sendMessage(CMD_REASSOCIATE); 1394 } 1395 1396 /** 1397 * Reload networks and then reconnect; helps load correct data for TLS networks 1398 */ 1399 1400 public void reloadTlsNetworksAndReconnect() { 1401 sendMessage(CMD_RELOAD_TLS_AND_RECONNECT); 1402 } 1403 1404 /** 1405 * Add a network synchronously 1406 * 1407 * @return network id of the new network 1408 */ 1409 public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) { 1410 Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config); 1411 int result = resultMsg.arg1; 1412 resultMsg.recycle(); 1413 return result; 1414 } 1415 1416 public List<WifiConfiguration> syncGetConfiguredNetworks(AsyncChannel channel) { 1417 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS); 1418 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 1419 resultMsg.recycle(); 1420 return result; 1421 } 1422 1423 /** 1424 * Delete a network 1425 * 1426 * @param networkId id of the network to be removed 1427 */ 1428 public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) { 1429 Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId); 1430 boolean result = (resultMsg.arg1 != FAILURE); 1431 resultMsg.recycle(); 1432 return result; 1433 } 1434 1435 /** 1436 * Enable a network 1437 * 1438 * @param netId network id of the network 1439 * @param disableOthers true, if all other networks have to be disabled 1440 * @return {@code true} if the operation succeeds, {@code false} otherwise 1441 */ 1442 public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) { 1443 Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId, 1444 disableOthers ? 1 : 0); 1445 boolean result = (resultMsg.arg1 != FAILURE); 1446 resultMsg.recycle(); 1447 return result; 1448 } 1449 1450 /** 1451 * Disable a network 1452 * 1453 * @param netId network id of the network 1454 * @return {@code true} if the operation succeeds, {@code false} otherwise 1455 */ 1456 public boolean syncDisableNetwork(AsyncChannel channel, int netId) { 1457 Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId); 1458 boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED); 1459 resultMsg.recycle(); 1460 return result; 1461 } 1462 1463 /** 1464 * Blacklist a BSSID. This will avoid the AP if there are 1465 * alternate APs to connect 1466 * 1467 * @param bssid BSSID of the network 1468 */ 1469 public void addToBlacklist(String bssid) { 1470 sendMessage(CMD_BLACKLIST_NETWORK, bssid); 1471 } 1472 1473 /** 1474 * Clear the blacklist list 1475 * 1476 */ 1477 public void clearBlacklist() { 1478 sendMessage(CMD_CLEAR_BLACKLIST); 1479 } 1480 1481 public void enableRssiPolling(boolean enabled) { 1482 sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0); 1483 } 1484 1485 public void enableBackgroundScanCommand(boolean enabled) { 1486 sendMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0); 1487 } 1488 1489 public void enableAllNetworks() { 1490 sendMessage(CMD_ENABLE_ALL_NETWORKS); 1491 } 1492 1493 /** 1494 * Start filtering Multicast v4 packets 1495 */ 1496 public void startFilteringMulticastV4Packets() { 1497 mFilteringMulticastV4Packets.set(true); 1498 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0); 1499 } 1500 1501 /** 1502 * Stop filtering Multicast v4 packets 1503 */ 1504 public void stopFilteringMulticastV4Packets() { 1505 mFilteringMulticastV4Packets.set(false); 1506 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0); 1507 } 1508 1509 /** 1510 * Start filtering Multicast v4 packets 1511 */ 1512 public void startFilteringMulticastV6Packets() { 1513 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0); 1514 } 1515 1516 /** 1517 * Stop filtering Multicast v4 packets 1518 */ 1519 public void stopFilteringMulticastV6Packets() { 1520 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0); 1521 } 1522 1523 /** 1524 * Set high performance mode of operation. 1525 * Enabling would set active power mode and disable suspend optimizations; 1526 * disabling would set auto power mode and enable suspend optimizations 1527 * @param enable true if enable, false otherwise 1528 */ 1529 public void setHighPerfModeEnabled(boolean enable) { 1530 sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0); 1531 } 1532 1533 /** 1534 * Set the country code 1535 * @param countryCode following ISO 3166 format 1536 * @param persist {@code true} if the setting should be remembered. 1537 */ 1538 public void setCountryCode(String countryCode, boolean persist) { 1539 // If it's a good country code, apply after the current 1540 // wifi connection is terminated; ignore resetting of code 1541 // for now (it is unclear what the chipset should do when 1542 // country code is reset) 1543 int countryCodeSequence = mCountryCodeSequence.incrementAndGet(); 1544 if (TextUtils.isEmpty(countryCode)) { 1545 log("Ignoring resetting of country code"); 1546 } else { 1547 sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, countryCode); 1548 } 1549 } 1550 1551 /** 1552 * Set the operational frequency band 1553 * @param band 1554 * @param persist {@code true} if the setting should be remembered. 1555 */ 1556 public void setFrequencyBand(int band, boolean persist) { 1557 if (persist) { 1558 Settings.Global.putInt(mContext.getContentResolver(), 1559 Settings.Global.WIFI_FREQUENCY_BAND, 1560 band); 1561 } 1562 sendMessage(CMD_SET_FREQUENCY_BAND, band, 0); 1563 } 1564 1565 /** 1566 * Enable TDLS for a specific MAC address 1567 */ 1568 public void enableTdls(String remoteMacAddress, boolean enable) { 1569 int enabler = enable ? 1 : 0; 1570 sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress); 1571 } 1572 1573 /** 1574 * Returns the operational frequency band 1575 */ 1576 public int getFrequencyBand() { 1577 return mFrequencyBand.get(); 1578 } 1579 1580 /** 1581 * Returns the wifi configuration file 1582 */ 1583 public String getConfigFile() { 1584 return mWifiConfigStore.getConfigFile(); 1585 } 1586 1587 /** 1588 * Send a message indicating bluetooth adapter connection state changed 1589 */ 1590 public void sendBluetoothAdapterStateChange(int state) { 1591 sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0); 1592 } 1593 1594 /** 1595 * Save configuration on supplicant 1596 * 1597 * @return {@code true} if the operation succeeds, {@code false} otherwise 1598 * 1599 * TODO: deprecate this 1600 */ 1601 public boolean syncSaveConfig(AsyncChannel channel) { 1602 Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG); 1603 boolean result = (resultMsg.arg1 != FAILURE); 1604 resultMsg.recycle(); 1605 return result; 1606 } 1607 1608 public void updateBatteryWorkSource(WorkSource newSource) { 1609 synchronized (mRunningWifiUids) { 1610 try { 1611 if (newSource != null) { 1612 mRunningWifiUids.set(newSource); 1613 } 1614 if (mIsRunning) { 1615 if (mReportedRunning) { 1616 // If the work source has changed since last time, need 1617 // to remove old work from battery stats. 1618 if (mLastRunningWifiUids.diff(mRunningWifiUids)) { 1619 mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids, 1620 mRunningWifiUids); 1621 mLastRunningWifiUids.set(mRunningWifiUids); 1622 } 1623 } else { 1624 // Now being started, report it. 1625 mBatteryStats.noteWifiRunning(mRunningWifiUids); 1626 mLastRunningWifiUids.set(mRunningWifiUids); 1627 mReportedRunning = true; 1628 } 1629 } else { 1630 if (mReportedRunning) { 1631 // Last reported we were running, time to stop. 1632 mBatteryStats.noteWifiStopped(mLastRunningWifiUids); 1633 mLastRunningWifiUids.clear(); 1634 mReportedRunning = false; 1635 } 1636 } 1637 mWakeLock.setWorkSource(newSource); 1638 } catch (RemoteException ignore) { 1639 } 1640 } 1641 } 1642 1643 @Override 1644 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1645 super.dump(fd, pw, args); 1646 mSupplicantStateTracker.dump(fd, pw, args); 1647 pw.println("mLinkProperties " + mLinkProperties); 1648 pw.println("mWifiInfo " + mWifiInfo); 1649 pw.println("mDhcpResults " + mDhcpResults); 1650 pw.println("mNetworkInfo " + mNetworkInfo); 1651 pw.println("mLastSignalLevel " + mLastSignalLevel); 1652 pw.println("mLastBssid " + mLastBssid); 1653 pw.println("mLastNetworkId " + mLastNetworkId); 1654 pw.println("mReconnectCount " + mReconnectCount); 1655 pw.println("mOperationalMode " + mOperationalMode); 1656 pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt); 1657 pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 1658 pw.println("Supplicant status " + mWifiNative.status()); 1659 pw.println("mEnableBackgroundScan " + mEnableBackgroundScan); 1660 pw.println("mLastSetCountryCode " + mLastSetCountryCode); 1661 pw.println("mPersistedCountryCode " + mPersistedCountryCode); 1662 pw.println(); 1663 mWifiConfigStore.dump(fd, pw, args); 1664 } 1665 1666 /********************************************************* 1667 * Internal private functions 1668 ********************************************************/ 1669 1670 private void handleScreenStateChanged(boolean screenOn) { 1671 if (DBG) log("handleScreenStateChanged: " + screenOn); 1672 enableRssiPolling(screenOn); 1673 if (mBackgroundScanSupported) { 1674 enableBackgroundScanCommand(screenOn == false); 1675 } 1676 1677 if (screenOn) enableAllNetworks(); 1678 if (mUserWantsSuspendOpt.get()) { 1679 if (screenOn) { 1680 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0); 1681 } else { 1682 //Allow 2s for suspend optimizations to be set 1683 mSuspendWakeLock.acquire(2000); 1684 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0); 1685 } 1686 } 1687 mScreenBroadcastReceived.set(true); 1688 } 1689 1690 private void checkAndSetConnectivityInstance() { 1691 if (mCm == null) { 1692 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 1693 } 1694 } 1695 1696 private boolean startTethering(ArrayList<String> available) { 1697 1698 boolean wifiAvailable = false; 1699 1700 checkAndSetConnectivityInstance(); 1701 1702 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 1703 1704 for (String intf : available) { 1705 for (String regex : wifiRegexs) { 1706 if (intf.matches(regex)) { 1707 1708 InterfaceConfiguration ifcg = null; 1709 try { 1710 ifcg = mNwService.getInterfaceConfig(intf); 1711 if (ifcg != null) { 1712 /* IP/netmask: 192.168.43.1/255.255.255.0 */ 1713 ifcg.setLinkAddress(new LinkAddress( 1714 NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); 1715 ifcg.setInterfaceUp(); 1716 1717 mNwService.setInterfaceConfig(intf, ifcg); 1718 } 1719 } catch (Exception e) { 1720 loge("Error configuring interface " + intf + ", :" + e); 1721 return false; 1722 } 1723 1724 if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 1725 loge("Error tethering on " + intf); 1726 return false; 1727 } 1728 mTetherInterfaceName = intf; 1729 return true; 1730 } 1731 } 1732 } 1733 // We found no interfaces to tether 1734 return false; 1735 } 1736 1737 private void stopTethering() { 1738 1739 checkAndSetConnectivityInstance(); 1740 1741 /* Clear the interface config to allow dhcp correctly configure new 1742 ip settings */ 1743 InterfaceConfiguration ifcg = null; 1744 try { 1745 ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName); 1746 if (ifcg != null) { 1747 ifcg.setLinkAddress( 1748 new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); 1749 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg); 1750 } 1751 } catch (Exception e) { 1752 loge("Error resetting interface " + mTetherInterfaceName + ", :" + e); 1753 } 1754 1755 if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 1756 loge("Untether initiate failed!"); 1757 } 1758 } 1759 1760 private boolean isWifiTethered(ArrayList<String> active) { 1761 1762 checkAndSetConnectivityInstance(); 1763 1764 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 1765 for (String intf : active) { 1766 for (String regex : wifiRegexs) { 1767 if (intf.matches(regex)) { 1768 return true; 1769 } 1770 } 1771 } 1772 // We found no interfaces that are tethered 1773 return false; 1774 } 1775 1776 /** 1777 * Set the country code from the system setting value, if any. 1778 */ 1779 private void setCountryCode() { 1780 String countryCode = Settings.Global.getString(mContext.getContentResolver(), 1781 Settings.Global.WIFI_COUNTRY_CODE); 1782 if (countryCode != null && !countryCode.isEmpty()) { 1783 setCountryCode(countryCode, false); 1784 } else { 1785 //use driver default 1786 } 1787 } 1788 1789 /** 1790 * Set the frequency band from the system setting value, if any. 1791 */ 1792 private void setFrequencyBand() { 1793 int band = Settings.Global.getInt(mContext.getContentResolver(), 1794 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO); 1795 setFrequencyBand(band, false); 1796 } 1797 1798 private void setSuspendOptimizationsNative(int reason, boolean enabled) { 1799 if (DBG) log("setSuspendOptimizationsNative: " + reason + " " + enabled); 1800 if (enabled) { 1801 mSuspendOptNeedsDisabled &= ~reason; 1802 /* None of dhcp, screen or highperf need it disabled and user wants it enabled */ 1803 if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) { 1804 mWifiNative.setSuspendOptimizations(true); 1805 } 1806 } else { 1807 mSuspendOptNeedsDisabled |= reason; 1808 mWifiNative.setSuspendOptimizations(false); 1809 } 1810 } 1811 1812 private void setSuspendOptimizations(int reason, boolean enabled) { 1813 if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled); 1814 if (enabled) { 1815 mSuspendOptNeedsDisabled &= ~reason; 1816 } else { 1817 mSuspendOptNeedsDisabled |= reason; 1818 } 1819 if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 1820 } 1821 1822 private void setWifiState(int wifiState) { 1823 final int previousWifiState = mWifiState.get(); 1824 1825 try { 1826 if (wifiState == WIFI_STATE_ENABLED) { 1827 mBatteryStats.noteWifiOn(); 1828 } else if (wifiState == WIFI_STATE_DISABLED) { 1829 mBatteryStats.noteWifiOff(); 1830 } 1831 } catch (RemoteException e) { 1832 loge("Failed to note battery stats in wifi"); 1833 } 1834 1835 mWifiState.set(wifiState); 1836 1837 if (DBG) log("setWifiState: " + syncGetWifiStateByName()); 1838 1839 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 1840 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1841 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 1842 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 1843 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1844 } 1845 1846 private void setWifiApState(int wifiApState) { 1847 final int previousWifiApState = mWifiApState.get(); 1848 1849 try { 1850 if (wifiApState == WIFI_AP_STATE_ENABLED) { 1851 mBatteryStats.noteWifiOn(); 1852 } else if (wifiApState == WIFI_AP_STATE_DISABLED) { 1853 mBatteryStats.noteWifiOff(); 1854 } 1855 } catch (RemoteException e) { 1856 loge("Failed to note battery stats in wifi"); 1857 } 1858 1859 // Update state 1860 mWifiApState.set(wifiApState); 1861 1862 if (DBG) log("setWifiApState: " + syncGetWifiApStateByName()); 1863 1864 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 1865 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1866 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); 1867 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); 1868 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1869 } 1870 1871 private static final String ID_STR = "id="; 1872 private static final String BSSID_STR = "bssid="; 1873 private static final String FREQ_STR = "freq="; 1874 private static final String LEVEL_STR = "level="; 1875 private static final String TSF_STR = "tsf="; 1876 private static final String FLAGS_STR = "flags="; 1877 private static final String SSID_STR = "ssid="; 1878 private static final String DELIMITER_STR = "===="; 1879 private static final String END_STR = "####"; 1880 1881 /** 1882 * Format: 1883 * 1884 * id=1 1885 * bssid=68:7f:76:d7:1a:6e 1886 * freq=2412 1887 * level=-44 1888 * tsf=1344626243700342 1889 * flags=[WPA2-PSK-CCMP][WPS][ESS] 1890 * ssid=zfdy 1891 * ==== 1892 * id=2 1893 * bssid=68:5f:74:d7:1a:6f 1894 * freq=5180 1895 * level=-73 1896 * tsf=1344626243700373 1897 * flags=[WPA2-PSK-CCMP][WPS][ESS] 1898 * ssid=zuby 1899 * ==== 1900 */ 1901 private void setScanResults() { 1902 String bssid = ""; 1903 int level = 0; 1904 int freq = 0; 1905 long tsf = 0; 1906 String flags = ""; 1907 WifiSsid wifiSsid = null; 1908 String scanResults; 1909 String tmpResults; 1910 StringBuffer scanResultsBuf = new StringBuffer(); 1911 int sid = 0; 1912 1913 while (true) { 1914 tmpResults = mWifiNative.scanResults(sid); 1915 if (TextUtils.isEmpty(tmpResults)) break; 1916 scanResultsBuf.append(tmpResults); 1917 scanResultsBuf.append("\n"); 1918 String[] lines = tmpResults.split("\n"); 1919 sid = -1; 1920 for (int i=lines.length - 1; i >= 0; i--) { 1921 if (lines[i].startsWith(END_STR)) { 1922 break; 1923 } else if (lines[i].startsWith(ID_STR)) { 1924 try { 1925 sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1; 1926 } catch (NumberFormatException e) { 1927 // Nothing to do 1928 } 1929 break; 1930 } 1931 } 1932 if (sid == -1) break; 1933 } 1934 1935 scanResults = scanResultsBuf.toString(); 1936 if (TextUtils.isEmpty(scanResults)) { 1937 return; 1938 } 1939 1940 // note that all these splits and substrings keep references to the original 1941 // huge string buffer while the amount we really want is generally pretty small 1942 // so make copies instead (one example b/11087956 wasted 400k of heap here). 1943 synchronized(mScanResultCache) { 1944 mScanResults = new ArrayList<ScanResult>(); 1945 String[] lines = scanResults.split("\n"); 1946 final int bssidStrLen = BSSID_STR.length(); 1947 final int flagLen = FLAGS_STR.length(); 1948 1949 for (String line : lines) { 1950 if (line.startsWith(BSSID_STR)) { 1951 bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen); 1952 } else if (line.startsWith(FREQ_STR)) { 1953 try { 1954 freq = Integer.parseInt(line.substring(FREQ_STR.length())); 1955 } catch (NumberFormatException e) { 1956 freq = 0; 1957 } 1958 } else if (line.startsWith(LEVEL_STR)) { 1959 try { 1960 level = Integer.parseInt(line.substring(LEVEL_STR.length())); 1961 /* some implementations avoid negative values by adding 256 1962 * so we need to adjust for that here. 1963 */ 1964 if (level > 0) level -= 256; 1965 } catch(NumberFormatException e) { 1966 level = 0; 1967 } 1968 } else if (line.startsWith(TSF_STR)) { 1969 try { 1970 tsf = Long.parseLong(line.substring(TSF_STR.length())); 1971 } catch (NumberFormatException e) { 1972 tsf = 0; 1973 } 1974 } else if (line.startsWith(FLAGS_STR)) { 1975 flags = new String(line.getBytes(), flagLen, line.length() - flagLen); 1976 } else if (line.startsWith(SSID_STR)) { 1977 wifiSsid = WifiSsid.createFromAsciiEncoded( 1978 line.substring(SSID_STR.length())); 1979 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) { 1980 if (bssid != null) { 1981 String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 1982 String key = bssid + ssid; 1983 ScanResult scanResult = mScanResultCache.get(key); 1984 if (scanResult != null) { 1985 scanResult.level = level; 1986 scanResult.wifiSsid = wifiSsid; 1987 // Keep existing API 1988 scanResult.SSID = (wifiSsid != null) ? wifiSsid.toString() : 1989 WifiSsid.NONE; 1990 scanResult.capabilities = flags; 1991 scanResult.frequency = freq; 1992 scanResult.timestamp = tsf; 1993 } else { 1994 scanResult = 1995 new ScanResult( 1996 wifiSsid, bssid, flags, level, freq, tsf); 1997 mScanResultCache.put(key, scanResult); 1998 } 1999 mScanResults.add(scanResult); 2000 } 2001 bssid = null; 2002 level = 0; 2003 freq = 0; 2004 tsf = 0; 2005 flags = ""; 2006 wifiSsid = null; 2007 } 2008 } 2009 } 2010 } 2011 2012 /* 2013 * Fetch RSSI and linkspeed on current connection 2014 */ 2015 private void fetchRssiAndLinkSpeedNative() { 2016 int newRssi = -1; 2017 int newLinkSpeed = -1; 2018 2019 String signalPoll = mWifiNative.signalPoll(); 2020 2021 if (signalPoll != null) { 2022 String[] lines = signalPoll.split("\n"); 2023 for (String line : lines) { 2024 String[] prop = line.split("="); 2025 if (prop.length < 2) continue; 2026 try { 2027 if (prop[0].equals("RSSI")) { 2028 newRssi = Integer.parseInt(prop[1]); 2029 } else if (prop[0].equals("LINKSPEED")) { 2030 newLinkSpeed = Integer.parseInt(prop[1]); 2031 } 2032 } catch (NumberFormatException e) { 2033 //Ignore, defaults on rssi and linkspeed are assigned 2034 } 2035 } 2036 } 2037 2038 if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values 2039 /* some implementations avoid negative values by adding 256 2040 * so we need to adjust for that here. 2041 */ 2042 if (newRssi > 0) newRssi -= 256; 2043 mWifiInfo.setRssi(newRssi); 2044 /* 2045 * Rather then sending the raw RSSI out every time it 2046 * changes, we precalculate the signal level that would 2047 * be displayed in the status bar, and only send the 2048 * broadcast if that much more coarse-grained number 2049 * changes. This cuts down greatly on the number of 2050 * broadcasts, at the cost of not informing others 2051 * interested in RSSI of all the changes in signal 2052 * level. 2053 */ 2054 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); 2055 if (newSignalLevel != mLastSignalLevel) { 2056 sendRssiChangeBroadcast(newRssi); 2057 } 2058 mLastSignalLevel = newSignalLevel; 2059 } else { 2060 mWifiInfo.setRssi(MIN_RSSI); 2061 } 2062 2063 if (newLinkSpeed != -1) { 2064 mWifiInfo.setLinkSpeed(newLinkSpeed); 2065 } 2066 } 2067 2068 /* 2069 * Fetch TX packet counters on current connection 2070 */ 2071 private void fetchPktcntNative(RssiPacketCountInfo info) { 2072 String pktcntPoll = mWifiNative.pktcntPoll(); 2073 2074 if (pktcntPoll != null) { 2075 String[] lines = pktcntPoll.split("\n"); 2076 for (String line : lines) { 2077 String[] prop = line.split("="); 2078 if (prop.length < 2) continue; 2079 try { 2080 if (prop[0].equals("TXGOOD")) { 2081 info.txgood = Integer.parseInt(prop[1]); 2082 } else if (prop[0].equals("TXBAD")) { 2083 info.txbad = Integer.parseInt(prop[1]); 2084 } 2085 } catch (NumberFormatException e) { 2086 //Ignore 2087 } 2088 } 2089 } 2090 } 2091 2092 /** 2093 * Updates mLinkProperties by merging information from various sources. 2094 * 2095 * This is needed because the information in mLinkProperties comes from multiple sources (DHCP, 2096 * netlink, static configuration, ...). When one of these sources of information has updated 2097 * link properties, we can't just assign them to mLinkProperties or we'd lose track of the 2098 * information that came from other sources. Instead, when one of those sources has new 2099 * information, we update the object that tracks the information from that source and then 2100 * call this method to apply the change to mLinkProperties. 2101 * 2102 * The information in mLinkProperties is currently obtained as follows: 2103 * - Interface name: set in the constructor. 2104 * - IPv4 and IPv6 addresses: netlink, via mInterfaceObserver. 2105 * - IPv4 routes, DNS servers, and domains: DHCP. 2106 * - HTTP proxy: the wifi config store. 2107 */ 2108 private void updateLinkProperties() { 2109 LinkProperties newLp = new LinkProperties(); 2110 2111 // Interface name and proxy are locally configured. 2112 newLp.setInterfaceName(mInterfaceName); 2113 newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); 2114 2115 // IPv4 and IPv6 addresses come from netlink. 2116 newLp.setLinkAddresses(mNetlinkLinkProperties.getLinkAddresses()); 2117 2118 // For now, routing and DNS only come from DHCP or static configuration. In the future, 2119 // we'll need to merge IPv6 DNS servers and domains coming from netlink. 2120 synchronized (mDhcpResultsLock) { 2121 // Even when we're using static configuration, we don't need to look at the config 2122 // store, because static IP configuration also populates mDhcpResults. 2123 if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) { 2124 LinkProperties lp = mDhcpResults.linkProperties; 2125 for (RouteInfo route: lp.getRoutes()) { 2126 newLp.addRoute(route); 2127 } 2128 for (InetAddress dns: lp.getDnses()) { 2129 newLp.addDns(dns); 2130 } 2131 newLp.setDomains(lp.getDomains()); 2132 } 2133 } 2134 2135 // If anything has changed, and we're already connected, send out a notification. 2136 // If we're still connecting, apps will be notified when we connect. 2137 if (!newLp.equals(mLinkProperties)) { 2138 if (DBG) { 2139 log("Link configuration changed for netId: " + mLastNetworkId 2140 + " old: " + mLinkProperties + "new: " + newLp); 2141 } 2142 mLinkProperties = newLp; 2143 if (getNetworkDetailedState() == DetailedState.CONNECTED) { 2144 sendLinkConfigurationChangedBroadcast(); 2145 } 2146 } 2147 } 2148 2149 /** 2150 * Clears all our link properties. 2151 */ 2152 private void clearLinkProperties() { 2153 // If the network used DHCP, clear the LinkProperties we stored in the config store. 2154 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 2155 mWifiConfigStore.clearLinkProperties(mLastNetworkId); 2156 } 2157 2158 // Clear the link properties obtained from DHCP and netlink. 2159 synchronized(mDhcpResultsLock) { 2160 if (mDhcpResults != null && mDhcpResults.linkProperties != null) { 2161 mDhcpResults.linkProperties.clear(); 2162 } 2163 } 2164 mNetlinkLinkProperties.clear(); 2165 2166 // Now clear the merged link properties. 2167 mLinkProperties.clear(); 2168 } 2169 2170 private int getMaxDhcpRetries() { 2171 return Settings.Global.getInt(mContext.getContentResolver(), 2172 Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, 2173 DEFAULT_MAX_DHCP_RETRIES); 2174 } 2175 2176 private void sendScanResultsAvailableBroadcast() { 2177 noteScanEnd(); 2178 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 2179 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2180 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2181 } 2182 2183 private void sendRssiChangeBroadcast(final int newRssi) { 2184 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); 2185 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2186 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); 2187 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2188 } 2189 2190 private void sendNetworkStateChangeBroadcast(String bssid) { 2191 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); 2192 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2193 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 2194 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties)); 2195 if (bssid != null) 2196 intent.putExtra(WifiManager.EXTRA_BSSID, bssid); 2197 if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK || 2198 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { 2199 intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo)); 2200 } 2201 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2202 } 2203 2204 private void sendLinkConfigurationChangedBroadcast() { 2205 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); 2206 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2207 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); 2208 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2209 } 2210 2211 private void sendSupplicantConnectionChangedBroadcast(boolean connected) { 2212 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 2213 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2214 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); 2215 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2216 } 2217 2218 /** 2219 * Record the detailed state of a network. 2220 * @param state the new {@code DetailedState} 2221 */ 2222 private void setNetworkDetailedState(NetworkInfo.DetailedState state) { 2223 if (DBG) { 2224 log("setDetailed state, old =" 2225 + mNetworkInfo.getDetailedState() + " and new state=" + state); 2226 } 2227 2228 if (state != mNetworkInfo.getDetailedState()) { 2229 mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); 2230 } 2231 } 2232 2233 private DetailedState getNetworkDetailedState() { 2234 return mNetworkInfo.getDetailedState(); 2235 } 2236 2237 2238 private SupplicantState handleSupplicantStateChange(Message message) { 2239 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 2240 SupplicantState state = stateChangeResult.state; 2241 // Supplicant state change 2242 // [31-13] Reserved for future use 2243 // [8 - 0] Supplicant state (as defined in SupplicantState.java) 2244 // 50023 supplicant_state_changed (custom|1|5) 2245 mWifiInfo.setSupplicantState(state); 2246 // Network id is only valid when we start connecting 2247 if (SupplicantState.isConnecting(state)) { 2248 mWifiInfo.setNetworkId(stateChangeResult.networkId); 2249 } else { 2250 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 2251 } 2252 2253 mWifiInfo.setBSSID(stateChangeResult.BSSID); 2254 mWifiInfo.setSSID(stateChangeResult.wifiSsid); 2255 2256 mSupplicantStateTracker.sendMessage(Message.obtain(message)); 2257 2258 return state; 2259 } 2260 2261 /** 2262 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 2263 * using the interface, stopping DHCP & disabling interface 2264 */ 2265 private void handleNetworkDisconnect() { 2266 if (DBG) log("Stopping DHCP and clearing IP"); 2267 2268 stopDhcp(); 2269 2270 try { 2271 mNwService.clearInterfaceAddresses(mInterfaceName); 2272 mNwService.disableIpv6(mInterfaceName); 2273 } catch (Exception e) { 2274 loge("Failed to clear addresses or disable ipv6" + e); 2275 } 2276 2277 /* Reset data structures */ 2278 mWifiInfo.setInetAddress(null); 2279 mWifiInfo.setBSSID(null); 2280 mWifiInfo.setSSID(null); 2281 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 2282 mWifiInfo.setRssi(MIN_RSSI); 2283 mWifiInfo.setLinkSpeed(-1); 2284 mWifiInfo.setMeteredHint(false); 2285 2286 setNetworkDetailedState(DetailedState.DISCONNECTED); 2287 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 2288 2289 /* Clear network properties */ 2290 clearLinkProperties(); 2291 2292 /* send event to CM & network change broadcast */ 2293 sendNetworkStateChangeBroadcast(mLastBssid); 2294 2295 mLastBssid= null; 2296 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 2297 } 2298 2299 private void handleSupplicantConnectionLoss() { 2300 /* Socket connection can be lost when we do a graceful shutdown 2301 * or when the driver is hung. Ensure supplicant is stopped here. 2302 */ 2303 mWifiMonitor.killSupplicant(mP2pSupported); 2304 sendSupplicantConnectionChangedBroadcast(false); 2305 setWifiState(WIFI_STATE_DISABLED); 2306 } 2307 2308 void handlePreDhcpSetup() { 2309 mDhcpActive = true; 2310 if (!mBluetoothConnectionActive) { 2311 /* 2312 * There are problems setting the Wi-Fi driver's power 2313 * mode to active when bluetooth coexistence mode is 2314 * enabled or sense. 2315 * <p> 2316 * We set Wi-Fi to active mode when 2317 * obtaining an IP address because we've found 2318 * compatibility issues with some routers with low power 2319 * mode. 2320 * <p> 2321 * In order for this active power mode to properly be set, 2322 * we disable coexistence mode until we're done with 2323 * obtaining an IP address. One exception is if we 2324 * are currently connected to a headset, since disabling 2325 * coexistence would interrupt that connection. 2326 */ 2327 // Disable the coexistence mode 2328 mWifiNative.setBluetoothCoexistenceMode( 2329 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); 2330 } 2331 2332 /* Disable power save and suspend optimizations during DHCP */ 2333 // Note: The order here is important for now. Brcm driver changes 2334 // power settings when we control suspend mode optimizations. 2335 // TODO: Remove this comment when the driver is fixed. 2336 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false); 2337 mWifiNative.setPowerSave(false); 2338 2339 stopBatchedScan(); 2340 2341 /* P2p discovery breaks dhcp, shut it down in order to get through this */ 2342 Message msg = new Message(); 2343 msg.what = WifiP2pService.BLOCK_DISCOVERY; 2344 msg.arg1 = WifiP2pService.ENABLED; 2345 msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE; 2346 msg.obj = mDhcpStateMachine; 2347 mWifiP2pChannel.sendMessage(msg); 2348 } 2349 2350 2351 void startDhcp() { 2352 if (mDhcpStateMachine == null) { 2353 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 2354 mContext, WifiStateMachine.this, mInterfaceName); 2355 2356 } 2357 mDhcpStateMachine.registerForPreDhcpNotification(); 2358 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); 2359 } 2360 2361 void stopDhcp() { 2362 if (mDhcpStateMachine != null) { 2363 /* In case we were in middle of DHCP operation restore back powermode */ 2364 handlePostDhcpSetup(); 2365 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); 2366 } 2367 } 2368 2369 void handlePostDhcpSetup() { 2370 /* Restore power save and suspend optimizations */ 2371 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true); 2372 mWifiNative.setPowerSave(true); 2373 2374 mWifiP2pChannel.sendMessage(WifiP2pService.BLOCK_DISCOVERY, WifiP2pService.DISABLED); 2375 2376 // Set the coexistence mode back to its default value 2377 mWifiNative.setBluetoothCoexistenceMode( 2378 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); 2379 2380 mDhcpActive = false; 2381 2382 startBatchedScan(); 2383 } 2384 2385 private void handleSuccessfulIpConfiguration(DhcpResults dhcpResults) { 2386 mLastSignalLevel = -1; // force update of signal strength 2387 mReconnectCount = 0; //Reset IP failure tracking 2388 synchronized (mDhcpResultsLock) { 2389 mDhcpResults = dhcpResults; 2390 } 2391 LinkProperties linkProperties = dhcpResults.linkProperties; 2392 mWifiConfigStore.setLinkProperties(mLastNetworkId, new LinkProperties(linkProperties)); 2393 InetAddress addr = null; 2394 Iterator<InetAddress> addrs = linkProperties.getAddresses().iterator(); 2395 if (addrs.hasNext()) { 2396 addr = addrs.next(); 2397 } 2398 mWifiInfo.setInetAddress(addr); 2399 mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint()); 2400 updateLinkProperties(); 2401 } 2402 2403 private void handleFailedIpConfiguration() { 2404 loge("IP configuration failed"); 2405 2406 mWifiInfo.setInetAddress(null); 2407 mWifiInfo.setMeteredHint(false); 2408 /** 2409 * If we've exceeded the maximum number of retries for DHCP 2410 * to a given network, disable the network 2411 */ 2412 int maxRetries = getMaxDhcpRetries(); 2413 // maxRetries == 0 means keep trying forever 2414 if (maxRetries > 0 && ++mReconnectCount > maxRetries) { 2415 loge("Failed " + 2416 mReconnectCount + " times, Disabling " + mLastNetworkId); 2417 mWifiConfigStore.disableNetwork(mLastNetworkId, 2418 WifiConfiguration.DISABLED_DHCP_FAILURE); 2419 mReconnectCount = 0; 2420 } 2421 2422 /* DHCP times out after about 30 seconds, we do a 2423 * disconnect and an immediate reconnect to try again 2424 */ 2425 mWifiNative.disconnect(); 2426 mWifiNative.reconnect(); 2427 } 2428 2429 /* Current design is to not set the config on a running hostapd but instead 2430 * stop and start tethering when user changes config on a running access point 2431 * 2432 * TODO: Add control channel setup through hostapd that allows changing config 2433 * on a running daemon 2434 */ 2435 private void startSoftApWithConfig(final WifiConfiguration config) { 2436 // start hostapd on a seperate thread 2437 new Thread(new Runnable() { 2438 public void run() { 2439 try { 2440 mNwService.startAccessPoint(config, mInterfaceName); 2441 } catch (Exception e) { 2442 loge("Exception in softap start " + e); 2443 try { 2444 mNwService.stopAccessPoint(mInterfaceName); 2445 mNwService.startAccessPoint(config, mInterfaceName); 2446 } catch (Exception e1) { 2447 loge("Exception in softap re-start " + e1); 2448 sendMessage(CMD_START_AP_FAILURE); 2449 return; 2450 } 2451 } 2452 if (DBG) log("Soft AP start successful"); 2453 sendMessage(CMD_START_AP_SUCCESS); 2454 } 2455 }).start(); 2456 } 2457 2458 /******************************************************** 2459 * HSM states 2460 *******************************************************/ 2461 2462 class DefaultState extends State { 2463 @Override 2464 public boolean processMessage(Message message) { 2465 switch (message.what) { 2466 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 2467 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 2468 mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 2469 } else { 2470 loge("WifiP2pService connection failure, error=" + message.arg1); 2471 } 2472 break; 2473 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 2474 loge("WifiP2pService channel lost, message.arg1 =" + message.arg1); 2475 //TODO: Re-establish connection to state machine after a delay 2476 //mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger()); 2477 break; 2478 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 2479 mBluetoothConnectionActive = (message.arg1 != 2480 BluetoothAdapter.STATE_DISCONNECTED); 2481 break; 2482 /* Synchronous call returns */ 2483 case CMD_PING_SUPPLICANT: 2484 case CMD_ENABLE_NETWORK: 2485 case CMD_ADD_OR_UPDATE_NETWORK: 2486 case CMD_REMOVE_NETWORK: 2487 case CMD_SAVE_CONFIG: 2488 replyToMessage(message, message.what, FAILURE); 2489 break; 2490 case CMD_GET_CONFIGURED_NETWORKS: 2491 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 2492 break; 2493 case CMD_ENABLE_RSSI_POLL: 2494 mEnableRssiPolling = (message.arg1 == 1); 2495 break; 2496 case CMD_ENABLE_BACKGROUND_SCAN: 2497 mEnableBackgroundScan = (message.arg1 == 1); 2498 break; 2499 case CMD_SET_HIGH_PERF_MODE: 2500 if (message.arg1 == 1) { 2501 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false); 2502 } else { 2503 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true); 2504 } 2505 break; 2506 case CMD_BOOT_COMPLETED: 2507 String countryCode = mPersistedCountryCode; 2508 if (TextUtils.isEmpty(countryCode) == false) { 2509 Settings.Global.putString(mContext.getContentResolver(), 2510 Settings.Global.WIFI_COUNTRY_CODE, 2511 countryCode); 2512 // it may be that the state transition that should send this info 2513 // to the driver happened between mPersistedCountryCode getting set 2514 // and now, so simply persisting it here would mean we have sent 2515 // nothing to the driver. Send the cmd so it might be set now. 2516 int sequenceNum = mCountryCodeSequence.incrementAndGet(); 2517 sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE, 2518 sequenceNum, 0, countryCode); 2519 } 2520 break; 2521 case CMD_SET_BATCHED_SCAN: 2522 recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj); 2523 break; 2524 case CMD_POLL_BATCHED_SCAN: 2525 handleBatchedScanPollRequest(); 2526 break; 2527 case CMD_START_NEXT_BATCHED_SCAN: 2528 startNextBatchedScan(); 2529 break; 2530 /* Discard */ 2531 case CMD_START_SCAN: 2532 case CMD_START_SUPPLICANT: 2533 case CMD_STOP_SUPPLICANT: 2534 case CMD_STOP_SUPPLICANT_FAILED: 2535 case CMD_START_DRIVER: 2536 case CMD_STOP_DRIVER: 2537 case CMD_DELAYED_STOP_DRIVER: 2538 case CMD_DRIVER_START_TIMED_OUT: 2539 case CMD_CAPTIVE_CHECK_COMPLETE: 2540 case CMD_START_AP: 2541 case CMD_START_AP_SUCCESS: 2542 case CMD_START_AP_FAILURE: 2543 case CMD_STOP_AP: 2544 case CMD_TETHER_STATE_CHANGE: 2545 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 2546 case CMD_DISCONNECT: 2547 case CMD_RECONNECT: 2548 case CMD_REASSOCIATE: 2549 case CMD_RELOAD_TLS_AND_RECONNECT: 2550 case WifiMonitor.SUP_CONNECTION_EVENT: 2551 case WifiMonitor.SUP_DISCONNECTION_EVENT: 2552 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2553 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2554 case WifiMonitor.SCAN_RESULTS_EVENT: 2555 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2556 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 2557 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 2558 case WifiMonitor.WPS_OVERLAP_EVENT: 2559 case CMD_BLACKLIST_NETWORK: 2560 case CMD_CLEAR_BLACKLIST: 2561 case CMD_SET_OPERATIONAL_MODE: 2562 case CMD_SET_COUNTRY_CODE: 2563 case CMD_SET_FREQUENCY_BAND: 2564 case CMD_RSSI_POLL: 2565 case CMD_ENABLE_ALL_NETWORKS: 2566 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 2567 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 2568 /* Handled by WifiApConfigStore */ 2569 case CMD_SET_AP_CONFIG: 2570 case CMD_SET_AP_CONFIG_COMPLETED: 2571 case CMD_REQUEST_AP_CONFIG: 2572 case CMD_RESPONSE_AP_CONFIG: 2573 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 2574 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 2575 case CMD_NO_NETWORKS_PERIODIC_SCAN: 2576 case CMD_DISABLE_P2P_RSP: 2577 break; 2578 case DhcpStateMachine.CMD_ON_QUIT: 2579 mDhcpStateMachine = null; 2580 break; 2581 case CMD_SET_SUSPEND_OPT_ENABLED: 2582 if (message.arg1 == 1) { 2583 mSuspendWakeLock.release(); 2584 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true); 2585 } else { 2586 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false); 2587 } 2588 break; 2589 case WifiMonitor.DRIVER_HUNG_EVENT: 2590 setSupplicantRunning(false); 2591 setSupplicantRunning(true); 2592 break; 2593 case WifiManager.CONNECT_NETWORK: 2594 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 2595 WifiManager.BUSY); 2596 break; 2597 case WifiManager.FORGET_NETWORK: 2598 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 2599 WifiManager.BUSY); 2600 break; 2601 case WifiManager.SAVE_NETWORK: 2602 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 2603 WifiManager.BUSY); 2604 break; 2605 case WifiManager.START_WPS: 2606 replyToMessage(message, WifiManager.WPS_FAILED, 2607 WifiManager.BUSY); 2608 break; 2609 case WifiManager.CANCEL_WPS: 2610 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, 2611 WifiManager.BUSY); 2612 break; 2613 case WifiManager.DISABLE_NETWORK: 2614 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 2615 WifiManager.BUSY); 2616 break; 2617 case WifiManager.RSSI_PKTCNT_FETCH: 2618 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED, 2619 WifiManager.BUSY); 2620 break; 2621 case WifiP2pService.P2P_CONNECTION_CHANGED: 2622 NetworkInfo info = (NetworkInfo) message.obj; 2623 mP2pConnected.set(info.isConnected()); 2624 break; 2625 case WifiP2pService.DISCONNECT_WIFI_REQUEST: 2626 mTemporarilyDisconnectWifi = (message.arg1 == 1); 2627 replyToMessage(message, WifiP2pService.DISCONNECT_WIFI_RESPONSE); 2628 break; 2629 case CMD_IP_ADDRESS_UPDATED: 2630 // addLinkAddress is a no-op if called more than once with the same address. 2631 if (mNetlinkLinkProperties.addLinkAddress((LinkAddress) message.obj)) { 2632 updateLinkProperties(); 2633 } 2634 break; 2635 case CMD_IP_ADDRESS_REMOVED: 2636 if (mNetlinkLinkProperties.removeLinkAddress((LinkAddress) message.obj)) { 2637 updateLinkProperties(); 2638 } 2639 break; 2640 default: 2641 loge("Error! unhandled message" + message); 2642 break; 2643 } 2644 return HANDLED; 2645 } 2646 } 2647 2648 class InitialState extends State { 2649 @Override 2650 public void enter() { 2651 mWifiNative.unloadDriver(); 2652 2653 if (mWifiP2pChannel == null) { 2654 mWifiP2pChannel = new AsyncChannel(); 2655 mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger()); 2656 } 2657 2658 if (mWifiApConfigChannel == null) { 2659 mWifiApConfigChannel = new AsyncChannel(); 2660 WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore( 2661 mContext, getHandler()); 2662 wifiApConfigStore.loadApConfiguration(); 2663 mWifiApConfigChannel.connectSync(mContext, getHandler(), 2664 wifiApConfigStore.getMessenger()); 2665 } 2666 } 2667 @Override 2668 public boolean processMessage(Message message) { 2669 switch (message.what) { 2670 case CMD_START_SUPPLICANT: 2671 if (mWifiNative.loadDriver()) { 2672 try { 2673 mNwService.wifiFirmwareReload(mInterfaceName, "STA"); 2674 } catch (Exception e) { 2675 loge("Failed to reload STA firmware " + e); 2676 // continue 2677 } 2678 2679 try { 2680 // A runtime crash can leave the interface up and 2681 // this affects connectivity when supplicant starts up. 2682 // Ensure interface is down before a supplicant start. 2683 mNwService.setInterfaceDown(mInterfaceName); 2684 // Set privacy extensions 2685 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); 2686 2687 // IPv6 is enabled only as long as access point is connected since: 2688 // - IPv6 addresses and routes stick around after disconnection 2689 // - kernel is unaware when connected and fails to start IPv6 negotiation 2690 // - kernel can start autoconfiguration when 802.1x is not complete 2691 mNwService.disableIpv6(mInterfaceName); 2692 } catch (RemoteException re) { 2693 loge("Unable to change interface settings: " + re); 2694 } catch (IllegalStateException ie) { 2695 loge("Unable to change interface settings: " + ie); 2696 } 2697 2698 /* Stop a running supplicant after a runtime restart 2699 * Avoids issues with drivers that do not handle interface down 2700 * on a running supplicant properly. 2701 */ 2702 mWifiMonitor.killSupplicant(mP2pSupported); 2703 if(mWifiNative.startSupplicant(mP2pSupported)) { 2704 setWifiState(WIFI_STATE_ENABLING); 2705 if (DBG) log("Supplicant start successful"); 2706 mWifiMonitor.startMonitoring(); 2707 transitionTo(mSupplicantStartingState); 2708 } else { 2709 loge("Failed to start supplicant!"); 2710 } 2711 } else { 2712 loge("Failed to load driver"); 2713 } 2714 break; 2715 case CMD_START_AP: 2716 if (mWifiNative.loadDriver()) { 2717 setWifiApState(WIFI_AP_STATE_ENABLING); 2718 transitionTo(mSoftApStartingState); 2719 } else { 2720 loge("Failed to load driver for softap"); 2721 } 2722 default: 2723 return NOT_HANDLED; 2724 } 2725 return HANDLED; 2726 } 2727 } 2728 2729 class SupplicantStartingState extends State { 2730 private void initializeWpsDetails() { 2731 String detail; 2732 detail = SystemProperties.get("ro.product.name", ""); 2733 if (!mWifiNative.setDeviceName(detail)) { 2734 loge("Failed to set device name " + detail); 2735 } 2736 detail = SystemProperties.get("ro.product.manufacturer", ""); 2737 if (!mWifiNative.setManufacturer(detail)) { 2738 loge("Failed to set manufacturer " + detail); 2739 } 2740 detail = SystemProperties.get("ro.product.model", ""); 2741 if (!mWifiNative.setModelName(detail)) { 2742 loge("Failed to set model name " + detail); 2743 } 2744 detail = SystemProperties.get("ro.product.model", ""); 2745 if (!mWifiNative.setModelNumber(detail)) { 2746 loge("Failed to set model number " + detail); 2747 } 2748 detail = SystemProperties.get("ro.serialno", ""); 2749 if (!mWifiNative.setSerialNumber(detail)) { 2750 loge("Failed to set serial number " + detail); 2751 } 2752 if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) { 2753 loge("Failed to set WPS config methods"); 2754 } 2755 if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) { 2756 loge("Failed to set primary device type " + mPrimaryDeviceType); 2757 } 2758 } 2759 2760 @Override 2761 public boolean processMessage(Message message) { 2762 switch(message.what) { 2763 case WifiMonitor.SUP_CONNECTION_EVENT: 2764 if (DBG) log("Supplicant connection established"); 2765 setWifiState(WIFI_STATE_ENABLED); 2766 mSupplicantRestartCount = 0; 2767 /* Reset the supplicant state to indicate the supplicant 2768 * state is not known at this time */ 2769 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2770 /* Initialize data structures */ 2771 mLastBssid = null; 2772 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 2773 mLastSignalLevel = -1; 2774 2775 mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); 2776 mWifiConfigStore.loadAndEnableAllNetworks(); 2777 initializeWpsDetails(); 2778 2779 sendSupplicantConnectionChangedBroadcast(true); 2780 transitionTo(mDriverStartedState); 2781 break; 2782 case WifiMonitor.SUP_DISCONNECTION_EVENT: 2783 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { 2784 loge("Failed to setup control channel, restart supplicant"); 2785 mWifiMonitor.killSupplicant(mP2pSupported); 2786 transitionTo(mInitialState); 2787 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 2788 } else { 2789 loge("Failed " + mSupplicantRestartCount + 2790 " times to start supplicant, unload driver"); 2791 mSupplicantRestartCount = 0; 2792 setWifiState(WIFI_STATE_UNKNOWN); 2793 transitionTo(mInitialState); 2794 } 2795 break; 2796 case CMD_START_SUPPLICANT: 2797 case CMD_STOP_SUPPLICANT: 2798 case CMD_START_AP: 2799 case CMD_STOP_AP: 2800 case CMD_START_DRIVER: 2801 case CMD_STOP_DRIVER: 2802 case CMD_SET_OPERATIONAL_MODE: 2803 case CMD_SET_COUNTRY_CODE: 2804 case CMD_SET_FREQUENCY_BAND: 2805 case CMD_START_PACKET_FILTERING: 2806 case CMD_STOP_PACKET_FILTERING: 2807 deferMessage(message); 2808 break; 2809 default: 2810 return NOT_HANDLED; 2811 } 2812 return HANDLED; 2813 } 2814 } 2815 2816 class SupplicantStartedState extends State { 2817 @Override 2818 public void enter() { 2819 /* Wifi is available as long as we have a connection to supplicant */ 2820 mNetworkInfo.setIsAvailable(true); 2821 2822 int defaultInterval = mContext.getResources().getInteger( 2823 R.integer.config_wifi_supplicant_scan_interval); 2824 2825 mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 2826 Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, 2827 defaultInterval); 2828 2829 mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000); 2830 } 2831 @Override 2832 public boolean processMessage(Message message) { 2833 switch(message.what) { 2834 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ 2835 if (mP2pSupported) { 2836 transitionTo(mWaitForP2pDisableState); 2837 } else { 2838 transitionTo(mSupplicantStoppingState); 2839 } 2840 break; 2841 case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ 2842 loge("Connection lost, restart supplicant"); 2843 handleSupplicantConnectionLoss(); 2844 handleNetworkDisconnect(); 2845 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2846 if (mP2pSupported) { 2847 transitionTo(mWaitForP2pDisableState); 2848 } else { 2849 transitionTo(mInitialState); 2850 } 2851 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 2852 break; 2853 case WifiMonitor.SCAN_RESULTS_EVENT: 2854 setScanResults(); 2855 sendScanResultsAvailableBroadcast(); 2856 mScanResultIsPending = false; 2857 break; 2858 case CMD_PING_SUPPLICANT: 2859 boolean ok = mWifiNative.ping(); 2860 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 2861 break; 2862 /* Cannot start soft AP while in client mode */ 2863 case CMD_START_AP: 2864 loge("Failed to start soft AP with a running supplicant"); 2865 setWifiApState(WIFI_AP_STATE_FAILED); 2866 break; 2867 case CMD_SET_OPERATIONAL_MODE: 2868 mOperationalMode = message.arg1; 2869 break; 2870 default: 2871 return NOT_HANDLED; 2872 } 2873 return HANDLED; 2874 } 2875 2876 @Override 2877 public void exit() { 2878 mNetworkInfo.setIsAvailable(false); 2879 } 2880 } 2881 2882 class SupplicantStoppingState extends State { 2883 @Override 2884 public void enter() { 2885 /* Send any reset commands to supplicant before shutting it down */ 2886 handleNetworkDisconnect(); 2887 if (mDhcpStateMachine != null) { 2888 mDhcpStateMachine.doQuit(); 2889 } 2890 2891 if (DBG) log("stopping supplicant"); 2892 mWifiMonitor.stopSupplicant(); 2893 2894 /* Send ourselves a delayed message to indicate failure after a wait time */ 2895 sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED, 2896 ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS); 2897 setWifiState(WIFI_STATE_DISABLING); 2898 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2899 } 2900 @Override 2901 public boolean processMessage(Message message) { 2902 switch(message.what) { 2903 case WifiMonitor.SUP_CONNECTION_EVENT: 2904 loge("Supplicant connection received while stopping"); 2905 break; 2906 case WifiMonitor.SUP_DISCONNECTION_EVENT: 2907 if (DBG) log("Supplicant connection lost"); 2908 handleSupplicantConnectionLoss(); 2909 transitionTo(mInitialState); 2910 break; 2911 case CMD_STOP_SUPPLICANT_FAILED: 2912 if (message.arg1 == mSupplicantStopFailureToken) { 2913 loge("Timed out on a supplicant stop, kill and proceed"); 2914 handleSupplicantConnectionLoss(); 2915 transitionTo(mInitialState); 2916 } 2917 break; 2918 case CMD_START_SUPPLICANT: 2919 case CMD_STOP_SUPPLICANT: 2920 case CMD_START_AP: 2921 case CMD_STOP_AP: 2922 case CMD_START_DRIVER: 2923 case CMD_STOP_DRIVER: 2924 case CMD_SET_OPERATIONAL_MODE: 2925 case CMD_SET_COUNTRY_CODE: 2926 case CMD_SET_FREQUENCY_BAND: 2927 case CMD_START_PACKET_FILTERING: 2928 case CMD_STOP_PACKET_FILTERING: 2929 deferMessage(message); 2930 break; 2931 default: 2932 return NOT_HANDLED; 2933 } 2934 return HANDLED; 2935 } 2936 } 2937 2938 class DriverStartingState extends State { 2939 private int mTries; 2940 @Override 2941 public void enter() { 2942 mTries = 1; 2943 /* Send ourselves a delayed message to start driver a second time */ 2944 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 2945 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 2946 } 2947 @Override 2948 public boolean processMessage(Message message) { 2949 switch(message.what) { 2950 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2951 SupplicantState state = handleSupplicantStateChange(message); 2952 /* If suplicant is exiting out of INTERFACE_DISABLED state into 2953 * a state that indicates driver has started, it is ready to 2954 * receive driver commands 2955 */ 2956 if (SupplicantState.isDriverActive(state)) { 2957 transitionTo(mDriverStartedState); 2958 } 2959 break; 2960 case CMD_DRIVER_START_TIMED_OUT: 2961 if (message.arg1 == mDriverStartToken) { 2962 if (mTries >= 2) { 2963 loge("Failed to start driver after " + mTries); 2964 transitionTo(mDriverStoppedState); 2965 } else { 2966 loge("Driver start failed, retrying"); 2967 mWakeLock.acquire(); 2968 mWifiNative.startDriver(); 2969 mWakeLock.release(); 2970 2971 ++mTries; 2972 /* Send ourselves a delayed message to start driver again */ 2973 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 2974 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 2975 } 2976 } 2977 break; 2978 /* Queue driver commands & connection events */ 2979 case CMD_START_DRIVER: 2980 case CMD_STOP_DRIVER: 2981 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2982 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2983 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 2984 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 2985 case WifiMonitor.WPS_OVERLAP_EVENT: 2986 case CMD_SET_COUNTRY_CODE: 2987 case CMD_SET_FREQUENCY_BAND: 2988 case CMD_START_PACKET_FILTERING: 2989 case CMD_STOP_PACKET_FILTERING: 2990 case CMD_START_SCAN: 2991 case CMD_DISCONNECT: 2992 case CMD_REASSOCIATE: 2993 case CMD_RECONNECT: 2994 deferMessage(message); 2995 break; 2996 default: 2997 return NOT_HANDLED; 2998 } 2999 return HANDLED; 3000 } 3001 } 3002 3003 class DriverStartedState extends State { 3004 @Override 3005 public void enter() { 3006 mIsRunning = true; 3007 mInDelayedStop = false; 3008 mDelayedStopCounter++; 3009 updateBatteryWorkSource(null); 3010 /** 3011 * Enable bluetooth coexistence scan mode when bluetooth connection is active. 3012 * When this mode is on, some of the low-level scan parameters used by the 3013 * driver are changed to reduce interference with bluetooth 3014 */ 3015 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 3016 /* set country code */ 3017 setCountryCode(); 3018 /* set frequency band of operation */ 3019 setFrequencyBand(); 3020 /* initialize network state */ 3021 setNetworkDetailedState(DetailedState.DISCONNECTED); 3022 3023 /* Remove any filtering on Multicast v6 at start */ 3024 mWifiNative.stopFilteringMulticastV6Packets(); 3025 3026 /* Reset Multicast v4 filtering state */ 3027 if (mFilteringMulticastV4Packets.get()) { 3028 mWifiNative.startFilteringMulticastV4Packets(); 3029 } else { 3030 mWifiNative.stopFilteringMulticastV4Packets(); 3031 } 3032 3033 mDhcpActive = false; 3034 3035 startBatchedScan(); 3036 3037 if (mOperationalMode != CONNECT_MODE) { 3038 mWifiNative.disconnect(); 3039 mWifiConfigStore.disableAllNetworks(); 3040 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 3041 setWifiState(WIFI_STATE_DISABLED); 3042 } 3043 transitionTo(mScanModeState); 3044 } else { 3045 /* Driver stop may have disabled networks, enable right after start */ 3046 mWifiConfigStore.enableAllNetworks(); 3047 3048 if (DBG) log("Attempting to reconnect to wifi network .."); 3049 mWifiNative.reconnect(); 3050 3051 // Status pulls in the current supplicant state and network connection state 3052 // events over the monitor connection. This helps framework sync up with 3053 // current supplicant state 3054 mWifiNative.status(); 3055 transitionTo(mDisconnectedState); 3056 } 3057 3058 // We may have missed screen update at boot 3059 if (mScreenBroadcastReceived.get() == false) { 3060 PowerManager powerManager = (PowerManager)mContext.getSystemService( 3061 Context.POWER_SERVICE); 3062 handleScreenStateChanged(powerManager.isScreenOn()); 3063 } else { 3064 // Set the right suspend mode settings 3065 mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0 3066 && mUserWantsSuspendOpt.get()); 3067 } 3068 mWifiNative.setPowerSave(true); 3069 3070 if (mP2pSupported) { 3071 if (mOperationalMode == CONNECT_MODE) { 3072 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); 3073 } else { 3074 // P2P statemachine starts in disabled state, and is not enabled until 3075 // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to 3076 // keep it disabled. 3077 } 3078 } 3079 3080 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 3081 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3082 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED); 3083 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3084 } 3085 3086 @Override 3087 public boolean processMessage(Message message) { 3088 switch(message.what) { 3089 case CMD_START_SCAN: 3090 noteScanStart(message.arg1, (WorkSource) message.obj); 3091 startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP); 3092 break; 3093 case CMD_SET_BATCHED_SCAN: 3094 if (recordBatchedScanSettings(message.arg1, message.arg2, 3095 (Bundle)message.obj)) { 3096 if (mBatchedScanSettings != null) { 3097 startBatchedScan(); 3098 } else { 3099 stopBatchedScan(); 3100 } 3101 } 3102 break; 3103 case CMD_SET_COUNTRY_CODE: 3104 String country = (String) message.obj; 3105 final boolean persist = (message.arg2 == 1); 3106 final int sequence = message.arg1; 3107 if (sequence != mCountryCodeSequence.get()) { 3108 if (DBG) log("set country code ignored due to sequence num"); 3109 break; 3110 } 3111 if (DBG) log("set country code " + country); 3112 if (persist) { 3113 mPersistedCountryCode = country; 3114 Settings.Global.putString(mContext.getContentResolver(), 3115 Settings.Global.WIFI_COUNTRY_CODE, 3116 country); 3117 } 3118 country = country.toUpperCase(Locale.ROOT); 3119 if (mLastSetCountryCode == null 3120 || country.equals(mLastSetCountryCode) == false) { 3121 if (mWifiNative.setCountryCode(country)) { 3122 mLastSetCountryCode = country; 3123 } else { 3124 loge("Failed to set country code " + country); 3125 } 3126 } 3127 mWifiP2pChannel.sendMessage(WifiP2pService.SET_COUNTRY_CODE, country); 3128 break; 3129 case CMD_SET_FREQUENCY_BAND: 3130 int band = message.arg1; 3131 if (DBG) log("set frequency band " + band); 3132 if (mWifiNative.setBand(band)) { 3133 mFrequencyBand.set(band); 3134 // flush old data - like scan results 3135 mWifiNative.bssFlush(); 3136 //Fetch the latest scan results when frequency band is set 3137 startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP); 3138 } else { 3139 loge("Failed to set frequency band " + band); 3140 } 3141 break; 3142 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 3143 mBluetoothConnectionActive = (message.arg1 != 3144 BluetoothAdapter.STATE_DISCONNECTED); 3145 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 3146 break; 3147 case CMD_STOP_DRIVER: 3148 int mode = message.arg1; 3149 3150 /* Already doing a delayed stop */ 3151 if (mInDelayedStop) { 3152 if (DBG) log("Already in delayed stop"); 3153 break; 3154 } 3155 /* disconnect right now, but leave the driver running for a bit */ 3156 mWifiConfigStore.disableAllNetworks(); 3157 3158 mInDelayedStop = true; 3159 mDelayedStopCounter++; 3160 if (DBG) log("Delayed stop message " + mDelayedStopCounter); 3161 3162 /* send regular delayed shut down */ 3163 Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); 3164 driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); 3165 mDriverStopIntent = PendingIntent.getBroadcast(mContext, 3166 DRIVER_STOP_REQUEST, driverStopIntent, 3167 PendingIntent.FLAG_UPDATE_CURRENT); 3168 3169 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 3170 + mDriverStopDelayMs, mDriverStopIntent); 3171 break; 3172 case CMD_START_DRIVER: 3173 if (mInDelayedStop) { 3174 mInDelayedStop = false; 3175 mDelayedStopCounter++; 3176 mAlarmManager.cancel(mDriverStopIntent); 3177 if (DBG) log("Delayed stop ignored due to start"); 3178 if (mOperationalMode == CONNECT_MODE) { 3179 mWifiConfigStore.enableAllNetworks(); 3180 } 3181 } 3182 break; 3183 case CMD_DELAYED_STOP_DRIVER: 3184 if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter); 3185 if (message.arg1 != mDelayedStopCounter) break; 3186 if (getCurrentState() != mDisconnectedState) { 3187 mWifiNative.disconnect(); 3188 handleNetworkDisconnect(); 3189 } 3190 mWakeLock.acquire(); 3191 mWifiNative.stopDriver(); 3192 mWakeLock.release(); 3193 if (mP2pSupported) { 3194 transitionTo(mWaitForP2pDisableState); 3195 } else { 3196 transitionTo(mDriverStoppingState); 3197 } 3198 break; 3199 case CMD_START_PACKET_FILTERING: 3200 if (message.arg1 == MULTICAST_V6) { 3201 mWifiNative.startFilteringMulticastV6Packets(); 3202 } else if (message.arg1 == MULTICAST_V4) { 3203 mWifiNative.startFilteringMulticastV4Packets(); 3204 } else { 3205 loge("Illegal arugments to CMD_START_PACKET_FILTERING"); 3206 } 3207 break; 3208 case CMD_STOP_PACKET_FILTERING: 3209 if (message.arg1 == MULTICAST_V6) { 3210 mWifiNative.stopFilteringMulticastV6Packets(); 3211 } else if (message.arg1 == MULTICAST_V4) { 3212 mWifiNative.stopFilteringMulticastV4Packets(); 3213 } else { 3214 loge("Illegal arugments to CMD_STOP_PACKET_FILTERING"); 3215 } 3216 break; 3217 case CMD_SET_SUSPEND_OPT_ENABLED: 3218 if (message.arg1 == 1) { 3219 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true); 3220 mSuspendWakeLock.release(); 3221 } else { 3222 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false); 3223 } 3224 break; 3225 case CMD_SET_HIGH_PERF_MODE: 3226 if (message.arg1 == 1) { 3227 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false); 3228 } else { 3229 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true); 3230 } 3231 break; 3232 case CMD_ENABLE_TDLS: 3233 if (message.obj != null) { 3234 String remoteAddress = (String) message.obj; 3235 boolean enable = (message.arg1 == 1); 3236 mWifiNative.startTdls(remoteAddress, enable); 3237 } 3238 break; 3239 default: 3240 return NOT_HANDLED; 3241 } 3242 return HANDLED; 3243 } 3244 @Override 3245 public void exit() { 3246 mIsRunning = false; 3247 updateBatteryWorkSource(null); 3248 mScanResults = new ArrayList<ScanResult>(); 3249 3250 stopBatchedScan(); 3251 3252 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 3253 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3254 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 3255 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3256 noteScanEnd(); // wrap up any pending request. 3257 3258 mLastSetCountryCode = null; 3259 } 3260 } 3261 3262 class WaitForP2pDisableState extends State { 3263 private State mTransitionToState; 3264 @Override 3265 public void enter() { 3266 switch (getCurrentMessage().what) { 3267 case WifiMonitor.SUP_DISCONNECTION_EVENT: 3268 mTransitionToState = mInitialState; 3269 break; 3270 case CMD_DELAYED_STOP_DRIVER: 3271 mTransitionToState = mDriverStoppingState; 3272 break; 3273 case CMD_STOP_SUPPLICANT: 3274 mTransitionToState = mSupplicantStoppingState; 3275 break; 3276 default: 3277 mTransitionToState = mDriverStoppingState; 3278 break; 3279 } 3280 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ); 3281 } 3282 @Override 3283 public boolean processMessage(Message message) { 3284 switch(message.what) { 3285 case WifiStateMachine.CMD_DISABLE_P2P_RSP: 3286 transitionTo(mTransitionToState); 3287 break; 3288 /* Defer wifi start/shut and driver commands */ 3289 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3290 case CMD_START_SUPPLICANT: 3291 case CMD_STOP_SUPPLICANT: 3292 case CMD_START_AP: 3293 case CMD_STOP_AP: 3294 case CMD_START_DRIVER: 3295 case CMD_STOP_DRIVER: 3296 case CMD_SET_OPERATIONAL_MODE: 3297 case CMD_SET_COUNTRY_CODE: 3298 case CMD_SET_FREQUENCY_BAND: 3299 case CMD_START_PACKET_FILTERING: 3300 case CMD_STOP_PACKET_FILTERING: 3301 case CMD_START_SCAN: 3302 case CMD_DISCONNECT: 3303 case CMD_REASSOCIATE: 3304 case CMD_RECONNECT: 3305 deferMessage(message); 3306 break; 3307 default: 3308 return NOT_HANDLED; 3309 } 3310 return HANDLED; 3311 } 3312 } 3313 3314 class DriverStoppingState extends State { 3315 @Override 3316 public boolean processMessage(Message message) { 3317 switch(message.what) { 3318 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3319 SupplicantState state = handleSupplicantStateChange(message); 3320 if (state == SupplicantState.INTERFACE_DISABLED) { 3321 transitionTo(mDriverStoppedState); 3322 } 3323 break; 3324 /* Queue driver commands */ 3325 case CMD_START_DRIVER: 3326 case CMD_STOP_DRIVER: 3327 case CMD_SET_COUNTRY_CODE: 3328 case CMD_SET_FREQUENCY_BAND: 3329 case CMD_START_PACKET_FILTERING: 3330 case CMD_STOP_PACKET_FILTERING: 3331 case CMD_START_SCAN: 3332 case CMD_DISCONNECT: 3333 case CMD_REASSOCIATE: 3334 case CMD_RECONNECT: 3335 deferMessage(message); 3336 break; 3337 default: 3338 return NOT_HANDLED; 3339 } 3340 return HANDLED; 3341 } 3342 } 3343 3344 class DriverStoppedState extends State { 3345 @Override 3346 public boolean processMessage(Message message) { 3347 switch (message.what) { 3348 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3349 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 3350 SupplicantState state = stateChangeResult.state; 3351 // A WEXT bug means that we can be back to driver started state 3352 // unexpectedly 3353 if (SupplicantState.isDriverActive(state)) { 3354 transitionTo(mDriverStartedState); 3355 } 3356 break; 3357 case CMD_START_DRIVER: 3358 mWakeLock.acquire(); 3359 mWifiNative.startDriver(); 3360 mWakeLock.release(); 3361 transitionTo(mDriverStartingState); 3362 break; 3363 default: 3364 return NOT_HANDLED; 3365 } 3366 return HANDLED; 3367 } 3368 } 3369 3370 class ScanModeState extends State { 3371 private int mLastOperationMode; 3372 @Override 3373 public void enter() { 3374 mLastOperationMode = mOperationalMode; 3375 } 3376 @Override 3377 public boolean processMessage(Message message) { 3378 switch(message.what) { 3379 case CMD_SET_OPERATIONAL_MODE: 3380 if (message.arg1 == CONNECT_MODE) { 3381 3382 if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 3383 setWifiState(WIFI_STATE_ENABLED); 3384 // Load and re-enable networks when going back to enabled state 3385 // This is essential for networks to show up after restore 3386 mWifiConfigStore.loadAndEnableAllNetworks(); 3387 mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P); 3388 } else { 3389 mWifiConfigStore.enableAllNetworks(); 3390 } 3391 3392 mWifiNative.reconnect(); 3393 3394 mOperationalMode = CONNECT_MODE; 3395 transitionTo(mDisconnectedState); 3396 } else { 3397 // Nothing to do 3398 return HANDLED; 3399 } 3400 break; 3401 // Handle scan. All the connection related commands are 3402 // handled only in ConnectModeState 3403 case CMD_START_SCAN: 3404 noteScanStart(message.arg1, (WorkSource) message.obj); 3405 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP); 3406 break; 3407 default: 3408 return NOT_HANDLED; 3409 } 3410 return HANDLED; 3411 } 3412 } 3413 3414 class ConnectModeState extends State { 3415 @Override 3416 public boolean processMessage(Message message) { 3417 WifiConfiguration config; 3418 boolean ok; 3419 switch(message.what) { 3420 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 3421 mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT); 3422 break; 3423 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 3424 mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT); 3425 break; 3426 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3427 SupplicantState state = handleSupplicantStateChange(message); 3428 // A driver/firmware hang can now put the interface in a down state. 3429 // We detect the interface going down and recover from it 3430 if (!SupplicantState.isDriverActive(state)) { 3431 if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 3432 handleNetworkDisconnect(); 3433 } 3434 log("Detected an interface down, restart driver"); 3435 transitionTo(mDriverStoppedState); 3436 sendMessage(CMD_START_DRIVER); 3437 break; 3438 } 3439 3440 // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT 3441 // when authentication times out after a successful connection, 3442 // we can figure this from the supplicant state. If supplicant 3443 // state is DISCONNECTED, but the mNetworkInfo says we are not 3444 // disconnected, we need to handle a disconnection 3445 if (state == SupplicantState.DISCONNECTED && 3446 mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 3447 if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect"); 3448 handleNetworkDisconnect(); 3449 transitionTo(mDisconnectedState); 3450 } 3451 break; 3452 case WifiP2pService.DISCONNECT_WIFI_REQUEST: 3453 if (message.arg1 == 1) { 3454 mWifiNative.disconnect(); 3455 mTemporarilyDisconnectWifi = true; 3456 } else { 3457 mWifiNative.reconnect(); 3458 mTemporarilyDisconnectWifi = false; 3459 } 3460 break; 3461 case CMD_ADD_OR_UPDATE_NETWORK: 3462 config = (WifiConfiguration) message.obj; 3463 replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, 3464 mWifiConfigStore.addOrUpdateNetwork(config)); 3465 break; 3466 case CMD_REMOVE_NETWORK: 3467 ok = mWifiConfigStore.removeNetwork(message.arg1); 3468 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 3469 break; 3470 case CMD_ENABLE_NETWORK: 3471 ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); 3472 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 3473 break; 3474 case CMD_ENABLE_ALL_NETWORKS: 3475 long time = android.os.SystemClock.elapsedRealtime(); 3476 if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { 3477 mWifiConfigStore.enableAllNetworks(); 3478 mLastEnableAllNetworksTime = time; 3479 } 3480 break; 3481 case WifiManager.DISABLE_NETWORK: 3482 if (mWifiConfigStore.disableNetwork(message.arg1, 3483 WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) { 3484 replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); 3485 } else { 3486 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 3487 WifiManager.ERROR); 3488 } 3489 break; 3490 case CMD_BLACKLIST_NETWORK: 3491 mWifiNative.addToBlacklist((String)message.obj); 3492 break; 3493 case CMD_CLEAR_BLACKLIST: 3494 mWifiNative.clearBlacklist(); 3495 break; 3496 case CMD_SAVE_CONFIG: 3497 ok = mWifiConfigStore.saveConfig(); 3498 replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); 3499 3500 // Inform the backup manager about a data change 3501 IBackupManager ibm = IBackupManager.Stub.asInterface( 3502 ServiceManager.getService(Context.BACKUP_SERVICE)); 3503 if (ibm != null) { 3504 try { 3505 ibm.dataChanged("com.android.providers.settings"); 3506 } catch (Exception e) { 3507 // Try again later 3508 } 3509 } 3510 break; 3511 case CMD_GET_CONFIGURED_NETWORKS: 3512 replyToMessage(message, message.what, 3513 mWifiConfigStore.getConfiguredNetworks()); 3514 break; 3515 /* Do a redundant disconnect without transition */ 3516 case CMD_DISCONNECT: 3517 mWifiNative.disconnect(); 3518 break; 3519 case CMD_RECONNECT: 3520 mWifiNative.reconnect(); 3521 break; 3522 case CMD_REASSOCIATE: 3523 mWifiNative.reassociate(); 3524 break; 3525 case CMD_RELOAD_TLS_AND_RECONNECT: 3526 if (mWifiConfigStore.needsUnlockedKeyStore()) { 3527 logd("Reconnecting to give a chance to un-connected TLS networks"); 3528 mWifiNative.disconnect(); 3529 mWifiNative.reconnect(); 3530 } 3531 break; 3532 case WifiManager.CONNECT_NETWORK: 3533 /* The connect message can contain a network id passed as arg1 on message or 3534 * or a config passed as obj on message. 3535 * For a new network, a config is passed to create and connect. 3536 * For an existing network, a network id is passed 3537 */ 3538 int netId = message.arg1; 3539 config = (WifiConfiguration) message.obj; 3540 3541 /* Save the network config */ 3542 if (config != null) { 3543 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 3544 netId = result.getNetworkId(); 3545 } 3546 3547 if (mWifiConfigStore.selectNetwork(netId) && 3548 mWifiNative.reconnect()) { 3549 /* The state tracker handles enabling networks upon completion/failure */ 3550 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 3551 replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 3552 /* Expect a disconnection from the old connection */ 3553 transitionTo(mDisconnectingState); 3554 } else { 3555 loge("Failed to connect config: " + config + " netId: " + netId); 3556 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 3557 WifiManager.ERROR); 3558 break; 3559 } 3560 break; 3561 case WifiManager.SAVE_NETWORK: 3562 config = (WifiConfiguration) message.obj; 3563 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 3564 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 3565 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 3566 } else { 3567 loge("Failed to save network"); 3568 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 3569 WifiManager.ERROR); 3570 } 3571 break; 3572 case WifiManager.FORGET_NETWORK: 3573 if (mWifiConfigStore.forgetNetwork(message.arg1)) { 3574 replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); 3575 } else { 3576 loge("Failed to forget network"); 3577 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 3578 WifiManager.ERROR); 3579 } 3580 break; 3581 case WifiManager.START_WPS: 3582 WpsInfo wpsInfo = (WpsInfo) message.obj; 3583 WpsResult wpsResult; 3584 switch (wpsInfo.setup) { 3585 case WpsInfo.PBC: 3586 wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo); 3587 break; 3588 case WpsInfo.KEYPAD: 3589 wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); 3590 break; 3591 case WpsInfo.DISPLAY: 3592 wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); 3593 break; 3594 default: 3595 wpsResult = new WpsResult(Status.FAILURE); 3596 loge("Invalid setup for WPS"); 3597 break; 3598 } 3599 if (wpsResult.status == Status.SUCCESS) { 3600 replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult); 3601 transitionTo(mWpsRunningState); 3602 } else { 3603 loge("Failed to start WPS with config " + wpsInfo.toString()); 3604 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR); 3605 } 3606 break; 3607 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3608 if (DBG) log("Network connection established"); 3609 mLastNetworkId = message.arg1; 3610 mLastBssid = (String) message.obj; 3611 3612 mWifiInfo.setBSSID(mLastBssid); 3613 mWifiInfo.setNetworkId(mLastNetworkId); 3614 /* send event to CM & network change broadcast */ 3615 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 3616 sendNetworkStateChangeBroadcast(mLastBssid); 3617 transitionTo(mObtainingIpState); 3618 break; 3619 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 3620 if (DBG) log("Network connection lost"); 3621 handleNetworkDisconnect(); 3622 transitionTo(mDisconnectedState); 3623 break; 3624 default: 3625 return NOT_HANDLED; 3626 } 3627 return HANDLED; 3628 } 3629 } 3630 3631 class L2ConnectedState extends State { 3632 @Override 3633 public void enter() { 3634 mRssiPollToken++; 3635 if (mEnableRssiPolling) { 3636 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0); 3637 } 3638 } 3639 3640 @Override 3641 public void exit() { 3642 handleNetworkDisconnect(); 3643 } 3644 3645 @Override 3646 public boolean processMessage(Message message) { 3647 switch (message.what) { 3648 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 3649 handlePreDhcpSetup(); 3650 break; 3651 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 3652 handlePostDhcpSetup(); 3653 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 3654 if (DBG) log("DHCP successful"); 3655 handleSuccessfulIpConfiguration((DhcpResults) message.obj); 3656 transitionTo(mVerifyingLinkState); 3657 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { 3658 if (DBG) log("DHCP failed"); 3659 handleFailedIpConfiguration(); 3660 transitionTo(mDisconnectingState); 3661 } 3662 break; 3663 case CMD_DISCONNECT: 3664 mWifiNative.disconnect(); 3665 transitionTo(mDisconnectingState); 3666 break; 3667 case WifiP2pService.DISCONNECT_WIFI_REQUEST: 3668 if (message.arg1 == 1) { 3669 mWifiNative.disconnect(); 3670 mTemporarilyDisconnectWifi = true; 3671 transitionTo(mDisconnectingState); 3672 } 3673 break; 3674 case CMD_SET_OPERATIONAL_MODE: 3675 if (message.arg1 != CONNECT_MODE) { 3676 sendMessage(CMD_DISCONNECT); 3677 deferMessage(message); 3678 } 3679 break; 3680 case CMD_SET_COUNTRY_CODE: 3681 deferMessage(message); 3682 break; 3683 case CMD_START_SCAN: 3684 /* Do not attempt to connect when we are already connected */ 3685 noteScanStart(message.arg1, (WorkSource) message.obj); 3686 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP); 3687 break; 3688 /* Ignore connection to same network */ 3689 case WifiManager.CONNECT_NETWORK: 3690 int netId = message.arg1; 3691 if (mWifiInfo.getNetworkId() == netId) { 3692 break; 3693 } 3694 return NOT_HANDLED; 3695 case WifiManager.SAVE_NETWORK: 3696 WifiConfiguration config = (WifiConfiguration) message.obj; 3697 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 3698 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 3699 if (result.hasIpChanged()) { 3700 log("Reconfiguring IP on connection"); 3701 transitionTo(mObtainingIpState); 3702 } 3703 if (result.hasProxyChanged()) { 3704 log("Reconfiguring proxy on connection"); 3705 updateLinkProperties(); 3706 } 3707 } 3708 3709 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 3710 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 3711 } else { 3712 loge("Failed to save network"); 3713 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 3714 WifiManager.ERROR); 3715 } 3716 break; 3717 /* Ignore */ 3718 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3719 break; 3720 case CMD_RSSI_POLL: 3721 if (message.arg1 == mRssiPollToken) { 3722 // Get Info and continue polling 3723 fetchRssiAndLinkSpeedNative(); 3724 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 3725 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 3726 } else { 3727 // Polling has completed 3728 } 3729 break; 3730 case CMD_ENABLE_RSSI_POLL: 3731 mEnableRssiPolling = (message.arg1 == 1); 3732 mRssiPollToken++; 3733 if (mEnableRssiPolling) { 3734 // first poll 3735 fetchRssiAndLinkSpeedNative(); 3736 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 3737 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 3738 } 3739 break; 3740 case WifiManager.RSSI_PKTCNT_FETCH: 3741 RssiPacketCountInfo info = new RssiPacketCountInfo(); 3742 fetchRssiAndLinkSpeedNative(); 3743 info.rssi = mWifiInfo.getRssi(); 3744 fetchPktcntNative(info); 3745 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info); 3746 break; 3747 default: 3748 return NOT_HANDLED; 3749 } 3750 3751 return HANDLED; 3752 } 3753 } 3754 3755 class ObtainingIpState extends State { 3756 @Override 3757 public void enter() { 3758 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 3759 // TODO: If we're switching between static IP configuration and DHCP, remove the 3760 // static configuration first. 3761 startDhcp(); 3762 } else { 3763 // stop any running dhcp before assigning static IP 3764 stopDhcp(); 3765 DhcpResults dhcpResults = new DhcpResults( 3766 mWifiConfigStore.getLinkProperties(mLastNetworkId)); 3767 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 3768 Iterator<LinkAddress> addrs = 3769 dhcpResults.linkProperties.getLinkAddresses().iterator(); 3770 if (!addrs.hasNext()) { 3771 loge("Static IP lacks address"); 3772 sendMessage(CMD_STATIC_IP_FAILURE); 3773 } else { 3774 ifcg.setLinkAddress(addrs.next()); 3775 ifcg.setInterfaceUp(); 3776 try { 3777 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 3778 if (DBG) log("Static IP configuration succeeded"); 3779 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults); 3780 } catch (RemoteException re) { 3781 loge("Static IP configuration failed: " + re); 3782 sendMessage(CMD_STATIC_IP_FAILURE); 3783 } catch (IllegalStateException e) { 3784 loge("Static IP configuration failed: " + e); 3785 sendMessage(CMD_STATIC_IP_FAILURE); 3786 } 3787 } 3788 } 3789 } 3790 @Override 3791 public boolean processMessage(Message message) { 3792 if (DBG) log(getName() + message.toString() + "\n"); 3793 switch(message.what) { 3794 case CMD_STATIC_IP_SUCCESS: 3795 handleSuccessfulIpConfiguration((DhcpResults) message.obj); 3796 transitionTo(mVerifyingLinkState); 3797 break; 3798 case CMD_STATIC_IP_FAILURE: 3799 handleFailedIpConfiguration(); 3800 transitionTo(mDisconnectingState); 3801 break; 3802 case WifiManager.SAVE_NETWORK: 3803 deferMessage(message); 3804 break; 3805 /* Defer any power mode changes since we must keep active power mode at DHCP */ 3806 case CMD_SET_HIGH_PERF_MODE: 3807 deferMessage(message); 3808 break; 3809 /* Defer scan request since we should not switch to other channels at DHCP */ 3810 case CMD_START_SCAN: 3811 deferMessage(message); 3812 break; 3813 default: 3814 return NOT_HANDLED; 3815 } 3816 return HANDLED; 3817 } 3818 } 3819 3820 class VerifyingLinkState extends State { 3821 @Override 3822 public void enter() { 3823 log(getName() + " enter"); 3824 setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); 3825 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); 3826 sendNetworkStateChangeBroadcast(mLastBssid); 3827 } 3828 @Override 3829 public boolean processMessage(Message message) { 3830 switch (message.what) { 3831 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 3832 //stay here 3833 log(getName() + " POOR_LINK_DETECTED: no transition"); 3834 break; 3835 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 3836 log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); 3837 transitionTo(mCaptivePortalCheckState); 3838 break; 3839 default: 3840 if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); 3841 return NOT_HANDLED; 3842 } 3843 return HANDLED; 3844 } 3845 } 3846 3847 class CaptivePortalCheckState extends State { 3848 @Override 3849 public void enter() { 3850 log(getName() + " enter"); 3851 setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); 3852 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CAPTIVE_PORTAL_CHECK); 3853 sendNetworkStateChangeBroadcast(mLastBssid); 3854 } 3855 @Override 3856 public boolean processMessage(Message message) { 3857 switch (message.what) { 3858 case CMD_CAPTIVE_CHECK_COMPLETE: 3859 log(getName() + " CMD_CAPTIVE_CHECK_COMPLETE"); 3860 try { 3861 mNwService.enableIpv6(mInterfaceName); 3862 } catch (RemoteException re) { 3863 loge("Failed to enable IPv6: " + re); 3864 } catch (IllegalStateException e) { 3865 loge("Failed to enable IPv6: " + e); 3866 } 3867 setNetworkDetailedState(DetailedState.CONNECTED); 3868 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); 3869 sendNetworkStateChangeBroadcast(mLastBssid); 3870 transitionTo(mConnectedState); 3871 break; 3872 default: 3873 return NOT_HANDLED; 3874 } 3875 return HANDLED; 3876 } 3877 } 3878 3879 class ConnectedState extends State { 3880 @Override 3881 public boolean processMessage(Message message) { 3882 switch (message.what) { 3883 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 3884 if (DBG) log("Watchdog reports poor link"); 3885 try { 3886 mNwService.disableIpv6(mInterfaceName); 3887 } catch (RemoteException re) { 3888 loge("Failed to disable IPv6: " + re); 3889 } catch (IllegalStateException e) { 3890 loge("Failed to disable IPv6: " + e); 3891 } 3892 /* Report a disconnect */ 3893 setNetworkDetailedState(DetailedState.DISCONNECTED); 3894 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 3895 sendNetworkStateChangeBroadcast(mLastBssid); 3896 3897 transitionTo(mVerifyingLinkState); 3898 break; 3899 default: 3900 return NOT_HANDLED; 3901 } 3902 return HANDLED; 3903 } 3904 @Override 3905 public void exit() { 3906 /* Request a CS wakelock during transition to mobile */ 3907 checkAndSetConnectivityInstance(); 3908 mCm.requestNetworkTransitionWakelock(getName()); 3909 } 3910 } 3911 3912 class DisconnectingState extends State { 3913 @Override 3914 public boolean processMessage(Message message) { 3915 switch (message.what) { 3916 case CMD_SET_OPERATIONAL_MODE: 3917 if (message.arg1 != CONNECT_MODE) { 3918 deferMessage(message); 3919 } 3920 break; 3921 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3922 /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT 3923 * we have missed the network disconnection, transition to mDisconnectedState 3924 * and handle the rest of the events there 3925 */ 3926 deferMessage(message); 3927 handleNetworkDisconnect(); 3928 transitionTo(mDisconnectedState); 3929 break; 3930 default: 3931 return NOT_HANDLED; 3932 } 3933 return HANDLED; 3934 } 3935 } 3936 3937 class DisconnectedState extends State { 3938 private boolean mAlarmEnabled = false; 3939 /* This is set from the overlay config file or from a secure setting. 3940 * A value of 0 disables scanning in the framework. 3941 */ 3942 private long mFrameworkScanIntervalMs; 3943 3944 private void setScanAlarm(boolean enabled) { 3945 if (enabled == mAlarmEnabled) return; 3946 if (enabled) { 3947 if (mFrameworkScanIntervalMs > 0) { 3948 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 3949 System.currentTimeMillis() + mFrameworkScanIntervalMs, 3950 mFrameworkScanIntervalMs, 3951 mScanIntent); 3952 mAlarmEnabled = true; 3953 } 3954 } else { 3955 mAlarmManager.cancel(mScanIntent); 3956 mAlarmEnabled = false; 3957 } 3958 } 3959 3960 @Override 3961 public void enter() { 3962 // We dont scan frequently if this is a temporary disconnect 3963 // due to p2p 3964 if (mTemporarilyDisconnectWifi) { 3965 mWifiP2pChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_RESPONSE); 3966 return; 3967 } 3968 3969 mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 3970 Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS, 3971 mDefaultFrameworkScanIntervalMs); 3972 /* 3973 * We initiate background scanning if it is enabled, otherwise we 3974 * initiate an infrequent scan that wakes up the device to ensure 3975 * a user connects to an access point on the move 3976 */ 3977 if (mEnableBackgroundScan) { 3978 /* If a regular scan result is pending, do not initiate background 3979 * scan until the scan results are returned. This is needed because 3980 * initiating a background scan will cancel the regular scan and 3981 * scan results will not be returned until background scanning is 3982 * cleared 3983 */ 3984 if (!mScanResultIsPending) { 3985 mWifiNative.enableBackgroundScan(true); 3986 } 3987 } else { 3988 setScanAlarm(true); 3989 } 3990 3991 /** 3992 * If we have no networks saved, the supplicant stops doing the periodic scan. 3993 * The scans are useful to notify the user of the presence of an open network. 3994 * Note that these are not wake up scans. 3995 */ 3996 if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) { 3997 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 3998 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 3999 } 4000 } 4001 @Override 4002 public boolean processMessage(Message message) { 4003 boolean ret = HANDLED; 4004 switch (message.what) { 4005 case CMD_NO_NETWORKS_PERIODIC_SCAN: 4006 if (mP2pConnected.get()) break; 4007 if (message.arg1 == mPeriodicScanToken && 4008 mWifiConfigStore.getConfiguredNetworks().size() == 0) { 4009 sendMessage(CMD_START_SCAN, UNKNOWN_SCAN_SOURCE, 0, (WorkSource) null); 4010 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 4011 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 4012 } 4013 break; 4014 case WifiManager.FORGET_NETWORK: 4015 case CMD_REMOVE_NETWORK: 4016 // Set up a delayed message here. After the forget/remove is handled 4017 // the handled delayed message will determine if there is a need to 4018 // scan and continue 4019 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 4020 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 4021 ret = NOT_HANDLED; 4022 break; 4023 case CMD_SET_OPERATIONAL_MODE: 4024 if (message.arg1 != CONNECT_MODE) { 4025 mOperationalMode = message.arg1; 4026 4027 mWifiConfigStore.disableAllNetworks(); 4028 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 4029 mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); 4030 setWifiState(WIFI_STATE_DISABLED); 4031 } 4032 4033 transitionTo(mScanModeState); 4034 } 4035 break; 4036 case CMD_ENABLE_BACKGROUND_SCAN: 4037 mEnableBackgroundScan = (message.arg1 == 1); 4038 if (mEnableBackgroundScan) { 4039 mWifiNative.enableBackgroundScan(true); 4040 setScanAlarm(false); 4041 } else { 4042 mWifiNative.enableBackgroundScan(false); 4043 setScanAlarm(true); 4044 } 4045 break; 4046 /* Ignore network disconnect */ 4047 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 4048 break; 4049 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4050 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 4051 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 4052 /* ConnectModeState does the rest of the handling */ 4053 ret = NOT_HANDLED; 4054 break; 4055 case CMD_START_SCAN: 4056 /* Disable background scan temporarily during a regular scan */ 4057 if (mEnableBackgroundScan) { 4058 mWifiNative.enableBackgroundScan(false); 4059 } 4060 /* Handled in parent state */ 4061 ret = NOT_HANDLED; 4062 break; 4063 case WifiMonitor.SCAN_RESULTS_EVENT: 4064 /* Re-enable background scan when a pending scan result is received */ 4065 if (mEnableBackgroundScan && mScanResultIsPending) { 4066 mWifiNative.enableBackgroundScan(true); 4067 } 4068 /* Handled in parent state */ 4069 ret = NOT_HANDLED; 4070 break; 4071 case WifiP2pService.P2P_CONNECTION_CHANGED: 4072 NetworkInfo info = (NetworkInfo) message.obj; 4073 mP2pConnected.set(info.isConnected()); 4074 if (mP2pConnected.get()) { 4075 int defaultInterval = mContext.getResources().getInteger( 4076 R.integer.config_wifi_scan_interval_p2p_connected); 4077 long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 4078 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 4079 defaultInterval); 4080 mWifiNative.setScanInterval((int) scanIntervalMs/1000); 4081 } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { 4082 if (DBG) log("Turn on scanning after p2p disconnected"); 4083 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 4084 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 4085 } 4086 case CMD_RECONNECT: 4087 case CMD_REASSOCIATE: 4088 if (mTemporarilyDisconnectWifi) { 4089 // Drop a third party reconnect/reassociate if STA is 4090 // temporarily disconnected for p2p 4091 break; 4092 } else { 4093 // ConnectModeState handles it 4094 ret = NOT_HANDLED; 4095 } 4096 break; 4097 default: 4098 ret = NOT_HANDLED; 4099 } 4100 return ret; 4101 } 4102 4103 @Override 4104 public void exit() { 4105 /* No need for a background scan upon exit from a disconnected state */ 4106 if (mEnableBackgroundScan) { 4107 mWifiNative.enableBackgroundScan(false); 4108 } 4109 setScanAlarm(false); 4110 } 4111 } 4112 4113 class WpsRunningState extends State { 4114 //Tracks the source to provide a reply 4115 private Message mSourceMessage; 4116 @Override 4117 public void enter() { 4118 mSourceMessage = Message.obtain(getCurrentMessage()); 4119 } 4120 @Override 4121 public boolean processMessage(Message message) { 4122 switch (message.what) { 4123 case WifiMonitor.WPS_SUCCESS_EVENT: 4124 // Ignore intermediate success, wait for full connection 4125 break; 4126 case WifiMonitor.NETWORK_CONNECTION_EVENT: 4127 replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED); 4128 mSourceMessage.recycle(); 4129 mSourceMessage = null; 4130 deferMessage(message); 4131 transitionTo(mDisconnectedState); 4132 break; 4133 case WifiMonitor.WPS_OVERLAP_EVENT: 4134 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 4135 WifiManager.WPS_OVERLAP_ERROR); 4136 mSourceMessage.recycle(); 4137 mSourceMessage = null; 4138 transitionTo(mDisconnectedState); 4139 break; 4140 case WifiMonitor.WPS_FAIL_EVENT: 4141 //arg1 has the reason for the failure 4142 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1); 4143 mSourceMessage.recycle(); 4144 mSourceMessage = null; 4145 transitionTo(mDisconnectedState); 4146 break; 4147 case WifiMonitor.WPS_TIMEOUT_EVENT: 4148 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 4149 WifiManager.WPS_TIMED_OUT); 4150 mSourceMessage.recycle(); 4151 mSourceMessage = null; 4152 transitionTo(mDisconnectedState); 4153 break; 4154 case WifiManager.START_WPS: 4155 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS); 4156 break; 4157 case WifiManager.CANCEL_WPS: 4158 if (mWifiNative.cancelWps()) { 4159 replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED); 4160 } else { 4161 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR); 4162 } 4163 transitionTo(mDisconnectedState); 4164 break; 4165 /* Defer all commands that can cause connections to a different network 4166 * or put the state machine out of connect mode 4167 */ 4168 case CMD_STOP_DRIVER: 4169 case CMD_SET_OPERATIONAL_MODE: 4170 case WifiManager.CONNECT_NETWORK: 4171 case CMD_ENABLE_NETWORK: 4172 case CMD_RECONNECT: 4173 case CMD_REASSOCIATE: 4174 deferMessage(message); 4175 break; 4176 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 4177 if (DBG) log("Network connection lost"); 4178 handleNetworkDisconnect(); 4179 break; 4180 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 4181 if (DBG) log("Ignore Assoc reject event during WPS Connection"); 4182 break; 4183 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 4184 // Disregard auth failure events during WPS connection. The 4185 // EAP sequence is retried several times, and there might be 4186 // failures (especially for wps pin). We will get a WPS_XXX 4187 // event at the end of the sequence anyway. 4188 if (DBG) log("Ignore auth failure during WPS connection"); 4189 break; 4190 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4191 //Throw away supplicant state changes when WPS is running. 4192 //We will start getting supplicant state changes once we get 4193 //a WPS success or failure 4194 break; 4195 default: 4196 return NOT_HANDLED; 4197 } 4198 return HANDLED; 4199 } 4200 4201 @Override 4202 public void exit() { 4203 mWifiConfigStore.enableAllNetworks(); 4204 mWifiConfigStore.loadConfiguredNetworks(); 4205 } 4206 } 4207 4208 class SoftApStartingState extends State { 4209 @Override 4210 public void enter() { 4211 final Message message = getCurrentMessage(); 4212 if (message.what == CMD_START_AP) { 4213 final WifiConfiguration config = (WifiConfiguration) message.obj; 4214 4215 if (config == null) { 4216 mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); 4217 } else { 4218 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 4219 startSoftApWithConfig(config); 4220 } 4221 } else { 4222 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); 4223 } 4224 } 4225 @Override 4226 public boolean processMessage(Message message) { 4227 switch(message.what) { 4228 case CMD_START_SUPPLICANT: 4229 case CMD_STOP_SUPPLICANT: 4230 case CMD_START_AP: 4231 case CMD_STOP_AP: 4232 case CMD_START_DRIVER: 4233 case CMD_STOP_DRIVER: 4234 case CMD_SET_OPERATIONAL_MODE: 4235 case CMD_SET_COUNTRY_CODE: 4236 case CMD_SET_FREQUENCY_BAND: 4237 case CMD_START_PACKET_FILTERING: 4238 case CMD_STOP_PACKET_FILTERING: 4239 case CMD_TETHER_STATE_CHANGE: 4240 deferMessage(message); 4241 break; 4242 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: 4243 WifiConfiguration config = (WifiConfiguration) message.obj; 4244 if (config != null) { 4245 startSoftApWithConfig(config); 4246 } else { 4247 loge("Softap config is null!"); 4248 sendMessage(CMD_START_AP_FAILURE); 4249 } 4250 break; 4251 case CMD_START_AP_SUCCESS: 4252 setWifiApState(WIFI_AP_STATE_ENABLED); 4253 transitionTo(mSoftApStartedState); 4254 break; 4255 case CMD_START_AP_FAILURE: 4256 setWifiApState(WIFI_AP_STATE_FAILED); 4257 transitionTo(mInitialState); 4258 break; 4259 default: 4260 return NOT_HANDLED; 4261 } 4262 return HANDLED; 4263 } 4264 } 4265 4266 class SoftApStartedState extends State { 4267 @Override 4268 public boolean processMessage(Message message) { 4269 switch(message.what) { 4270 case CMD_STOP_AP: 4271 if (DBG) log("Stopping Soft AP"); 4272 /* We have not tethered at this point, so we just shutdown soft Ap */ 4273 try { 4274 mNwService.stopAccessPoint(mInterfaceName); 4275 } catch(Exception e) { 4276 loge("Exception in stopAccessPoint()"); 4277 } 4278 setWifiApState(WIFI_AP_STATE_DISABLED); 4279 transitionTo(mInitialState); 4280 break; 4281 case CMD_START_AP: 4282 // Ignore a start on a running access point 4283 break; 4284 /* Fail client mode operation when soft AP is enabled */ 4285 case CMD_START_SUPPLICANT: 4286 loge("Cannot start supplicant with a running soft AP"); 4287 setWifiState(WIFI_STATE_UNKNOWN); 4288 break; 4289 case CMD_TETHER_STATE_CHANGE: 4290 TetherStateChange stateChange = (TetherStateChange) message.obj; 4291 if (startTethering(stateChange.available)) { 4292 transitionTo(mTetheringState); 4293 } 4294 break; 4295 default: 4296 return NOT_HANDLED; 4297 } 4298 return HANDLED; 4299 } 4300 } 4301 4302 class TetheringState extends State { 4303 @Override 4304 public void enter() { 4305 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 4306 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 4307 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 4308 } 4309 @Override 4310 public boolean processMessage(Message message) { 4311 switch(message.what) { 4312 case CMD_TETHER_STATE_CHANGE: 4313 TetherStateChange stateChange = (TetherStateChange) message.obj; 4314 if (isWifiTethered(stateChange.active)) { 4315 transitionTo(mTetheredState); 4316 } 4317 return HANDLED; 4318 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 4319 if (message.arg1 == mTetherToken) { 4320 loge("Failed to get tether update, shutdown soft access point"); 4321 transitionTo(mSoftApStartedState); 4322 // Needs to be first thing handled 4323 sendMessageAtFrontOfQueue(CMD_STOP_AP); 4324 } 4325 break; 4326 case CMD_START_SUPPLICANT: 4327 case CMD_STOP_SUPPLICANT: 4328 case CMD_START_AP: 4329 case CMD_STOP_AP: 4330 case CMD_START_DRIVER: 4331 case CMD_STOP_DRIVER: 4332 case CMD_SET_OPERATIONAL_MODE: 4333 case CMD_SET_COUNTRY_CODE: 4334 case CMD_SET_FREQUENCY_BAND: 4335 case CMD_START_PACKET_FILTERING: 4336 case CMD_STOP_PACKET_FILTERING: 4337 deferMessage(message); 4338 break; 4339 default: 4340 return NOT_HANDLED; 4341 } 4342 return HANDLED; 4343 } 4344 } 4345 4346 class TetheredState extends State { 4347 @Override 4348 public boolean processMessage(Message message) { 4349 switch(message.what) { 4350 case CMD_TETHER_STATE_CHANGE: 4351 TetherStateChange stateChange = (TetherStateChange) message.obj; 4352 if (!isWifiTethered(stateChange.active)) { 4353 loge("Tethering reports wifi as untethered!, shut down soft Ap"); 4354 setHostApRunning(null, false); 4355 setHostApRunning(null, true); 4356 } 4357 return HANDLED; 4358 case CMD_STOP_AP: 4359 if (DBG) log("Untethering before stopping AP"); 4360 setWifiApState(WIFI_AP_STATE_DISABLING); 4361 stopTethering(); 4362 transitionTo(mUntetheringState); 4363 // More work to do after untethering 4364 deferMessage(message); 4365 break; 4366 default: 4367 return NOT_HANDLED; 4368 } 4369 return HANDLED; 4370 } 4371 } 4372 4373 class UntetheringState extends State { 4374 @Override 4375 public void enter() { 4376 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 4377 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 4378 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 4379 4380 } 4381 @Override 4382 public boolean processMessage(Message message) { 4383 switch(message.what) { 4384 case CMD_TETHER_STATE_CHANGE: 4385 TetherStateChange stateChange = (TetherStateChange) message.obj; 4386 4387 /* Wait till wifi is untethered */ 4388 if (isWifiTethered(stateChange.active)) break; 4389 4390 transitionTo(mSoftApStartedState); 4391 break; 4392 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 4393 if (message.arg1 == mTetherToken) { 4394 loge("Failed to get tether update, force stop access point"); 4395 transitionTo(mSoftApStartedState); 4396 } 4397 break; 4398 case CMD_START_SUPPLICANT: 4399 case CMD_STOP_SUPPLICANT: 4400 case CMD_START_AP: 4401 case CMD_STOP_AP: 4402 case CMD_START_DRIVER: 4403 case CMD_STOP_DRIVER: 4404 case CMD_SET_OPERATIONAL_MODE: 4405 case CMD_SET_COUNTRY_CODE: 4406 case CMD_SET_FREQUENCY_BAND: 4407 case CMD_START_PACKET_FILTERING: 4408 case CMD_STOP_PACKET_FILTERING: 4409 deferMessage(message); 4410 break; 4411 default: 4412 return NOT_HANDLED; 4413 } 4414 return HANDLED; 4415 } 4416 } 4417 4418 //State machine initiated requests can have replyTo set to null indicating 4419 //there are no recepients, we ignore those reply actions 4420 private void replyToMessage(Message msg, int what) { 4421 if (msg.replyTo == null) return; 4422 Message dstMsg = obtainMessageWithArg2(msg); 4423 dstMsg.what = what; 4424 mReplyChannel.replyToMessage(msg, dstMsg); 4425 } 4426 4427 private void replyToMessage(Message msg, int what, int arg1) { 4428 if (msg.replyTo == null) return; 4429 Message dstMsg = obtainMessageWithArg2(msg); 4430 dstMsg.what = what; 4431 dstMsg.arg1 = arg1; 4432 mReplyChannel.replyToMessage(msg, dstMsg); 4433 } 4434 4435 private void replyToMessage(Message msg, int what, Object obj) { 4436 if (msg.replyTo == null) return; 4437 Message dstMsg = obtainMessageWithArg2(msg); 4438 dstMsg.what = what; 4439 dstMsg.obj = obj; 4440 mReplyChannel.replyToMessage(msg, dstMsg); 4441 } 4442 4443 /** 4444 * arg2 on the source message has a unique id that needs to be retained in replies 4445 * to match the request 4446 4447 * see WifiManager for details 4448 */ 4449 private Message obtainMessageWithArg2(Message srcMsg) { 4450 Message msg = Message.obtain(); 4451 msg.arg2 = srcMsg.arg2; 4452 return msg; 4453 } 4454 } 4455