WifiStateMachine.java revision 785c09f2ae609a580a620d1a45529881ea958f84
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 mWifiConfigStore.loadAndEnableAllNetworks(); 2901 initializeWpsDetails(); 2902 2903 sendSupplicantConnectionChangedBroadcast(true); 2904 transitionTo(mDriverStartedState); 2905 break; 2906 case WifiMonitor.SUP_DISCONNECTION_EVENT: 2907 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { 2908 loge("Failed to setup control channel, restart supplicant"); 2909 mWifiMonitor.killSupplicant(mP2pSupported); 2910 transitionTo(mInitialState); 2911 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 2912 } else { 2913 loge("Failed " + mSupplicantRestartCount + 2914 " times to start supplicant, unload driver"); 2915 mSupplicantRestartCount = 0; 2916 setWifiState(WIFI_STATE_UNKNOWN); 2917 transitionTo(mInitialState); 2918 } 2919 break; 2920 case CMD_START_SUPPLICANT: 2921 case CMD_STOP_SUPPLICANT: 2922 case CMD_START_AP: 2923 case CMD_STOP_AP: 2924 case CMD_START_DRIVER: 2925 case CMD_STOP_DRIVER: 2926 case CMD_SET_OPERATIONAL_MODE: 2927 case CMD_SET_COUNTRY_CODE: 2928 case CMD_SET_FREQUENCY_BAND: 2929 case CMD_START_PACKET_FILTERING: 2930 case CMD_STOP_PACKET_FILTERING: 2931 deferMessage(message); 2932 break; 2933 default: 2934 return NOT_HANDLED; 2935 } 2936 return HANDLED; 2937 } 2938 } 2939 2940 class SupplicantStartedState extends State { 2941 @Override 2942 public void enter() { 2943 /* Wifi is available as long as we have a connection to supplicant */ 2944 mNetworkInfo.setIsAvailable(true); 2945 2946 int defaultInterval = mContext.getResources().getInteger( 2947 R.integer.config_wifi_supplicant_scan_interval); 2948 2949 mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 2950 Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, 2951 defaultInterval); 2952 2953 mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000); 2954 } 2955 @Override 2956 public boolean processMessage(Message message) { 2957 switch(message.what) { 2958 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ 2959 if (mP2pSupported) { 2960 transitionTo(mWaitForP2pDisableState); 2961 } else { 2962 transitionTo(mSupplicantStoppingState); 2963 } 2964 break; 2965 case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ 2966 loge("Connection lost, restart supplicant"); 2967 handleSupplicantConnectionLoss(); 2968 handleNetworkDisconnect(); 2969 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2970 if (mP2pSupported) { 2971 transitionTo(mWaitForP2pDisableState); 2972 } else { 2973 transitionTo(mInitialState); 2974 } 2975 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 2976 break; 2977 case WifiMonitor.SCAN_RESULTS_EVENT: 2978 setScanResults(); 2979 sendScanResultsAvailableBroadcast(); 2980 mIsScanOngoing = false; 2981 mIsFullScanOngoing = false; 2982 if (mBufferedScanMsg.size() > 0) 2983 sendMessage(mBufferedScanMsg.remove()); 2984 break; 2985 case CMD_PING_SUPPLICANT: 2986 boolean ok = mWifiNative.ping(); 2987 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 2988 break; 2989 case CMD_GET_CAPABILITY_FREQ: 2990 String freqs = mWifiNative.getFreqCapability(); 2991 replyToMessage(message, message.what, freqs); 2992 break; 2993 case CMD_START_AP: 2994 /* Cannot start soft AP while in client mode */ 2995 loge("Failed to start soft AP with a running supplicant"); 2996 setWifiApState(WIFI_AP_STATE_FAILED); 2997 break; 2998 case CMD_SET_OPERATIONAL_MODE: 2999 mOperationalMode = message.arg1; 3000 break; 3001 default: 3002 return NOT_HANDLED; 3003 } 3004 return HANDLED; 3005 } 3006 3007 @Override 3008 public void exit() { 3009 mNetworkInfo.setIsAvailable(false); 3010 } 3011 } 3012 3013 class SupplicantStoppingState extends State { 3014 @Override 3015 public void enter() { 3016 /* Send any reset commands to supplicant before shutting it down */ 3017 handleNetworkDisconnect(); 3018 if (mDhcpStateMachine != null) { 3019 mDhcpStateMachine.doQuit(); 3020 } 3021 3022 if (DBG) log("stopping supplicant"); 3023 mWifiMonitor.stopSupplicant(); 3024 3025 /* Send ourselves a delayed message to indicate failure after a wait time */ 3026 sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED, 3027 ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS); 3028 setWifiState(WIFI_STATE_DISABLING); 3029 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 3030 } 3031 @Override 3032 public boolean processMessage(Message message) { 3033 switch(message.what) { 3034 case WifiMonitor.SUP_CONNECTION_EVENT: 3035 loge("Supplicant connection received while stopping"); 3036 break; 3037 case WifiMonitor.SUP_DISCONNECTION_EVENT: 3038 if (DBG) log("Supplicant connection lost"); 3039 handleSupplicantConnectionLoss(); 3040 transitionTo(mInitialState); 3041 break; 3042 case CMD_STOP_SUPPLICANT_FAILED: 3043 if (message.arg1 == mSupplicantStopFailureToken) { 3044 loge("Timed out on a supplicant stop, kill and proceed"); 3045 handleSupplicantConnectionLoss(); 3046 transitionTo(mInitialState); 3047 } 3048 break; 3049 case CMD_START_SUPPLICANT: 3050 case CMD_STOP_SUPPLICANT: 3051 case CMD_START_AP: 3052 case CMD_STOP_AP: 3053 case CMD_START_DRIVER: 3054 case CMD_STOP_DRIVER: 3055 case CMD_SET_OPERATIONAL_MODE: 3056 case CMD_SET_COUNTRY_CODE: 3057 case CMD_SET_FREQUENCY_BAND: 3058 case CMD_START_PACKET_FILTERING: 3059 case CMD_STOP_PACKET_FILTERING: 3060 deferMessage(message); 3061 break; 3062 default: 3063 return NOT_HANDLED; 3064 } 3065 return HANDLED; 3066 } 3067 } 3068 3069 class DriverStartingState extends State { 3070 private int mTries; 3071 @Override 3072 public void enter() { 3073 mTries = 1; 3074 /* Send ourselves a delayed message to start driver a second time */ 3075 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 3076 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 3077 } 3078 @Override 3079 public boolean processMessage(Message message) { 3080 switch(message.what) { 3081 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3082 SupplicantState state = handleSupplicantStateChange(message); 3083 /* If suplicant is exiting out of INTERFACE_DISABLED state into 3084 * a state that indicates driver has started, it is ready to 3085 * receive driver commands 3086 */ 3087 if (SupplicantState.isDriverActive(state)) { 3088 transitionTo(mDriverStartedState); 3089 } 3090 break; 3091 case CMD_DRIVER_START_TIMED_OUT: 3092 if (message.arg1 == mDriverStartToken) { 3093 if (mTries >= 2) { 3094 loge("Failed to start driver after " + mTries); 3095 transitionTo(mDriverStoppedState); 3096 } else { 3097 loge("Driver start failed, retrying"); 3098 mWakeLock.acquire(); 3099 mWifiNative.startDriver(); 3100 mWakeLock.release(); 3101 3102 ++mTries; 3103 /* Send ourselves a delayed message to start driver again */ 3104 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 3105 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 3106 } 3107 } 3108 break; 3109 /* Queue driver commands & connection events */ 3110 case CMD_START_DRIVER: 3111 case CMD_STOP_DRIVER: 3112 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3113 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 3114 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 3115 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 3116 case WifiMonitor.WPS_OVERLAP_EVENT: 3117 case CMD_SET_COUNTRY_CODE: 3118 case CMD_SET_FREQUENCY_BAND: 3119 case CMD_START_PACKET_FILTERING: 3120 case CMD_STOP_PACKET_FILTERING: 3121 case CMD_START_SCAN: 3122 case CMD_DISCONNECT: 3123 case CMD_REASSOCIATE: 3124 case CMD_RECONNECT: 3125 deferMessage(message); 3126 break; 3127 default: 3128 return NOT_HANDLED; 3129 } 3130 return HANDLED; 3131 } 3132 } 3133 3134 class DriverStartedState extends State { 3135 @Override 3136 public void enter() { 3137 mIsRunning = true; 3138 mInDelayedStop = false; 3139 mDelayedStopCounter++; 3140 updateBatteryWorkSource(null); 3141 /** 3142 * Enable bluetooth coexistence scan mode when bluetooth connection is active. 3143 * When this mode is on, some of the low-level scan parameters used by the 3144 * driver are changed to reduce interference with bluetooth 3145 */ 3146 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 3147 /* set country code */ 3148 setCountryCode(); 3149 /* set frequency band of operation */ 3150 setFrequencyBand(); 3151 /* initialize network state */ 3152 setNetworkDetailedState(DetailedState.DISCONNECTED); 3153 3154 /* Remove any filtering on Multicast v6 at start */ 3155 mWifiNative.stopFilteringMulticastV6Packets(); 3156 3157 /* Reset Multicast v4 filtering state */ 3158 if (mFilteringMulticastV4Packets.get()) { 3159 mWifiNative.startFilteringMulticastV4Packets(); 3160 } else { 3161 mWifiNative.stopFilteringMulticastV4Packets(); 3162 } 3163 3164 mDhcpActive = false; 3165 3166 startBatchedScan(); 3167 3168 if (mOperationalMode != CONNECT_MODE) { 3169 mWifiNative.disconnect(); 3170 mWifiConfigStore.disableAllNetworks(); 3171 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 3172 setWifiState(WIFI_STATE_DISABLED); 3173 } 3174 transitionTo(mScanModeState); 3175 } else { 3176 /* Driver stop may have disabled networks, enable right after start */ 3177 mWifiConfigStore.enableAllNetworks(); 3178 3179 if (DBG) log("Attempting to reconnect to wifi network .."); 3180 mWifiNative.reconnect(); 3181 3182 // Status pulls in the current supplicant state and network connection state 3183 // events over the monitor connection. This helps framework sync up with 3184 // current supplicant state 3185 mWifiNative.status(); 3186 transitionTo(mDisconnectedState); 3187 } 3188 3189 // We may have missed screen update at boot 3190 if (mScreenBroadcastReceived.get() == false) { 3191 PowerManager powerManager = (PowerManager)mContext.getSystemService( 3192 Context.POWER_SERVICE); 3193 handleScreenStateChanged(powerManager.isScreenOn()); 3194 } else { 3195 // Set the right suspend mode settings 3196 mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0 3197 && mUserWantsSuspendOpt.get()); 3198 } 3199 mWifiNative.setPowerSave(true); 3200 3201 if (mP2pSupported) { 3202 if (mOperationalMode == CONNECT_MODE) { 3203 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); 3204 } else { 3205 // P2P statemachine starts in disabled state, and is not enabled until 3206 // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to 3207 // keep it disabled. 3208 } 3209 } 3210 3211 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 3212 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3213 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED); 3214 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3215 } 3216 3217 @Override 3218 public boolean processMessage(Message message) { 3219 switch(message.what) { 3220 case CMD_START_SCAN: 3221 handleScanRequest(WifiNative.SCAN_WITH_CONNECTION_SETUP, message); 3222 break; 3223 case CMD_SET_BATCHED_SCAN: 3224 if (recordBatchedScanSettings(message.arg1, message.arg2, 3225 (Bundle)message.obj)) { 3226 startBatchedScan(); 3227 } 3228 break; 3229 case CMD_SET_COUNTRY_CODE: 3230 String country = (String) message.obj; 3231 final boolean persist = (message.arg2 == 1); 3232 final int sequence = message.arg1; 3233 if (sequence != mCountryCodeSequence.get()) { 3234 if (DBG) log("set country code ignored due to sequnce num"); 3235 break; 3236 } 3237 if (DBG) log("set country code " + country); 3238 if (persist) { 3239 mPersistedCountryCode = country; 3240 Settings.Global.putString(mContext.getContentResolver(), 3241 Settings.Global.WIFI_COUNTRY_CODE, 3242 country); 3243 } 3244 country = country.toUpperCase(Locale.ROOT); 3245 if (mLastSetCountryCode == null 3246 || country.equals(mLastSetCountryCode) == false) { 3247 if (mWifiNative.setCountryCode(country)) { 3248 mLastSetCountryCode = country; 3249 } else { 3250 loge("Failed to set country code " + country); 3251 } 3252 } 3253 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.SET_COUNTRY_CODE, country); 3254 break; 3255 case CMD_SET_FREQUENCY_BAND: 3256 int band = message.arg1; 3257 if (DBG) log("set frequency band " + band); 3258 if (mWifiNative.setBand(band)) { 3259 mFrequencyBand.set(band); 3260 // flush old data - like scan results 3261 mWifiNative.bssFlush(); 3262 // fetch the latest scan results when frequency band is set 3263 startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP, null); 3264 } else { 3265 loge("Failed to set frequency band " + band); 3266 } 3267 break; 3268 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 3269 mBluetoothConnectionActive = (message.arg1 != 3270 BluetoothAdapter.STATE_DISCONNECTED); 3271 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 3272 break; 3273 case CMD_STOP_DRIVER: 3274 int mode = message.arg1; 3275 3276 /* Already doing a delayed stop */ 3277 if (mInDelayedStop) { 3278 if (DBG) log("Already in delayed stop"); 3279 break; 3280 } 3281 /* disconnect right now, but leave the driver running for a bit */ 3282 mWifiConfigStore.disableAllNetworks(); 3283 3284 mInDelayedStop = true; 3285 mDelayedStopCounter++; 3286 if (DBG) log("Delayed stop message " + mDelayedStopCounter); 3287 3288 /* send regular delayed shut down */ 3289 Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); 3290 driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); 3291 mDriverStopIntent = PendingIntent.getBroadcast(mContext, 3292 DRIVER_STOP_REQUEST, driverStopIntent, 3293 PendingIntent.FLAG_UPDATE_CURRENT); 3294 3295 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 3296 + mDriverStopDelayMs, mDriverStopIntent); 3297 break; 3298 case CMD_START_DRIVER: 3299 if (mInDelayedStop) { 3300 mInDelayedStop = false; 3301 mDelayedStopCounter++; 3302 mAlarmManager.cancel(mDriverStopIntent); 3303 if (DBG) log("Delayed stop ignored due to start"); 3304 if (mOperationalMode == CONNECT_MODE) { 3305 mWifiConfigStore.enableAllNetworks(); 3306 } 3307 } 3308 break; 3309 case CMD_DELAYED_STOP_DRIVER: 3310 if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter); 3311 if (message.arg1 != mDelayedStopCounter) break; 3312 if (getCurrentState() != mDisconnectedState) { 3313 mWifiNative.disconnect(); 3314 handleNetworkDisconnect(); 3315 } 3316 mWakeLock.acquire(); 3317 mWifiNative.stopDriver(); 3318 mWakeLock.release(); 3319 if (mP2pSupported) { 3320 transitionTo(mWaitForP2pDisableState); 3321 } else { 3322 transitionTo(mDriverStoppingState); 3323 } 3324 break; 3325 case CMD_START_PACKET_FILTERING: 3326 if (message.arg1 == MULTICAST_V6) { 3327 mWifiNative.startFilteringMulticastV6Packets(); 3328 } else if (message.arg1 == MULTICAST_V4) { 3329 mWifiNative.startFilteringMulticastV4Packets(); 3330 } else { 3331 loge("Illegal arugments to CMD_START_PACKET_FILTERING"); 3332 } 3333 break; 3334 case CMD_STOP_PACKET_FILTERING: 3335 if (message.arg1 == MULTICAST_V6) { 3336 mWifiNative.stopFilteringMulticastV6Packets(); 3337 } else if (message.arg1 == MULTICAST_V4) { 3338 mWifiNative.stopFilteringMulticastV4Packets(); 3339 } else { 3340 loge("Illegal arugments to CMD_STOP_PACKET_FILTERING"); 3341 } 3342 break; 3343 case CMD_SET_SUSPEND_OPT_ENABLED: 3344 if (message.arg1 == 1) { 3345 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true); 3346 mSuspendWakeLock.release(); 3347 } else { 3348 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false); 3349 } 3350 break; 3351 case CMD_SET_HIGH_PERF_MODE: 3352 if (message.arg1 == 1) { 3353 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false); 3354 } else { 3355 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true); 3356 } 3357 break; 3358 case CMD_ENABLE_TDLS: 3359 if (message.obj != null) { 3360 String remoteAddress = (String) message.obj; 3361 boolean enable = (message.arg1 == 1); 3362 mWifiNative.startTdls(remoteAddress, enable); 3363 } 3364 break; 3365 default: 3366 return NOT_HANDLED; 3367 } 3368 return HANDLED; 3369 } 3370 @Override 3371 public void exit() { 3372 mIsRunning = false; 3373 updateBatteryWorkSource(null); 3374 mScanResults = new ArrayList<ScanResult>(); 3375 3376 stopBatchedScan(); 3377 3378 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 3379 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3380 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 3381 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3382 noteScanEnd(); // wrap up any pending request. 3383 mBufferedScanMsg.clear(); 3384 3385 mLastSetCountryCode = null; 3386 } 3387 } 3388 3389 class WaitForP2pDisableState extends State { 3390 private State mTransitionToState; 3391 @Override 3392 public void enter() { 3393 switch (getCurrentMessage().what) { 3394 case WifiMonitor.SUP_DISCONNECTION_EVENT: 3395 mTransitionToState = mInitialState; 3396 break; 3397 case CMD_DELAYED_STOP_DRIVER: 3398 mTransitionToState = mDriverStoppingState; 3399 break; 3400 case CMD_STOP_SUPPLICANT: 3401 mTransitionToState = mSupplicantStoppingState; 3402 break; 3403 default: 3404 mTransitionToState = mDriverStoppingState; 3405 break; 3406 } 3407 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ); 3408 } 3409 @Override 3410 public boolean processMessage(Message message) { 3411 switch(message.what) { 3412 case WifiStateMachine.CMD_DISABLE_P2P_RSP: 3413 transitionTo(mTransitionToState); 3414 break; 3415 /* Defer wifi start/shut and driver commands */ 3416 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3417 case CMD_START_SUPPLICANT: 3418 case CMD_STOP_SUPPLICANT: 3419 case CMD_START_AP: 3420 case CMD_STOP_AP: 3421 case CMD_START_DRIVER: 3422 case CMD_STOP_DRIVER: 3423 case CMD_SET_OPERATIONAL_MODE: 3424 case CMD_SET_COUNTRY_CODE: 3425 case CMD_SET_FREQUENCY_BAND: 3426 case CMD_START_PACKET_FILTERING: 3427 case CMD_STOP_PACKET_FILTERING: 3428 case CMD_START_SCAN: 3429 case CMD_DISCONNECT: 3430 case CMD_REASSOCIATE: 3431 case CMD_RECONNECT: 3432 deferMessage(message); 3433 break; 3434 default: 3435 return NOT_HANDLED; 3436 } 3437 return HANDLED; 3438 } 3439 } 3440 3441 class DriverStoppingState extends State { 3442 @Override 3443 public boolean processMessage(Message message) { 3444 switch(message.what) { 3445 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3446 SupplicantState state = handleSupplicantStateChange(message); 3447 if (state == SupplicantState.INTERFACE_DISABLED) { 3448 transitionTo(mDriverStoppedState); 3449 } 3450 break; 3451 /* Queue driver commands */ 3452 case CMD_START_DRIVER: 3453 case CMD_STOP_DRIVER: 3454 case CMD_SET_COUNTRY_CODE: 3455 case CMD_SET_FREQUENCY_BAND: 3456 case CMD_START_PACKET_FILTERING: 3457 case CMD_STOP_PACKET_FILTERING: 3458 case CMD_START_SCAN: 3459 case CMD_DISCONNECT: 3460 case CMD_REASSOCIATE: 3461 case CMD_RECONNECT: 3462 deferMessage(message); 3463 break; 3464 default: 3465 return NOT_HANDLED; 3466 } 3467 return HANDLED; 3468 } 3469 } 3470 3471 class DriverStoppedState extends State { 3472 @Override 3473 public boolean processMessage(Message message) { 3474 switch (message.what) { 3475 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3476 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 3477 SupplicantState state = stateChangeResult.state; 3478 // A WEXT bug means that we can be back to driver started state 3479 // unexpectedly 3480 if (SupplicantState.isDriverActive(state)) { 3481 transitionTo(mDriverStartedState); 3482 } 3483 break; 3484 case CMD_START_DRIVER: 3485 mWakeLock.acquire(); 3486 mWifiNative.startDriver(); 3487 mWakeLock.release(); 3488 transitionTo(mDriverStartingState); 3489 break; 3490 default: 3491 return NOT_HANDLED; 3492 } 3493 return HANDLED; 3494 } 3495 } 3496 3497 class ScanModeState extends State { 3498 private int mLastOperationMode; 3499 @Override 3500 public void enter() { 3501 mLastOperationMode = mOperationalMode; 3502 } 3503 @Override 3504 public boolean processMessage(Message message) { 3505 switch(message.what) { 3506 case CMD_SET_OPERATIONAL_MODE: 3507 if (message.arg1 == CONNECT_MODE) { 3508 3509 if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 3510 setWifiState(WIFI_STATE_ENABLED); 3511 // Load and re-enable networks when going back to enabled state 3512 // This is essential for networks to show up after restore 3513 mWifiConfigStore.loadAndEnableAllNetworks(); 3514 mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P); 3515 } else { 3516 mWifiConfigStore.enableAllNetworks(); 3517 } 3518 3519 mWifiNative.reconnect(); 3520 3521 mOperationalMode = CONNECT_MODE; 3522 transitionTo(mDisconnectedState); 3523 } else { 3524 // Nothing to do 3525 return HANDLED; 3526 } 3527 break; 3528 // Handle scan. All the connection related commands are 3529 // handled only in ConnectModeState 3530 case CMD_START_SCAN: 3531 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 3532 break; 3533 default: 3534 return NOT_HANDLED; 3535 } 3536 return HANDLED; 3537 } 3538 } 3539 3540 class ConnectModeState extends State { 3541 @Override 3542 public boolean processMessage(Message message) { 3543 WifiConfiguration config; 3544 boolean ok; 3545 switch(message.what) { 3546 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 3547 mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT); 3548 break; 3549 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 3550 mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT); 3551 break; 3552 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3553 SupplicantState state = handleSupplicantStateChange(message); 3554 // A driver/firmware hang can now put the interface in a down state. 3555 // We detect the interface going down and recover from it 3556 if (!SupplicantState.isDriverActive(state)) { 3557 if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 3558 handleNetworkDisconnect(); 3559 } 3560 log("Detected an interface down, restart driver"); 3561 transitionTo(mDriverStoppedState); 3562 sendMessage(CMD_START_DRIVER); 3563 break; 3564 } 3565 3566 // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT 3567 // when authentication times out after a successful connection, 3568 // we can figure this from the supplicant state. If supplicant 3569 // state is DISCONNECTED, but the mNetworkInfo says we are not 3570 // disconnected, we need to handle a disconnection 3571 if (state == SupplicantState.DISCONNECTED && 3572 mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 3573 if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect"); 3574 handleNetworkDisconnect(); 3575 transitionTo(mDisconnectedState); 3576 } 3577 break; 3578 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 3579 if (message.arg1 == 1) { 3580 mWifiNative.disconnect(); 3581 mTemporarilyDisconnectWifi = true; 3582 } else { 3583 mWifiNative.reconnect(); 3584 mTemporarilyDisconnectWifi = false; 3585 } 3586 break; 3587 case CMD_ADD_OR_UPDATE_NETWORK: 3588 config = (WifiConfiguration) message.obj; 3589 replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, 3590 mWifiConfigStore.addOrUpdateNetwork(config)); 3591 break; 3592 case CMD_REMOVE_NETWORK: 3593 ok = mWifiConfigStore.removeNetwork(message.arg1); 3594 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 3595 break; 3596 case CMD_ENABLE_NETWORK: 3597 ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); 3598 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 3599 break; 3600 case CMD_ENABLE_ALL_NETWORKS: 3601 long time = android.os.SystemClock.elapsedRealtime(); 3602 if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { 3603 mWifiConfigStore.enableAllNetworks(); 3604 mLastEnableAllNetworksTime = time; 3605 } 3606 break; 3607 case WifiManager.DISABLE_NETWORK: 3608 if (mWifiConfigStore.disableNetwork(message.arg1, 3609 WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) { 3610 replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); 3611 } else { 3612 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 3613 WifiManager.ERROR); 3614 } 3615 break; 3616 case CMD_BLACKLIST_NETWORK: 3617 mWifiNative.addToBlacklist((String)message.obj); 3618 break; 3619 case CMD_CLEAR_BLACKLIST: 3620 mWifiNative.clearBlacklist(); 3621 break; 3622 case CMD_SAVE_CONFIG: 3623 ok = mWifiConfigStore.saveConfig(); 3624 replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); 3625 3626 // Inform the backup manager about a data change 3627 IBackupManager ibm = IBackupManager.Stub.asInterface( 3628 ServiceManager.getService(Context.BACKUP_SERVICE)); 3629 if (ibm != null) { 3630 try { 3631 ibm.dataChanged("com.android.providers.settings"); 3632 } catch (Exception e) { 3633 // Try again later 3634 } 3635 } 3636 break; 3637 case CMD_GET_CONFIGURED_NETWORKS: 3638 replyToMessage(message, message.what, 3639 mWifiConfigStore.getConfiguredNetworks()); 3640 break; 3641 /* Do a redundant disconnect without transition */ 3642 case CMD_DISCONNECT: 3643 mWifiNative.disconnect(); 3644 break; 3645 case CMD_RECONNECT: 3646 mWifiNative.reconnect(); 3647 break; 3648 case CMD_REASSOCIATE: 3649 mWifiNative.reassociate(); 3650 break; 3651 case CMD_RELOAD_TLS_AND_RECONNECT: 3652 if (mWifiConfigStore.needsUnlockedKeyStore()) { 3653 logd("Reconnecting to give a chance to un-connected TLS networks"); 3654 mWifiNative.disconnect(); 3655 mWifiNative.reconnect(); 3656 } 3657 break; 3658 case WifiManager.CONNECT_NETWORK: 3659 /* The connect message can contain a network id passed as arg1 on message or 3660 * or a config passed as obj on message. 3661 * For a new network, a config is passed to create and connect. 3662 * For an existing network, a network id is passed 3663 */ 3664 int netId = message.arg1; 3665 config = (WifiConfiguration) message.obj; 3666 3667 /* Save the network config */ 3668 if (config != null) { 3669 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 3670 netId = result.getNetworkId(); 3671 } 3672 3673 if (mWifiConfigStore.selectNetwork(netId) && 3674 mWifiNative.reconnect()) { 3675 /* The state tracker handles enabling networks upon completion/failure */ 3676 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 3677 replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 3678 /* Expect a disconnection from the old connection */ 3679 transitionTo(mDisconnectingState); 3680 } else { 3681 loge("Failed to connect config: " + config + " netId: " + netId); 3682 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 3683 WifiManager.ERROR); 3684 break; 3685 } 3686 break; 3687 case WifiManager.SAVE_NETWORK: 3688 config = (WifiConfiguration) message.obj; 3689 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 3690 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 3691 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 3692 } else { 3693 loge("Failed to save network"); 3694 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 3695 WifiManager.ERROR); 3696 } 3697 break; 3698 case WifiManager.FORGET_NETWORK: 3699 if (mWifiConfigStore.forgetNetwork(message.arg1)) { 3700 replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); 3701 } else { 3702 loge("Failed to forget network"); 3703 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 3704 WifiManager.ERROR); 3705 } 3706 break; 3707 case WifiManager.START_WPS: 3708 WpsInfo wpsInfo = (WpsInfo) message.obj; 3709 WpsResult wpsResult; 3710 switch (wpsInfo.setup) { 3711 case WpsInfo.PBC: 3712 wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo); 3713 break; 3714 case WpsInfo.KEYPAD: 3715 wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); 3716 break; 3717 case WpsInfo.DISPLAY: 3718 wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); 3719 break; 3720 default: 3721 wpsResult = new WpsResult(Status.FAILURE); 3722 loge("Invalid setup for WPS"); 3723 break; 3724 } 3725 if (wpsResult.status == Status.SUCCESS) { 3726 replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult); 3727 transitionTo(mWpsRunningState); 3728 } else { 3729 loge("Failed to start WPS with config " + wpsInfo.toString()); 3730 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR); 3731 } 3732 break; 3733 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3734 if (DBG) log("Network connection established"); 3735 mLastNetworkId = message.arg1; 3736 mLastBssid = (String) message.obj; 3737 3738 mWifiInfo.setBSSID(mLastBssid); 3739 mWifiInfo.setNetworkId(mLastNetworkId); 3740 /* send event to CM & network change broadcast */ 3741 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 3742 sendNetworkStateChangeBroadcast(mLastBssid); 3743 transitionTo(mObtainingIpState); 3744 break; 3745 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 3746 if (DBG) log("Network connection lost"); 3747 handleNetworkDisconnect(); 3748 transitionTo(mDisconnectedState); 3749 break; 3750 default: 3751 return NOT_HANDLED; 3752 } 3753 return HANDLED; 3754 } 3755 } 3756 3757 class L2ConnectedState extends State { 3758 @Override 3759 public void enter() { 3760 mRssiPollToken++; 3761 if (mEnableRssiPolling) { 3762 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0); 3763 } 3764 } 3765 3766 @Override 3767 public void exit() { 3768 handleNetworkDisconnect(); 3769 } 3770 3771 @Override 3772 public boolean processMessage(Message message) { 3773 switch (message.what) { 3774 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 3775 handlePreDhcpSetup(); 3776 break; 3777 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 3778 handlePostDhcpSetup(); 3779 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 3780 if (DBG) log("DHCP successful"); 3781 handleSuccessfulIpConfiguration((DhcpResults) message.obj); 3782 transitionTo(mVerifyingLinkState); 3783 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { 3784 if (DBG) log("DHCP failed"); 3785 handleFailedIpConfiguration(); 3786 transitionTo(mDisconnectingState); 3787 } 3788 break; 3789 case CMD_DISCONNECT: 3790 mWifiNative.disconnect(); 3791 transitionTo(mDisconnectingState); 3792 break; 3793 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 3794 if (message.arg1 == 1) { 3795 mWifiNative.disconnect(); 3796 mTemporarilyDisconnectWifi = true; 3797 transitionTo(mDisconnectingState); 3798 } 3799 break; 3800 case CMD_SET_OPERATIONAL_MODE: 3801 if (message.arg1 != CONNECT_MODE) { 3802 sendMessage(CMD_DISCONNECT); 3803 deferMessage(message); 3804 } 3805 break; 3806 case CMD_START_SCAN: 3807 /* Do not attempt to connect when we are already connected */ 3808 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 3809 break; 3810 /* Ignore connection to same network */ 3811 case WifiManager.CONNECT_NETWORK: 3812 int netId = message.arg1; 3813 if (mWifiInfo.getNetworkId() == netId) { 3814 break; 3815 } 3816 return NOT_HANDLED; 3817 case WifiManager.SAVE_NETWORK: 3818 WifiConfiguration config = (WifiConfiguration) message.obj; 3819 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 3820 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 3821 if (result.hasIpChanged()) { 3822 log("Reconfiguring IP on connection"); 3823 transitionTo(mObtainingIpState); 3824 } 3825 if (result.hasProxyChanged()) { 3826 log("Reconfiguring proxy on connection"); 3827 updateLinkProperties(); 3828 } 3829 } 3830 3831 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 3832 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 3833 } else { 3834 loge("Failed to save network"); 3835 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 3836 WifiManager.ERROR); 3837 } 3838 break; 3839 /* Ignore */ 3840 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3841 break; 3842 case CMD_RSSI_POLL: 3843 if (message.arg1 == mRssiPollToken) { 3844 // Get Info and continue polling 3845 fetchRssiLinkSpeedAndFrequencyNative(); 3846 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 3847 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 3848 } else { 3849 // Polling has completed 3850 } 3851 break; 3852 case CMD_ENABLE_RSSI_POLL: 3853 mEnableRssiPolling = (message.arg1 == 1); 3854 mRssiPollToken++; 3855 if (mEnableRssiPolling) { 3856 // first poll 3857 fetchRssiLinkSpeedAndFrequencyNative(); 3858 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 3859 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 3860 } 3861 break; 3862 case WifiManager.RSSI_PKTCNT_FETCH: 3863 RssiPacketCountInfo info = new RssiPacketCountInfo(); 3864 fetchRssiLinkSpeedAndFrequencyNative(); 3865 info.rssi = mWifiInfo.getRssi(); 3866 fetchPktcntNative(info); 3867 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info); 3868 break; 3869 default: 3870 return NOT_HANDLED; 3871 } 3872 3873 return HANDLED; 3874 } 3875 } 3876 3877 class ObtainingIpState extends State { 3878 @Override 3879 public void enter() { 3880 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 3881 // TODO: If we're switching between static IP configuration and DHCP, remove the 3882 // static configuration first. 3883 startDhcp(); 3884 } else { 3885 // stop any running dhcp before assigning static IP 3886 stopDhcp(); 3887 DhcpResults dhcpResults = new DhcpResults( 3888 mWifiConfigStore.getLinkProperties(mLastNetworkId)); 3889 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 3890 Iterator<LinkAddress> addrs = 3891 dhcpResults.linkProperties.getLinkAddresses().iterator(); 3892 if (!addrs.hasNext()) { 3893 loge("Static IP lacks address"); 3894 sendMessage(CMD_STATIC_IP_FAILURE); 3895 } else { 3896 ifcg.setLinkAddress(addrs.next()); 3897 ifcg.setInterfaceUp(); 3898 try { 3899 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 3900 if (DBG) log("Static IP configuration succeeded"); 3901 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults); 3902 } catch (RemoteException re) { 3903 loge("Static IP configuration failed: " + re); 3904 sendMessage(CMD_STATIC_IP_FAILURE); 3905 } catch (IllegalStateException e) { 3906 loge("Static IP configuration failed: " + e); 3907 sendMessage(CMD_STATIC_IP_FAILURE); 3908 } 3909 } 3910 } 3911 } 3912 @Override 3913 public boolean processMessage(Message message) { 3914 if (DBG) log(getName() + message.toString() + "\n"); 3915 switch(message.what) { 3916 case CMD_STATIC_IP_SUCCESS: 3917 handleSuccessfulIpConfiguration((DhcpResults) message.obj); 3918 transitionTo(mVerifyingLinkState); 3919 break; 3920 case CMD_STATIC_IP_FAILURE: 3921 handleFailedIpConfiguration(); 3922 transitionTo(mDisconnectingState); 3923 break; 3924 case WifiManager.SAVE_NETWORK: 3925 deferMessage(message); 3926 break; 3927 /* Defer any power mode changes since we must keep active power mode at DHCP */ 3928 case CMD_SET_HIGH_PERF_MODE: 3929 deferMessage(message); 3930 break; 3931 /* Defer scan request since we should not switch to other channels at DHCP */ 3932 case CMD_START_SCAN: 3933 deferMessage(message); 3934 break; 3935 default: 3936 return NOT_HANDLED; 3937 } 3938 return HANDLED; 3939 } 3940 } 3941 3942 class VerifyingLinkState extends State { 3943 @Override 3944 public void enter() { 3945 log(getName() + " enter"); 3946 setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); 3947 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); 3948 sendNetworkStateChangeBroadcast(mLastBssid); 3949 } 3950 @Override 3951 public boolean processMessage(Message message) { 3952 switch (message.what) { 3953 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 3954 //stay here 3955 log(getName() + " POOR_LINK_DETECTED: no transition"); 3956 break; 3957 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 3958 log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); 3959 // Send out a broadcast with the CAPTIVE_PORTAL_CHECK to preserve 3960 // existing behaviour. The captive portal check really happens after we 3961 // transition into DetailedState.CONNECTED. 3962 setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); 3963 mWifiConfigStore.updateStatus(mLastNetworkId, 3964 DetailedState.CAPTIVE_PORTAL_CHECK); 3965 sendNetworkStateChangeBroadcast(mLastBssid); 3966 3967 // NOTE: This might look like an odd place to enable IPV6 but this is in 3968 // response to transitioning into GOOD_LINK_DETECTED. Similarly, we disable 3969 // ipv6 when we transition into POOR_LINK_DETECTED in mConnectedState. 3970 try { 3971 mNwService.enableIpv6(mInterfaceName); 3972 } catch (RemoteException re) { 3973 loge("Failed to enable IPv6: " + re); 3974 } catch (IllegalStateException e) { 3975 loge("Failed to enable IPv6: " + e); 3976 } 3977 3978 log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED"); 3979 setNetworkDetailedState(DetailedState.CONNECTED); 3980 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); 3981 sendNetworkStateChangeBroadcast(mLastBssid); 3982 transitionTo(mConnectedState); 3983 3984 break; 3985 default: 3986 if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); 3987 return NOT_HANDLED; 3988 } 3989 return HANDLED; 3990 } 3991 } 3992 3993 class ConnectedState extends State { 3994 @Override 3995 public boolean processMessage(Message message) { 3996 switch (message.what) { 3997 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 3998 if (DBG) log("Watchdog reports poor link"); 3999 try { 4000 mNwService.disableIpv6(mInterfaceName); 4001 } catch (RemoteException re) { 4002 loge("Failed to disable IPv6: " + re); 4003 } catch (IllegalStateException e) { 4004 loge("Failed to disable IPv6: " + e); 4005 } 4006 /* Report a disconnect */ 4007 setNetworkDetailedState(DetailedState.DISCONNECTED); 4008 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 4009 sendNetworkStateChangeBroadcast(mLastBssid); 4010 4011 transitionTo(mVerifyingLinkState); 4012 break; 4013 default: 4014 return NOT_HANDLED; 4015 } 4016 return HANDLED; 4017 } 4018 4019 @Override 4020 public void exit() { 4021 /* Request a CS wakelock during transition to mobile */ 4022 checkAndSetConnectivityInstance(); 4023 mCm.requestNetworkTransitionWakelock(getName()); 4024 } 4025 } 4026 4027 class DisconnectingState extends State { 4028 @Override 4029 public boolean processMessage(Message message) { 4030 switch (message.what) { 4031 case CMD_SET_OPERATIONAL_MODE: 4032 if (message.arg1 != CONNECT_MODE) { 4033 deferMessage(message); 4034 } 4035 break; 4036 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4037 /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT 4038 * we have missed the network disconnection, transition to mDisconnectedState 4039 * and handle the rest of the events there 4040 */ 4041 deferMessage(message); 4042 handleNetworkDisconnect(); 4043 transitionTo(mDisconnectedState); 4044 break; 4045 default: 4046 return NOT_HANDLED; 4047 } 4048 return HANDLED; 4049 } 4050 } 4051 4052 class DisconnectedState extends State { 4053 private boolean mAlarmEnabled = false; 4054 /* This is set from the overlay config file or from a secure setting. 4055 * A value of 0 disables scanning in the framework. 4056 */ 4057 private long mFrameworkScanIntervalMs; 4058 4059 private void setScanAlarm(boolean enabled) { 4060 if (enabled == mAlarmEnabled) return; 4061 if (enabled) { 4062 if (mFrameworkScanIntervalMs > 0) { 4063 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 4064 System.currentTimeMillis() + mFrameworkScanIntervalMs, 4065 mFrameworkScanIntervalMs, 4066 mScanIntent); 4067 mAlarmEnabled = true; 4068 } 4069 } else { 4070 mAlarmManager.cancel(mScanIntent); 4071 mAlarmEnabled = false; 4072 } 4073 } 4074 4075 @Override 4076 public void enter() { 4077 // We dont scan frequently if this is a temporary disconnect 4078 // due to p2p 4079 if (mTemporarilyDisconnectWifi) { 4080 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 4081 return; 4082 } 4083 4084 mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 4085 Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS, 4086 mDefaultFrameworkScanIntervalMs); 4087 /* 4088 * We initiate background scanning if it is enabled, otherwise we 4089 * initiate an infrequent scan that wakes up the device to ensure 4090 * a user connects to an access point on the move 4091 */ 4092 if (mEnableBackgroundScan) { 4093 /* If a regular scan result is pending, do not initiate background 4094 * scan until the scan results are returned. This is needed because 4095 * initiating a background scan will cancel the regular scan and 4096 * scan results will not be returned until background scanning is 4097 * cleared 4098 */ 4099 if (!mIsScanOngoing) { 4100 mWifiNative.enableBackgroundScan(true); 4101 } 4102 } else { 4103 setScanAlarm(true); 4104 } 4105 4106 /** 4107 * If we have no networks saved, the supplicant stops doing the periodic scan. 4108 * The scans are useful to notify the user of the presence of an open network. 4109 * Note that these are not wake up scans. 4110 */ 4111 if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) { 4112 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 4113 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 4114 } 4115 } 4116 @Override 4117 public boolean processMessage(Message message) { 4118 boolean ret = HANDLED; 4119 switch (message.what) { 4120 case CMD_NO_NETWORKS_PERIODIC_SCAN: 4121 if (mP2pConnected.get()) break; 4122 if (message.arg1 == mPeriodicScanToken && 4123 mWifiConfigStore.getConfiguredNetworks().size() == 0) { 4124 startScan(UNKNOWN_SCAN_SOURCE, null, null); 4125 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 4126 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 4127 } 4128 break; 4129 case WifiManager.FORGET_NETWORK: 4130 case CMD_REMOVE_NETWORK: 4131 // Set up a delayed message here. After the forget/remove is handled 4132 // the handled delayed message will determine if there is a need to 4133 // scan and continue 4134 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 4135 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 4136 ret = NOT_HANDLED; 4137 break; 4138 case CMD_SET_OPERATIONAL_MODE: 4139 if (message.arg1 != CONNECT_MODE) { 4140 mOperationalMode = message.arg1; 4141 4142 mWifiConfigStore.disableAllNetworks(); 4143 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 4144 mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); 4145 setWifiState(WIFI_STATE_DISABLED); 4146 } 4147 4148 transitionTo(mScanModeState); 4149 } 4150 break; 4151 case CMD_ENABLE_BACKGROUND_SCAN: 4152 mEnableBackgroundScan = (message.arg1 == 1); 4153 if (mEnableBackgroundScan) { 4154 mWifiNative.enableBackgroundScan(true); 4155 setScanAlarm(false); 4156 } else { 4157 mWifiNative.enableBackgroundScan(false); 4158 setScanAlarm(true); 4159 } 4160 break; 4161 /* Ignore network disconnect */ 4162 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 4163 break; 4164 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4165 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 4166 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 4167 /* ConnectModeState does the rest of the handling */ 4168 ret = NOT_HANDLED; 4169 break; 4170 case CMD_START_SCAN: 4171 /* Disable background scan temporarily during a regular scan */ 4172 if (mEnableBackgroundScan) { 4173 mWifiNative.enableBackgroundScan(false); 4174 } 4175 /* Handled in parent state */ 4176 ret = NOT_HANDLED; 4177 break; 4178 case WifiMonitor.SCAN_RESULTS_EVENT: 4179 /* Re-enable background scan when a pending scan result is received */ 4180 if (mEnableBackgroundScan && mIsScanOngoing) { 4181 mWifiNative.enableBackgroundScan(true); 4182 } 4183 /* Handled in parent state */ 4184 ret = NOT_HANDLED; 4185 break; 4186 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 4187 NetworkInfo info = (NetworkInfo) message.obj; 4188 mP2pConnected.set(info.isConnected()); 4189 if (mP2pConnected.get()) { 4190 int defaultInterval = mContext.getResources().getInteger( 4191 R.integer.config_wifi_scan_interval_p2p_connected); 4192 long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 4193 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 4194 defaultInterval); 4195 mWifiNative.setScanInterval((int) scanIntervalMs/1000); 4196 } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { 4197 if (DBG) log("Turn on scanning after p2p disconnected"); 4198 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 4199 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 4200 } 4201 case CMD_RECONNECT: 4202 case CMD_REASSOCIATE: 4203 if (mTemporarilyDisconnectWifi) { 4204 // Drop a third party reconnect/reassociate if STA is 4205 // temporarily disconnected for p2p 4206 break; 4207 } else { 4208 // ConnectModeState handles it 4209 ret = NOT_HANDLED; 4210 } 4211 break; 4212 default: 4213 ret = NOT_HANDLED; 4214 } 4215 return ret; 4216 } 4217 4218 @Override 4219 public void exit() { 4220 /* No need for a background scan upon exit from a disconnected state */ 4221 if (mEnableBackgroundScan) { 4222 mWifiNative.enableBackgroundScan(false); 4223 } 4224 setScanAlarm(false); 4225 } 4226 } 4227 4228 class WpsRunningState extends State { 4229 //Tracks the source to provide a reply 4230 private Message mSourceMessage; 4231 @Override 4232 public void enter() { 4233 mSourceMessage = Message.obtain(getCurrentMessage()); 4234 } 4235 @Override 4236 public boolean processMessage(Message message) { 4237 switch (message.what) { 4238 case WifiMonitor.WPS_SUCCESS_EVENT: 4239 // Ignore intermediate success, wait for full connection 4240 break; 4241 case WifiMonitor.NETWORK_CONNECTION_EVENT: 4242 replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED); 4243 mSourceMessage.recycle(); 4244 mSourceMessage = null; 4245 deferMessage(message); 4246 transitionTo(mDisconnectedState); 4247 break; 4248 case WifiMonitor.WPS_OVERLAP_EVENT: 4249 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 4250 WifiManager.WPS_OVERLAP_ERROR); 4251 mSourceMessage.recycle(); 4252 mSourceMessage = null; 4253 transitionTo(mDisconnectedState); 4254 break; 4255 case WifiMonitor.WPS_FAIL_EVENT: 4256 //arg1 has the reason for the failure 4257 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1); 4258 mSourceMessage.recycle(); 4259 mSourceMessage = null; 4260 transitionTo(mDisconnectedState); 4261 break; 4262 case WifiMonitor.WPS_TIMEOUT_EVENT: 4263 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 4264 WifiManager.WPS_TIMED_OUT); 4265 mSourceMessage.recycle(); 4266 mSourceMessage = null; 4267 transitionTo(mDisconnectedState); 4268 break; 4269 case WifiManager.START_WPS: 4270 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS); 4271 break; 4272 case WifiManager.CANCEL_WPS: 4273 if (mWifiNative.cancelWps()) { 4274 replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED); 4275 } else { 4276 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR); 4277 } 4278 transitionTo(mDisconnectedState); 4279 break; 4280 /* Defer all commands that can cause connections to a different network 4281 * or put the state machine out of connect mode 4282 */ 4283 case CMD_STOP_DRIVER: 4284 case CMD_SET_OPERATIONAL_MODE: 4285 case WifiManager.CONNECT_NETWORK: 4286 case CMD_ENABLE_NETWORK: 4287 case CMD_RECONNECT: 4288 case CMD_REASSOCIATE: 4289 deferMessage(message); 4290 break; 4291 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 4292 if (DBG) log("Network connection lost"); 4293 handleNetworkDisconnect(); 4294 break; 4295 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 4296 if (DBG) log("Ignore Assoc reject event during WPS Connection"); 4297 break; 4298 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 4299 // Disregard auth failure events during WPS connection. The 4300 // EAP sequence is retried several times, and there might be 4301 // failures (especially for wps pin). We will get a WPS_XXX 4302 // event at the end of the sequence anyway. 4303 if (DBG) log("Ignore auth failure during WPS connection"); 4304 break; 4305 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4306 //Throw away supplicant state changes when WPS is running. 4307 //We will start getting supplicant state changes once we get 4308 //a WPS success or failure 4309 break; 4310 default: 4311 return NOT_HANDLED; 4312 } 4313 return HANDLED; 4314 } 4315 4316 @Override 4317 public void exit() { 4318 mWifiConfigStore.enableAllNetworks(); 4319 mWifiConfigStore.loadConfiguredNetworks(); 4320 } 4321 } 4322 4323 class SoftApStartingState extends State { 4324 @Override 4325 public void enter() { 4326 final Message message = getCurrentMessage(); 4327 if (message.what == CMD_START_AP) { 4328 final WifiConfiguration config = (WifiConfiguration) message.obj; 4329 4330 if (config == null) { 4331 mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); 4332 } else { 4333 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 4334 startSoftApWithConfig(config); 4335 } 4336 } else { 4337 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); 4338 } 4339 } 4340 @Override 4341 public boolean processMessage(Message message) { 4342 switch(message.what) { 4343 case CMD_START_SUPPLICANT: 4344 case CMD_STOP_SUPPLICANT: 4345 case CMD_START_AP: 4346 case CMD_STOP_AP: 4347 case CMD_START_DRIVER: 4348 case CMD_STOP_DRIVER: 4349 case CMD_SET_OPERATIONAL_MODE: 4350 case CMD_SET_COUNTRY_CODE: 4351 case CMD_SET_FREQUENCY_BAND: 4352 case CMD_START_PACKET_FILTERING: 4353 case CMD_STOP_PACKET_FILTERING: 4354 case CMD_TETHER_STATE_CHANGE: 4355 deferMessage(message); 4356 break; 4357 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: 4358 WifiConfiguration config = (WifiConfiguration) message.obj; 4359 if (config != null) { 4360 startSoftApWithConfig(config); 4361 } else { 4362 loge("Softap config is null!"); 4363 sendMessage(CMD_START_AP_FAILURE); 4364 } 4365 break; 4366 case CMD_START_AP_SUCCESS: 4367 setWifiApState(WIFI_AP_STATE_ENABLED); 4368 transitionTo(mSoftApStartedState); 4369 break; 4370 case CMD_START_AP_FAILURE: 4371 setWifiApState(WIFI_AP_STATE_FAILED); 4372 transitionTo(mInitialState); 4373 break; 4374 default: 4375 return NOT_HANDLED; 4376 } 4377 return HANDLED; 4378 } 4379 } 4380 4381 class SoftApStartedState extends State { 4382 @Override 4383 public boolean processMessage(Message message) { 4384 switch(message.what) { 4385 case CMD_STOP_AP: 4386 if (DBG) log("Stopping Soft AP"); 4387 /* We have not tethered at this point, so we just shutdown soft Ap */ 4388 try { 4389 mNwService.stopAccessPoint(mInterfaceName); 4390 } catch(Exception e) { 4391 loge("Exception in stopAccessPoint()"); 4392 } 4393 setWifiApState(WIFI_AP_STATE_DISABLED); 4394 transitionTo(mInitialState); 4395 break; 4396 case CMD_START_AP: 4397 // Ignore a start on a running access point 4398 break; 4399 /* Fail client mode operation when soft AP is enabled */ 4400 case CMD_START_SUPPLICANT: 4401 loge("Cannot start supplicant with a running soft AP"); 4402 setWifiState(WIFI_STATE_UNKNOWN); 4403 break; 4404 case CMD_TETHER_STATE_CHANGE: 4405 TetherStateChange stateChange = (TetherStateChange) message.obj; 4406 if (startTethering(stateChange.available)) { 4407 transitionTo(mTetheringState); 4408 } 4409 break; 4410 default: 4411 return NOT_HANDLED; 4412 } 4413 return HANDLED; 4414 } 4415 } 4416 4417 class TetheringState extends State { 4418 @Override 4419 public void enter() { 4420 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 4421 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 4422 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 4423 } 4424 @Override 4425 public boolean processMessage(Message message) { 4426 switch(message.what) { 4427 case CMD_TETHER_STATE_CHANGE: 4428 TetherStateChange stateChange = (TetherStateChange) message.obj; 4429 if (isWifiTethered(stateChange.active)) { 4430 transitionTo(mTetheredState); 4431 } 4432 return HANDLED; 4433 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 4434 if (message.arg1 == mTetherToken) { 4435 loge("Failed to get tether update, shutdown soft access point"); 4436 transitionTo(mSoftApStartedState); 4437 // Needs to be first thing handled 4438 sendMessageAtFrontOfQueue(CMD_STOP_AP); 4439 } 4440 break; 4441 case CMD_START_SUPPLICANT: 4442 case CMD_STOP_SUPPLICANT: 4443 case CMD_START_AP: 4444 case CMD_STOP_AP: 4445 case CMD_START_DRIVER: 4446 case CMD_STOP_DRIVER: 4447 case CMD_SET_OPERATIONAL_MODE: 4448 case CMD_SET_COUNTRY_CODE: 4449 case CMD_SET_FREQUENCY_BAND: 4450 case CMD_START_PACKET_FILTERING: 4451 case CMD_STOP_PACKET_FILTERING: 4452 deferMessage(message); 4453 break; 4454 default: 4455 return NOT_HANDLED; 4456 } 4457 return HANDLED; 4458 } 4459 } 4460 4461 class TetheredState extends State { 4462 @Override 4463 public boolean processMessage(Message message) { 4464 switch(message.what) { 4465 case CMD_TETHER_STATE_CHANGE: 4466 TetherStateChange stateChange = (TetherStateChange) message.obj; 4467 if (!isWifiTethered(stateChange.active)) { 4468 loge("Tethering reports wifi as untethered!, shut down soft Ap"); 4469 setHostApRunning(null, false); 4470 setHostApRunning(null, true); 4471 } 4472 return HANDLED; 4473 case CMD_STOP_AP: 4474 if (DBG) log("Untethering before stopping AP"); 4475 setWifiApState(WIFI_AP_STATE_DISABLING); 4476 stopTethering(); 4477 transitionTo(mUntetheringState); 4478 // More work to do after untethering 4479 deferMessage(message); 4480 break; 4481 default: 4482 return NOT_HANDLED; 4483 } 4484 return HANDLED; 4485 } 4486 } 4487 4488 class UntetheringState extends State { 4489 @Override 4490 public void enter() { 4491 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 4492 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 4493 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 4494 4495 } 4496 @Override 4497 public boolean processMessage(Message message) { 4498 switch(message.what) { 4499 case CMD_TETHER_STATE_CHANGE: 4500 TetherStateChange stateChange = (TetherStateChange) message.obj; 4501 4502 /* Wait till wifi is untethered */ 4503 if (isWifiTethered(stateChange.active)) break; 4504 4505 transitionTo(mSoftApStartedState); 4506 break; 4507 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 4508 if (message.arg1 == mTetherToken) { 4509 loge("Failed to get tether update, force stop access point"); 4510 transitionTo(mSoftApStartedState); 4511 } 4512 break; 4513 case CMD_START_SUPPLICANT: 4514 case CMD_STOP_SUPPLICANT: 4515 case CMD_START_AP: 4516 case CMD_STOP_AP: 4517 case CMD_START_DRIVER: 4518 case CMD_STOP_DRIVER: 4519 case CMD_SET_OPERATIONAL_MODE: 4520 case CMD_SET_COUNTRY_CODE: 4521 case CMD_SET_FREQUENCY_BAND: 4522 case CMD_START_PACKET_FILTERING: 4523 case CMD_STOP_PACKET_FILTERING: 4524 deferMessage(message); 4525 break; 4526 default: 4527 return NOT_HANDLED; 4528 } 4529 return HANDLED; 4530 } 4531 } 4532 4533 //State machine initiated requests can have replyTo set to null indicating 4534 //there are no recepients, we ignore those reply actions 4535 private void replyToMessage(Message msg, int what) { 4536 if (msg.replyTo == null) return; 4537 Message dstMsg = obtainMessageWithArg2(msg); 4538 dstMsg.what = what; 4539 mReplyChannel.replyToMessage(msg, dstMsg); 4540 } 4541 4542 private void replyToMessage(Message msg, int what, int arg1) { 4543 if (msg.replyTo == null) return; 4544 Message dstMsg = obtainMessageWithArg2(msg); 4545 dstMsg.what = what; 4546 dstMsg.arg1 = arg1; 4547 mReplyChannel.replyToMessage(msg, dstMsg); 4548 } 4549 4550 private void replyToMessage(Message msg, int what, Object obj) { 4551 if (msg.replyTo == null) return; 4552 Message dstMsg = obtainMessageWithArg2(msg); 4553 dstMsg.what = what; 4554 dstMsg.obj = obj; 4555 mReplyChannel.replyToMessage(msg, dstMsg); 4556 } 4557 4558 /** 4559 * arg2 on the source message has a unique id that needs to be retained in replies 4560 * to match the request 4561 4562 * see WifiManager for details 4563 */ 4564 private Message obtainMessageWithArg2(Message srcMsg) { 4565 Message msg = Message.obtain(); 4566 msg.arg2 = srcMsg.arg2; 4567 return msg; 4568 } 4569} 4570