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