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