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