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