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