WifiStateMachine.java revision 3f7ef65ab71619040032aee96b5599849881d6fd
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 * Retrieves a WPS-NFC configuration token for the specified network 1462 * @return a hex string representation of the WPS-NFC configuration token 1463 */ 1464 public String syncGetWpsNfcConfigurationToken(int netId) { 1465 return mWifiNative.getNfcWpsConfigurationToken(netId); 1466 } 1467 1468 /** 1469 * Blacklist a BSSID. This will avoid the AP if there are 1470 * alternate APs to connect 1471 * 1472 * @param bssid BSSID of the network 1473 */ 1474 public void addToBlacklist(String bssid) { 1475 sendMessage(CMD_BLACKLIST_NETWORK, bssid); 1476 } 1477 1478 /** 1479 * Clear the blacklist list 1480 * 1481 */ 1482 public void clearBlacklist() { 1483 sendMessage(CMD_CLEAR_BLACKLIST); 1484 } 1485 1486 public void enableRssiPolling(boolean enabled) { 1487 sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0); 1488 } 1489 1490 public void enableBackgroundScanCommand(boolean enabled) { 1491 sendMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0); 1492 } 1493 1494 public void enableAllNetworks() { 1495 sendMessage(CMD_ENABLE_ALL_NETWORKS); 1496 } 1497 1498 /** 1499 * Start filtering Multicast v4 packets 1500 */ 1501 public void startFilteringMulticastV4Packets() { 1502 mFilteringMulticastV4Packets.set(true); 1503 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0); 1504 } 1505 1506 /** 1507 * Stop filtering Multicast v4 packets 1508 */ 1509 public void stopFilteringMulticastV4Packets() { 1510 mFilteringMulticastV4Packets.set(false); 1511 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0); 1512 } 1513 1514 /** 1515 * Start filtering Multicast v4 packets 1516 */ 1517 public void startFilteringMulticastV6Packets() { 1518 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0); 1519 } 1520 1521 /** 1522 * Stop filtering Multicast v4 packets 1523 */ 1524 public void stopFilteringMulticastV6Packets() { 1525 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0); 1526 } 1527 1528 /** 1529 * Set high performance mode of operation. 1530 * Enabling would set active power mode and disable suspend optimizations; 1531 * disabling would set auto power mode and enable suspend optimizations 1532 * @param enable true if enable, false otherwise 1533 */ 1534 public void setHighPerfModeEnabled(boolean enable) { 1535 sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0); 1536 } 1537 1538 /** 1539 * Set the country code 1540 * @param countryCode following ISO 3166 format 1541 * @param persist {@code true} if the setting should be remembered. 1542 */ 1543 public void setCountryCode(String countryCode, boolean persist) { 1544 if (persist) { 1545 mPersistedCountryCode = countryCode; 1546 Settings.Global.putString(mContext.getContentResolver(), 1547 Settings.Global.WIFI_COUNTRY_CODE, 1548 countryCode); 1549 } 1550 sendMessage(CMD_SET_COUNTRY_CODE, countryCode); 1551 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.SET_COUNTRY_CODE, countryCode); 1552 } 1553 1554 /** 1555 * Set the operational frequency band 1556 * @param band 1557 * @param persist {@code true} if the setting should be remembered. 1558 */ 1559 public void setFrequencyBand(int band, boolean persist) { 1560 if (persist) { 1561 Settings.Global.putInt(mContext.getContentResolver(), 1562 Settings.Global.WIFI_FREQUENCY_BAND, 1563 band); 1564 } 1565 sendMessage(CMD_SET_FREQUENCY_BAND, band, 0); 1566 } 1567 1568 /** 1569 * Enable TDLS for a specific MAC address 1570 */ 1571 public void enableTdls(String remoteMacAddress, boolean enable) { 1572 int enabler = enable ? 1 : 0; 1573 sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress); 1574 } 1575 1576 /** 1577 * Returns the operational frequency band 1578 */ 1579 public int getFrequencyBand() { 1580 return mFrequencyBand.get(); 1581 } 1582 1583 /** 1584 * Returns the wifi configuration file 1585 */ 1586 public String getConfigFile() { 1587 return mWifiConfigStore.getConfigFile(); 1588 } 1589 1590 /** 1591 * Send a message indicating bluetooth adapter connection state changed 1592 */ 1593 public void sendBluetoothAdapterStateChange(int state) { 1594 sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0); 1595 } 1596 1597 /** 1598 * Save configuration on supplicant 1599 * 1600 * @return {@code true} if the operation succeeds, {@code false} otherwise 1601 * 1602 * TODO: deprecate this 1603 */ 1604 public boolean syncSaveConfig(AsyncChannel channel) { 1605 Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG); 1606 boolean result = (resultMsg.arg1 != FAILURE); 1607 resultMsg.recycle(); 1608 return result; 1609 } 1610 1611 public void updateBatteryWorkSource(WorkSource newSource) { 1612 synchronized (mRunningWifiUids) { 1613 try { 1614 if (newSource != null) { 1615 mRunningWifiUids.set(newSource); 1616 } 1617 if (mIsRunning) { 1618 if (mReportedRunning) { 1619 // If the work source has changed since last time, need 1620 // to remove old work from battery stats. 1621 if (mLastRunningWifiUids.diff(mRunningWifiUids)) { 1622 mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids, 1623 mRunningWifiUids); 1624 mLastRunningWifiUids.set(mRunningWifiUids); 1625 } 1626 } else { 1627 // Now being started, report it. 1628 mBatteryStats.noteWifiRunning(mRunningWifiUids); 1629 mLastRunningWifiUids.set(mRunningWifiUids); 1630 mReportedRunning = true; 1631 } 1632 } else { 1633 if (mReportedRunning) { 1634 // Last reported we were running, time to stop. 1635 mBatteryStats.noteWifiStopped(mLastRunningWifiUids); 1636 mLastRunningWifiUids.clear(); 1637 mReportedRunning = false; 1638 } 1639 } 1640 mWakeLock.setWorkSource(newSource); 1641 } catch (RemoteException ignore) { 1642 } 1643 } 1644 } 1645 1646 @Override 1647 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1648 super.dump(fd, pw, args); 1649 mSupplicantStateTracker.dump(fd, pw, args); 1650 pw.println("mLinkProperties " + mLinkProperties); 1651 pw.println("mWifiInfo " + mWifiInfo); 1652 pw.println("mDhcpResults " + mDhcpResults); 1653 pw.println("mNetworkInfo " + mNetworkInfo); 1654 pw.println("mLastSignalLevel " + mLastSignalLevel); 1655 pw.println("mLastBssid " + mLastBssid); 1656 pw.println("mLastNetworkId " + mLastNetworkId); 1657 pw.println("mReconnectCount " + mReconnectCount); 1658 pw.println("mOperationalMode " + mOperationalMode); 1659 pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt); 1660 pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 1661 pw.println("Supplicant status " + mWifiNative.status()); 1662 pw.println("mEnableBackgroundScan " + mEnableBackgroundScan); 1663 pw.println(); 1664 mWifiConfigStore.dump(fd, pw, args); 1665 } 1666 1667 /********************************************************* 1668 * Internal private functions 1669 ********************************************************/ 1670 1671 private void handleScreenStateChanged(boolean screenOn) { 1672 if (DBG) log("handleScreenStateChanged: " + screenOn); 1673 enableRssiPolling(screenOn); 1674 if (mBackgroundScanSupported) { 1675 enableBackgroundScanCommand(screenOn == false); 1676 } 1677 1678 if (screenOn) enableAllNetworks(); 1679 if (mUserWantsSuspendOpt.get()) { 1680 if (screenOn) { 1681 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0); 1682 } else { 1683 //Allow 2s for suspend optimizations to be set 1684 mSuspendWakeLock.acquire(2000); 1685 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0); 1686 } 1687 } 1688 mScreenBroadcastReceived.set(true); 1689 } 1690 1691 private void checkAndSetConnectivityInstance() { 1692 if (mCm == null) { 1693 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 1694 } 1695 } 1696 1697 private boolean startTethering(ArrayList<String> available) { 1698 1699 boolean wifiAvailable = false; 1700 1701 checkAndSetConnectivityInstance(); 1702 1703 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 1704 1705 for (String intf : available) { 1706 for (String regex : wifiRegexs) { 1707 if (intf.matches(regex)) { 1708 1709 InterfaceConfiguration ifcg = null; 1710 try { 1711 ifcg = mNwService.getInterfaceConfig(intf); 1712 if (ifcg != null) { 1713 /* IP/netmask: 192.168.43.1/255.255.255.0 */ 1714 ifcg.setLinkAddress(new LinkAddress( 1715 NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); 1716 ifcg.setInterfaceUp(); 1717 1718 mNwService.setInterfaceConfig(intf, ifcg); 1719 } 1720 } catch (Exception e) { 1721 loge("Error configuring interface " + intf + ", :" + e); 1722 return false; 1723 } 1724 1725 if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 1726 loge("Error tethering on " + intf); 1727 return false; 1728 } 1729 mTetherInterfaceName = intf; 1730 return true; 1731 } 1732 } 1733 } 1734 // We found no interfaces to tether 1735 return false; 1736 } 1737 1738 private void stopTethering() { 1739 1740 checkAndSetConnectivityInstance(); 1741 1742 /* Clear the interface config to allow dhcp correctly configure new 1743 ip settings */ 1744 InterfaceConfiguration ifcg = null; 1745 try { 1746 ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName); 1747 if (ifcg != null) { 1748 ifcg.setLinkAddress( 1749 new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); 1750 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg); 1751 } 1752 } catch (Exception e) { 1753 loge("Error resetting interface " + mTetherInterfaceName + ", :" + e); 1754 } 1755 1756 if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 1757 loge("Untether initiate failed!"); 1758 } 1759 } 1760 1761 private boolean isWifiTethered(ArrayList<String> active) { 1762 1763 checkAndSetConnectivityInstance(); 1764 1765 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 1766 for (String intf : active) { 1767 for (String regex : wifiRegexs) { 1768 if (intf.matches(regex)) { 1769 return true; 1770 } 1771 } 1772 } 1773 // We found no interfaces that are tethered 1774 return false; 1775 } 1776 1777 /** 1778 * Set the country code from the system setting value, if any. 1779 */ 1780 private void setCountryCode() { 1781 String countryCode = Settings.Global.getString(mContext.getContentResolver(), 1782 Settings.Global.WIFI_COUNTRY_CODE); 1783 if (countryCode != null && !countryCode.isEmpty()) { 1784 setCountryCode(countryCode, false); 1785 } else { 1786 //use driver default 1787 } 1788 } 1789 1790 /** 1791 * Set the frequency band from the system setting value, if any. 1792 */ 1793 private void setFrequencyBand() { 1794 int band = Settings.Global.getInt(mContext.getContentResolver(), 1795 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO); 1796 setFrequencyBand(band, false); 1797 } 1798 1799 private void setSuspendOptimizationsNative(int reason, boolean enabled) { 1800 if (DBG) log("setSuspendOptimizationsNative: " + reason + " " + enabled); 1801 if (enabled) { 1802 mSuspendOptNeedsDisabled &= ~reason; 1803 /* None of dhcp, screen or highperf need it disabled and user wants it enabled */ 1804 if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) { 1805 mWifiNative.setSuspendOptimizations(true); 1806 } 1807 } else { 1808 mSuspendOptNeedsDisabled |= reason; 1809 mWifiNative.setSuspendOptimizations(false); 1810 } 1811 } 1812 1813 private void setSuspendOptimizations(int reason, boolean enabled) { 1814 if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled); 1815 if (enabled) { 1816 mSuspendOptNeedsDisabled &= ~reason; 1817 } else { 1818 mSuspendOptNeedsDisabled |= reason; 1819 } 1820 if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 1821 } 1822 1823 private void setWifiState(int wifiState) { 1824 final int previousWifiState = mWifiState.get(); 1825 1826 try { 1827 if (wifiState == WIFI_STATE_ENABLED) { 1828 mBatteryStats.noteWifiOn(); 1829 } else if (wifiState == WIFI_STATE_DISABLED) { 1830 mBatteryStats.noteWifiOff(); 1831 } 1832 } catch (RemoteException e) { 1833 loge("Failed to note battery stats in wifi"); 1834 } 1835 1836 mWifiState.set(wifiState); 1837 1838 if (DBG) log("setWifiState: " + syncGetWifiStateByName()); 1839 1840 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 1841 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1842 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 1843 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 1844 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1845 } 1846 1847 private void setWifiApState(int wifiApState) { 1848 final int previousWifiApState = mWifiApState.get(); 1849 1850 try { 1851 if (wifiApState == WIFI_AP_STATE_ENABLED) { 1852 mBatteryStats.noteWifiOn(); 1853 } else if (wifiApState == WIFI_AP_STATE_DISABLED) { 1854 mBatteryStats.noteWifiOff(); 1855 } 1856 } catch (RemoteException e) { 1857 loge("Failed to note battery stats in wifi"); 1858 } 1859 1860 // Update state 1861 mWifiApState.set(wifiApState); 1862 1863 if (DBG) log("setWifiApState: " + syncGetWifiApStateByName()); 1864 1865 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 1866 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1867 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); 1868 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); 1869 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1870 } 1871 1872 private static final String ID_STR = "id="; 1873 private static final String BSSID_STR = "bssid="; 1874 private static final String FREQ_STR = "freq="; 1875 private static final String LEVEL_STR = "level="; 1876 private static final String TSF_STR = "tsf="; 1877 private static final String FLAGS_STR = "flags="; 1878 private static final String SSID_STR = "ssid="; 1879 private static final String DELIMITER_STR = "===="; 1880 private static final String END_STR = "####"; 1881 1882 /** 1883 * Format: 1884 * 1885 * id=1 1886 * bssid=68:7f:76:d7:1a:6e 1887 * freq=2412 1888 * level=-44 1889 * tsf=1344626243700342 1890 * flags=[WPA2-PSK-CCMP][WPS][ESS] 1891 * ssid=zfdy 1892 * ==== 1893 * id=2 1894 * bssid=68:5f:74:d7:1a:6f 1895 * freq=5180 1896 * level=-73 1897 * tsf=1344626243700373 1898 * flags=[WPA2-PSK-CCMP][WPS][ESS] 1899 * ssid=zuby 1900 * ==== 1901 */ 1902 private void setScanResults() { 1903 String bssid = ""; 1904 int level = 0; 1905 int freq = 0; 1906 long tsf = 0; 1907 String flags = ""; 1908 WifiSsid wifiSsid = null; 1909 String scanResults; 1910 String tmpResults; 1911 StringBuffer scanResultsBuf = new StringBuffer(); 1912 int sid = 0; 1913 1914 while (true) { 1915 tmpResults = mWifiNative.scanResults(sid); 1916 if (TextUtils.isEmpty(tmpResults)) break; 1917 scanResultsBuf.append(tmpResults); 1918 scanResultsBuf.append("\n"); 1919 String[] lines = tmpResults.split("\n"); 1920 sid = -1; 1921 for (int i=lines.length - 1; i >= 0; i--) { 1922 if (lines[i].startsWith(END_STR)) { 1923 break; 1924 } else if (lines[i].startsWith(ID_STR)) { 1925 try { 1926 sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1; 1927 } catch (NumberFormatException e) { 1928 // Nothing to do 1929 } 1930 break; 1931 } 1932 } 1933 if (sid == -1) break; 1934 } 1935 1936 scanResults = scanResultsBuf.toString(); 1937 if (TextUtils.isEmpty(scanResults)) { 1938 return; 1939 } 1940 1941 // note that all these splits and substrings keep references to the original 1942 // huge string buffer while the amount we really want is generally pretty small 1943 // so make copies instead (one example b/11087956 wasted 400k of heap here). 1944 synchronized(mScanResultCache) { 1945 mScanResults = new ArrayList<ScanResult>(); 1946 String[] lines = scanResults.split("\n"); 1947 final int bssidStrLen = BSSID_STR.length(); 1948 final int flagLen = FLAGS_STR.length(); 1949 1950 for (String line : lines) { 1951 if (line.startsWith(BSSID_STR)) { 1952 bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen); 1953 } else if (line.startsWith(FREQ_STR)) { 1954 try { 1955 freq = Integer.parseInt(line.substring(FREQ_STR.length())); 1956 } catch (NumberFormatException e) { 1957 freq = 0; 1958 } 1959 } else if (line.startsWith(LEVEL_STR)) { 1960 try { 1961 level = Integer.parseInt(line.substring(LEVEL_STR.length())); 1962 /* some implementations avoid negative values by adding 256 1963 * so we need to adjust for that here. 1964 */ 1965 if (level > 0) level -= 256; 1966 } catch(NumberFormatException e) { 1967 level = 0; 1968 } 1969 } else if (line.startsWith(TSF_STR)) { 1970 try { 1971 tsf = Long.parseLong(line.substring(TSF_STR.length())); 1972 } catch (NumberFormatException e) { 1973 tsf = 0; 1974 } 1975 } else if (line.startsWith(FLAGS_STR)) { 1976 flags = new String(line.getBytes(), flagLen, line.length() - flagLen); 1977 } else if (line.startsWith(SSID_STR)) { 1978 wifiSsid = WifiSsid.createFromAsciiEncoded( 1979 line.substring(SSID_STR.length())); 1980 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) { 1981 if (bssid != null) { 1982 String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 1983 String key = bssid + ssid; 1984 ScanResult scanResult = mScanResultCache.get(key); 1985 if (scanResult != null) { 1986 scanResult.level = level; 1987 scanResult.wifiSsid = wifiSsid; 1988 // Keep existing API 1989 scanResult.SSID = (wifiSsid != null) ? wifiSsid.toString() : 1990 WifiSsid.NONE; 1991 scanResult.capabilities = flags; 1992 scanResult.frequency = freq; 1993 scanResult.timestamp = tsf; 1994 } else { 1995 scanResult = 1996 new ScanResult( 1997 wifiSsid, bssid, flags, level, freq, tsf); 1998 mScanResultCache.put(key, scanResult); 1999 } 2000 mScanResults.add(scanResult); 2001 } 2002 bssid = null; 2003 level = 0; 2004 freq = 0; 2005 tsf = 0; 2006 flags = ""; 2007 wifiSsid = null; 2008 } 2009 } 2010 } 2011 } 2012 2013 /* 2014 * Fetch RSSI and linkspeed on current connection 2015 */ 2016 private void fetchRssiAndLinkSpeedNative() { 2017 int newRssi = -1; 2018 int newLinkSpeed = -1; 2019 2020 String signalPoll = mWifiNative.signalPoll(); 2021 2022 if (signalPoll != null) { 2023 String[] lines = signalPoll.split("\n"); 2024 for (String line : lines) { 2025 String[] prop = line.split("="); 2026 if (prop.length < 2) continue; 2027 try { 2028 if (prop[0].equals("RSSI")) { 2029 newRssi = Integer.parseInt(prop[1]); 2030 } else if (prop[0].equals("LINKSPEED")) { 2031 newLinkSpeed = Integer.parseInt(prop[1]); 2032 } 2033 } catch (NumberFormatException e) { 2034 //Ignore, defaults on rssi and linkspeed are assigned 2035 } 2036 } 2037 } 2038 2039 if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values 2040 /* some implementations avoid negative values by adding 256 2041 * so we need to adjust for that here. 2042 */ 2043 if (newRssi > 0) newRssi -= 256; 2044 mWifiInfo.setRssi(newRssi); 2045 /* 2046 * Rather then sending the raw RSSI out every time it 2047 * changes, we precalculate the signal level that would 2048 * be displayed in the status bar, and only send the 2049 * broadcast if that much more coarse-grained number 2050 * changes. This cuts down greatly on the number of 2051 * broadcasts, at the cost of not informing others 2052 * interested in RSSI of all the changes in signal 2053 * level. 2054 */ 2055 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); 2056 if (newSignalLevel != mLastSignalLevel) { 2057 sendRssiChangeBroadcast(newRssi); 2058 } 2059 mLastSignalLevel = newSignalLevel; 2060 } else { 2061 mWifiInfo.setRssi(MIN_RSSI); 2062 } 2063 2064 if (newLinkSpeed != -1) { 2065 mWifiInfo.setLinkSpeed(newLinkSpeed); 2066 } 2067 } 2068 2069 /* 2070 * Fetch TX packet counters on current connection 2071 */ 2072 private void fetchPktcntNative(RssiPacketCountInfo info) { 2073 String pktcntPoll = mWifiNative.pktcntPoll(); 2074 2075 if (pktcntPoll != null) { 2076 String[] lines = pktcntPoll.split("\n"); 2077 for (String line : lines) { 2078 String[] prop = line.split("="); 2079 if (prop.length < 2) continue; 2080 try { 2081 if (prop[0].equals("TXGOOD")) { 2082 info.txgood = Integer.parseInt(prop[1]); 2083 } else if (prop[0].equals("TXBAD")) { 2084 info.txbad = Integer.parseInt(prop[1]); 2085 } 2086 } catch (NumberFormatException e) { 2087 //Ignore 2088 } 2089 } 2090 } 2091 } 2092 2093 /** 2094 * Updates mLinkProperties by merging information from various sources. 2095 * 2096 * This is needed because the information in mLinkProperties comes from multiple sources (DHCP, 2097 * netlink, static configuration, ...). When one of these sources of information has updated 2098 * link properties, we can't just assign them to mLinkProperties or we'd lose track of the 2099 * information that came from other sources. Instead, when one of those sources has new 2100 * information, we update the object that tracks the information from that source and then 2101 * call this method to apply the change to mLinkProperties. 2102 * 2103 * The information in mLinkProperties is currently obtained as follows: 2104 * - Interface name: set in the constructor. 2105 * - IPv4 and IPv6 addresses: netlink, via mInterfaceObserver. 2106 * - IPv4 routes, DNS servers, and domains: DHCP. 2107 * - HTTP proxy: the wifi config store. 2108 */ 2109 private void updateLinkProperties() { 2110 LinkProperties newLp = new LinkProperties(); 2111 2112 // Interface name and proxy are locally configured. 2113 newLp.setInterfaceName(mInterfaceName); 2114 newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); 2115 2116 // IPv4 and IPv6 addresses come from netlink. 2117 newLp.setLinkAddresses(mNetlinkLinkProperties.getLinkAddresses()); 2118 2119 // For now, routing and DNS only come from DHCP or static configuration. In the future, 2120 // we'll need to merge IPv6 DNS servers and domains coming from netlink. 2121 synchronized (mDhcpResultsLock) { 2122 // Even when we're using static configuration, we don't need to look at the config 2123 // store, because static IP configuration also populates mDhcpResults. 2124 if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) { 2125 LinkProperties lp = mDhcpResults.linkProperties; 2126 for (RouteInfo route: lp.getRoutes()) { 2127 newLp.addRoute(route); 2128 } 2129 for (InetAddress dns: lp.getDnses()) { 2130 newLp.addDns(dns); 2131 } 2132 newLp.setDomains(lp.getDomains()); 2133 } 2134 } 2135 2136 // If anything has changed, and we're already connected, send out a notification. 2137 // If we're still connecting, apps will be notified when we connect. 2138 if (!newLp.equals(mLinkProperties)) { 2139 if (DBG) { 2140 log("Link configuration changed for netId: " + mLastNetworkId 2141 + " old: " + mLinkProperties + "new: " + newLp); 2142 } 2143 mLinkProperties = newLp; 2144 if (getNetworkDetailedState() == DetailedState.CONNECTED) { 2145 sendLinkConfigurationChangedBroadcast(); 2146 } 2147 } 2148 } 2149 2150 /** 2151 * Clears all our link properties. 2152 */ 2153 private void clearLinkProperties() { 2154 // If the network used DHCP, clear the LinkProperties we stored in the config store. 2155 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 2156 mWifiConfigStore.clearLinkProperties(mLastNetworkId); 2157 } 2158 2159 // Clear the link properties obtained from DHCP and netlink. 2160 synchronized(mDhcpResultsLock) { 2161 if (mDhcpResults != null && mDhcpResults.linkProperties != null) { 2162 mDhcpResults.linkProperties.clear(); 2163 } 2164 } 2165 mNetlinkLinkProperties.clear(); 2166 2167 // Now clear the merged link properties. 2168 mLinkProperties.clear(); 2169 } 2170 2171 private int getMaxDhcpRetries() { 2172 return Settings.Global.getInt(mContext.getContentResolver(), 2173 Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, 2174 DEFAULT_MAX_DHCP_RETRIES); 2175 } 2176 2177 private void sendScanResultsAvailableBroadcast() { 2178 noteScanEnd(); 2179 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 2180 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2181 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2182 } 2183 2184 private void sendRssiChangeBroadcast(final int newRssi) { 2185 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); 2186 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2187 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); 2188 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2189 } 2190 2191 private void sendNetworkStateChangeBroadcast(String bssid) { 2192 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); 2193 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2194 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 2195 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties)); 2196 if (bssid != null) 2197 intent.putExtra(WifiManager.EXTRA_BSSID, bssid); 2198 if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK || 2199 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { 2200 intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo)); 2201 } 2202 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2203 } 2204 2205 private void sendLinkConfigurationChangedBroadcast() { 2206 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); 2207 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2208 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); 2209 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2210 } 2211 2212 private void sendSupplicantConnectionChangedBroadcast(boolean connected) { 2213 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 2214 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2215 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); 2216 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2217 } 2218 2219 /** 2220 * Record the detailed state of a network. 2221 * @param state the new {@code DetailedState} 2222 */ 2223 private void setNetworkDetailedState(NetworkInfo.DetailedState state) { 2224 if (DBG) { 2225 log("setDetailed state, old =" 2226 + mNetworkInfo.getDetailedState() + " and new state=" + state); 2227 } 2228 2229 if (state != mNetworkInfo.getDetailedState()) { 2230 mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); 2231 } 2232 } 2233 2234 private DetailedState getNetworkDetailedState() { 2235 return mNetworkInfo.getDetailedState(); 2236 } 2237 2238 2239 private SupplicantState handleSupplicantStateChange(Message message) { 2240 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 2241 SupplicantState state = stateChangeResult.state; 2242 // Supplicant state change 2243 // [31-13] Reserved for future use 2244 // [8 - 0] Supplicant state (as defined in SupplicantState.java) 2245 // 50023 supplicant_state_changed (custom|1|5) 2246 mWifiInfo.setSupplicantState(state); 2247 // Network id is only valid when we start connecting 2248 if (SupplicantState.isConnecting(state)) { 2249 mWifiInfo.setNetworkId(stateChangeResult.networkId); 2250 } else { 2251 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 2252 } 2253 2254 mWifiInfo.setBSSID(stateChangeResult.BSSID); 2255 mWifiInfo.setSSID(stateChangeResult.wifiSsid); 2256 2257 mSupplicantStateTracker.sendMessage(Message.obtain(message)); 2258 2259 return state; 2260 } 2261 2262 /** 2263 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 2264 * using the interface, stopping DHCP & disabling interface 2265 */ 2266 private void handleNetworkDisconnect() { 2267 if (DBG) log("Stopping DHCP and clearing IP"); 2268 2269 stopDhcp(); 2270 2271 try { 2272 mNwService.clearInterfaceAddresses(mInterfaceName); 2273 mNwService.disableIpv6(mInterfaceName); 2274 } catch (Exception e) { 2275 loge("Failed to clear addresses or disable ipv6" + e); 2276 } 2277 2278 /* Reset data structures */ 2279 mWifiInfo.setInetAddress(null); 2280 mWifiInfo.setBSSID(null); 2281 mWifiInfo.setSSID(null); 2282 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 2283 mWifiInfo.setRssi(MIN_RSSI); 2284 mWifiInfo.setLinkSpeed(-1); 2285 mWifiInfo.setMeteredHint(false); 2286 2287 setNetworkDetailedState(DetailedState.DISCONNECTED); 2288 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 2289 2290 /* Clear network properties */ 2291 clearLinkProperties(); 2292 2293 /* send event to CM & network change broadcast */ 2294 sendNetworkStateChangeBroadcast(mLastBssid); 2295 2296 mLastBssid= null; 2297 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 2298 } 2299 2300 private void handleSupplicantConnectionLoss() { 2301 /* Socket connection can be lost when we do a graceful shutdown 2302 * or when the driver is hung. Ensure supplicant is stopped here. 2303 */ 2304 mWifiMonitor.killSupplicant(mP2pSupported); 2305 sendSupplicantConnectionChangedBroadcast(false); 2306 setWifiState(WIFI_STATE_DISABLED); 2307 } 2308 2309 void handlePreDhcpSetup() { 2310 mDhcpActive = true; 2311 if (!mBluetoothConnectionActive) { 2312 /* 2313 * There are problems setting the Wi-Fi driver's power 2314 * mode to active when bluetooth coexistence mode is 2315 * enabled or sense. 2316 * <p> 2317 * We set Wi-Fi to active mode when 2318 * obtaining an IP address because we've found 2319 * compatibility issues with some routers with low power 2320 * mode. 2321 * <p> 2322 * In order for this active power mode to properly be set, 2323 * we disable coexistence mode until we're done with 2324 * obtaining an IP address. One exception is if we 2325 * are currently connected to a headset, since disabling 2326 * coexistence would interrupt that connection. 2327 */ 2328 // Disable the coexistence mode 2329 mWifiNative.setBluetoothCoexistenceMode( 2330 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); 2331 } 2332 2333 /* Disable power save and suspend optimizations during DHCP */ 2334 // Note: The order here is important for now. Brcm driver changes 2335 // power settings when we control suspend mode optimizations. 2336 // TODO: Remove this comment when the driver is fixed. 2337 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false); 2338 mWifiNative.setPowerSave(false); 2339 2340 stopBatchedScan(); 2341 2342 /* P2p discovery breaks dhcp, shut it down in order to get through this */ 2343 Message msg = new Message(); 2344 msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY; 2345 msg.arg1 = WifiP2pServiceImpl.ENABLED; 2346 msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE; 2347 msg.obj = mDhcpStateMachine; 2348 mWifiP2pChannel.sendMessage(msg); 2349 } 2350 2351 2352 void startDhcp() { 2353 if (mDhcpStateMachine == null) { 2354 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 2355 mContext, WifiStateMachine.this, mInterfaceName); 2356 2357 } 2358 mDhcpStateMachine.registerForPreDhcpNotification(); 2359 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); 2360 } 2361 2362 void stopDhcp() { 2363 if (mDhcpStateMachine != null) { 2364 /* In case we were in middle of DHCP operation restore back powermode */ 2365 handlePostDhcpSetup(); 2366 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); 2367 } 2368 } 2369 2370 void handlePostDhcpSetup() { 2371 /* Restore power save and suspend optimizations */ 2372 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true); 2373 mWifiNative.setPowerSave(true); 2374 2375 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED); 2376 2377 // Set the coexistence mode back to its default value 2378 mWifiNative.setBluetoothCoexistenceMode( 2379 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); 2380 2381 mDhcpActive = false; 2382 2383 startBatchedScan(); 2384 } 2385 2386 private void handleSuccessfulIpConfiguration(DhcpResults dhcpResults) { 2387 mLastSignalLevel = -1; // force update of signal strength 2388 mReconnectCount = 0; //Reset IP failure tracking 2389 synchronized (mDhcpResultsLock) { 2390 mDhcpResults = dhcpResults; 2391 } 2392 LinkProperties linkProperties = dhcpResults.linkProperties; 2393 mWifiConfigStore.setLinkProperties(mLastNetworkId, new LinkProperties(linkProperties)); 2394 InetAddress addr = null; 2395 Iterator<InetAddress> addrs = linkProperties.getAddresses().iterator(); 2396 if (addrs.hasNext()) { 2397 addr = addrs.next(); 2398 } 2399 mWifiInfo.setInetAddress(addr); 2400 mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint()); 2401 updateLinkProperties(); 2402 } 2403 2404 private void handleFailedIpConfiguration() { 2405 loge("IP configuration failed"); 2406 2407 mWifiInfo.setInetAddress(null); 2408 mWifiInfo.setMeteredHint(false); 2409 /** 2410 * If we've exceeded the maximum number of retries for DHCP 2411 * to a given network, disable the network 2412 */ 2413 int maxRetries = getMaxDhcpRetries(); 2414 // maxRetries == 0 means keep trying forever 2415 if (maxRetries > 0 && ++mReconnectCount > maxRetries) { 2416 loge("Failed " + 2417 mReconnectCount + " times, Disabling " + mLastNetworkId); 2418 mWifiConfigStore.disableNetwork(mLastNetworkId, 2419 WifiConfiguration.DISABLED_DHCP_FAILURE); 2420 mReconnectCount = 0; 2421 } 2422 2423 /* DHCP times out after about 30 seconds, we do a 2424 * disconnect and an immediate reconnect to try again 2425 */ 2426 mWifiNative.disconnect(); 2427 mWifiNative.reconnect(); 2428 } 2429 2430 /* Current design is to not set the config on a running hostapd but instead 2431 * stop and start tethering when user changes config on a running access point 2432 * 2433 * TODO: Add control channel setup through hostapd that allows changing config 2434 * on a running daemon 2435 */ 2436 private void startSoftApWithConfig(final WifiConfiguration config) { 2437 // start hostapd on a seperate thread 2438 new Thread(new Runnable() { 2439 public void run() { 2440 try { 2441 mNwService.startAccessPoint(config, mInterfaceName); 2442 } catch (Exception e) { 2443 loge("Exception in softap start " + e); 2444 try { 2445 mNwService.stopAccessPoint(mInterfaceName); 2446 mNwService.startAccessPoint(config, mInterfaceName); 2447 } catch (Exception e1) { 2448 loge("Exception in softap re-start " + e1); 2449 sendMessage(CMD_START_AP_FAILURE); 2450 return; 2451 } 2452 } 2453 if (DBG) log("Soft AP start successful"); 2454 sendMessage(CMD_START_AP_SUCCESS); 2455 } 2456 }).start(); 2457 } 2458 2459 /******************************************************** 2460 * HSM states 2461 *******************************************************/ 2462 2463 class DefaultState extends State { 2464 @Override 2465 public boolean processMessage(Message message) { 2466 switch (message.what) { 2467 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 2468 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 2469 mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 2470 } else { 2471 loge("WifiP2pService connection failure, error=" + message.arg1); 2472 } 2473 break; 2474 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 2475 loge("WifiP2pService channel lost, message.arg1 =" + message.arg1); 2476 //TODO: Re-establish connection to state machine after a delay 2477 //mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger()); 2478 break; 2479 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 2480 mBluetoothConnectionActive = (message.arg1 != 2481 BluetoothAdapter.STATE_DISCONNECTED); 2482 break; 2483 /* Synchronous call returns */ 2484 case CMD_PING_SUPPLICANT: 2485 case CMD_ENABLE_NETWORK: 2486 case CMD_ADD_OR_UPDATE_NETWORK: 2487 case CMD_REMOVE_NETWORK: 2488 case CMD_SAVE_CONFIG: 2489 replyToMessage(message, message.what, FAILURE); 2490 break; 2491 case CMD_GET_CONFIGURED_NETWORKS: 2492 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 2493 break; 2494 case CMD_ENABLE_RSSI_POLL: 2495 mEnableRssiPolling = (message.arg1 == 1); 2496 break; 2497 case CMD_ENABLE_BACKGROUND_SCAN: 2498 mEnableBackgroundScan = (message.arg1 == 1); 2499 break; 2500 case CMD_SET_HIGH_PERF_MODE: 2501 if (message.arg1 == 1) { 2502 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false); 2503 } else { 2504 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true); 2505 } 2506 break; 2507 case CMD_BOOT_COMPLETED: 2508 String countryCode = mPersistedCountryCode; 2509 if (TextUtils.isEmpty(countryCode) == false) { 2510 Settings.Global.putString(mContext.getContentResolver(), 2511 Settings.Global.WIFI_COUNTRY_CODE, 2512 countryCode); 2513 // it may be that the state transition that should send this info 2514 // to the driver happened between mPersistedCountryCode getting set 2515 // and now, so simply persisting it here would mean we have sent 2516 // nothing to the driver. Send the cmd so it might be set now. 2517 sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE, countryCode); 2518 } 2519 break; 2520 case CMD_SET_BATCHED_SCAN: 2521 recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj); 2522 break; 2523 case CMD_POLL_BATCHED_SCAN: 2524 handleBatchedScanPollRequest(); 2525 break; 2526 case CMD_START_NEXT_BATCHED_SCAN: 2527 startNextBatchedScan(); 2528 break; 2529 /* Discard */ 2530 case CMD_START_SCAN: 2531 case CMD_START_SUPPLICANT: 2532 case CMD_STOP_SUPPLICANT: 2533 case CMD_STOP_SUPPLICANT_FAILED: 2534 case CMD_START_DRIVER: 2535 case CMD_STOP_DRIVER: 2536 case CMD_DELAYED_STOP_DRIVER: 2537 case CMD_DRIVER_START_TIMED_OUT: 2538 case CMD_START_AP: 2539 case CMD_START_AP_SUCCESS: 2540 case CMD_START_AP_FAILURE: 2541 case CMD_STOP_AP: 2542 case CMD_TETHER_STATE_CHANGE: 2543 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 2544 case CMD_DISCONNECT: 2545 case CMD_RECONNECT: 2546 case CMD_REASSOCIATE: 2547 case CMD_RELOAD_TLS_AND_RECONNECT: 2548 case WifiMonitor.SUP_CONNECTION_EVENT: 2549 case WifiMonitor.SUP_DISCONNECTION_EVENT: 2550 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2551 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2552 case WifiMonitor.SCAN_RESULTS_EVENT: 2553 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2554 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 2555 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 2556 case WifiMonitor.WPS_OVERLAP_EVENT: 2557 case CMD_BLACKLIST_NETWORK: 2558 case CMD_CLEAR_BLACKLIST: 2559 case CMD_SET_OPERATIONAL_MODE: 2560 case CMD_SET_COUNTRY_CODE: 2561 case CMD_SET_FREQUENCY_BAND: 2562 case CMD_RSSI_POLL: 2563 case CMD_ENABLE_ALL_NETWORKS: 2564 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 2565 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 2566 /* Handled by WifiApConfigStore */ 2567 case CMD_SET_AP_CONFIG: 2568 case CMD_SET_AP_CONFIG_COMPLETED: 2569 case CMD_REQUEST_AP_CONFIG: 2570 case CMD_RESPONSE_AP_CONFIG: 2571 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 2572 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 2573 case CMD_NO_NETWORKS_PERIODIC_SCAN: 2574 case CMD_DISABLE_P2P_RSP: 2575 break; 2576 case DhcpStateMachine.CMD_ON_QUIT: 2577 mDhcpStateMachine = null; 2578 break; 2579 case CMD_SET_SUSPEND_OPT_ENABLED: 2580 if (message.arg1 == 1) { 2581 mSuspendWakeLock.release(); 2582 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true); 2583 } else { 2584 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false); 2585 } 2586 break; 2587 case WifiMonitor.DRIVER_HUNG_EVENT: 2588 setSupplicantRunning(false); 2589 setSupplicantRunning(true); 2590 break; 2591 case WifiManager.CONNECT_NETWORK: 2592 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 2593 WifiManager.BUSY); 2594 break; 2595 case WifiManager.FORGET_NETWORK: 2596 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 2597 WifiManager.BUSY); 2598 break; 2599 case WifiManager.SAVE_NETWORK: 2600 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 2601 WifiManager.BUSY); 2602 break; 2603 case WifiManager.START_WPS: 2604 replyToMessage(message, WifiManager.WPS_FAILED, 2605 WifiManager.BUSY); 2606 break; 2607 case WifiManager.CANCEL_WPS: 2608 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, 2609 WifiManager.BUSY); 2610 break; 2611 case WifiManager.DISABLE_NETWORK: 2612 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 2613 WifiManager.BUSY); 2614 break; 2615 case WifiManager.RSSI_PKTCNT_FETCH: 2616 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED, 2617 WifiManager.BUSY); 2618 break; 2619 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 2620 NetworkInfo info = (NetworkInfo) message.obj; 2621 mP2pConnected.set(info.isConnected()); 2622 break; 2623 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 2624 mTemporarilyDisconnectWifi = (message.arg1 == 1); 2625 replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 2626 break; 2627 case CMD_IP_ADDRESS_UPDATED: 2628 // addLinkAddress is a no-op if called more than once with the same address. 2629 if (mNetlinkLinkProperties.addLinkAddress((LinkAddress) message.obj)) { 2630 updateLinkProperties(); 2631 } 2632 break; 2633 case CMD_IP_ADDRESS_REMOVED: 2634 if (mNetlinkLinkProperties.removeLinkAddress((LinkAddress) message.obj)) { 2635 updateLinkProperties(); 2636 } 2637 break; 2638 default: 2639 loge("Error! unhandled message" + message); 2640 break; 2641 } 2642 return HANDLED; 2643 } 2644 } 2645 2646 class InitialState extends State { 2647 @Override 2648 public void enter() { 2649 mWifiNative.unloadDriver(); 2650 2651 if (mWifiP2pChannel == null) { 2652 mWifiP2pChannel = new AsyncChannel(); 2653 mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger()); 2654 } 2655 2656 if (mWifiApConfigChannel == null) { 2657 mWifiApConfigChannel = new AsyncChannel(); 2658 WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore( 2659 mContext, getHandler()); 2660 wifiApConfigStore.loadApConfiguration(); 2661 mWifiApConfigChannel.connectSync(mContext, getHandler(), 2662 wifiApConfigStore.getMessenger()); 2663 } 2664 } 2665 @Override 2666 public boolean processMessage(Message message) { 2667 switch (message.what) { 2668 case CMD_START_SUPPLICANT: 2669 if (mWifiNative.loadDriver()) { 2670 try { 2671 mNwService.wifiFirmwareReload(mInterfaceName, "STA"); 2672 } catch (Exception e) { 2673 loge("Failed to reload STA firmware " + e); 2674 // continue 2675 } 2676 2677 try { 2678 // A runtime crash can leave the interface up and 2679 // this affects connectivity when supplicant starts up. 2680 // Ensure interface is down before a supplicant start. 2681 mNwService.setInterfaceDown(mInterfaceName); 2682 // Set privacy extensions 2683 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); 2684 2685 // IPv6 is enabled only as long as access point is connected since: 2686 // - IPv6 addresses and routes stick around after disconnection 2687 // - kernel is unaware when connected and fails to start IPv6 negotiation 2688 // - kernel can start autoconfiguration when 802.1x is not complete 2689 mNwService.disableIpv6(mInterfaceName); 2690 } catch (RemoteException re) { 2691 loge("Unable to change interface settings: " + re); 2692 } catch (IllegalStateException ie) { 2693 loge("Unable to change interface settings: " + ie); 2694 } 2695 2696 /* Stop a running supplicant after a runtime restart 2697 * Avoids issues with drivers that do not handle interface down 2698 * on a running supplicant properly. 2699 */ 2700 mWifiMonitor.killSupplicant(mP2pSupported); 2701 if(mWifiNative.startSupplicant(mP2pSupported)) { 2702 setWifiState(WIFI_STATE_ENABLING); 2703 if (DBG) log("Supplicant start successful"); 2704 mWifiMonitor.startMonitoring(); 2705 transitionTo(mSupplicantStartingState); 2706 } else { 2707 loge("Failed to start supplicant!"); 2708 } 2709 } else { 2710 loge("Failed to load driver"); 2711 } 2712 break; 2713 case CMD_START_AP: 2714 if (mWifiNative.loadDriver()) { 2715 setWifiApState(WIFI_AP_STATE_ENABLING); 2716 transitionTo(mSoftApStartingState); 2717 } else { 2718 loge("Failed to load driver for softap"); 2719 } 2720 default: 2721 return NOT_HANDLED; 2722 } 2723 return HANDLED; 2724 } 2725 } 2726 2727 class SupplicantStartingState extends State { 2728 private void initializeWpsDetails() { 2729 String detail; 2730 detail = SystemProperties.get("ro.product.name", ""); 2731 if (!mWifiNative.setDeviceName(detail)) { 2732 loge("Failed to set device name " + detail); 2733 } 2734 detail = SystemProperties.get("ro.product.manufacturer", ""); 2735 if (!mWifiNative.setManufacturer(detail)) { 2736 loge("Failed to set manufacturer " + detail); 2737 } 2738 detail = SystemProperties.get("ro.product.model", ""); 2739 if (!mWifiNative.setModelName(detail)) { 2740 loge("Failed to set model name " + detail); 2741 } 2742 detail = SystemProperties.get("ro.product.model", ""); 2743 if (!mWifiNative.setModelNumber(detail)) { 2744 loge("Failed to set model number " + detail); 2745 } 2746 detail = SystemProperties.get("ro.serialno", ""); 2747 if (!mWifiNative.setSerialNumber(detail)) { 2748 loge("Failed to set serial number " + detail); 2749 } 2750 if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) { 2751 loge("Failed to set WPS config methods"); 2752 } 2753 if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) { 2754 loge("Failed to set primary device type " + mPrimaryDeviceType); 2755 } 2756 } 2757 2758 @Override 2759 public boolean processMessage(Message message) { 2760 switch(message.what) { 2761 case WifiMonitor.SUP_CONNECTION_EVENT: 2762 if (DBG) log("Supplicant connection established"); 2763 setWifiState(WIFI_STATE_ENABLED); 2764 mSupplicantRestartCount = 0; 2765 /* Reset the supplicant state to indicate the supplicant 2766 * state is not known at this time */ 2767 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2768 /* Initialize data structures */ 2769 mLastBssid = null; 2770 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 2771 mLastSignalLevel = -1; 2772 2773 mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); 2774 mWifiConfigStore.loadAndEnableAllNetworks(); 2775 initializeWpsDetails(); 2776 2777 sendSupplicantConnectionChangedBroadcast(true); 2778 transitionTo(mDriverStartedState); 2779 break; 2780 case WifiMonitor.SUP_DISCONNECTION_EVENT: 2781 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { 2782 loge("Failed to setup control channel, restart supplicant"); 2783 mWifiMonitor.killSupplicant(mP2pSupported); 2784 transitionTo(mInitialState); 2785 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 2786 } else { 2787 loge("Failed " + mSupplicantRestartCount + 2788 " times to start supplicant, unload driver"); 2789 mSupplicantRestartCount = 0; 2790 setWifiState(WIFI_STATE_UNKNOWN); 2791 transitionTo(mInitialState); 2792 } 2793 break; 2794 case CMD_START_SUPPLICANT: 2795 case CMD_STOP_SUPPLICANT: 2796 case CMD_START_AP: 2797 case CMD_STOP_AP: 2798 case CMD_START_DRIVER: 2799 case CMD_STOP_DRIVER: 2800 case CMD_SET_OPERATIONAL_MODE: 2801 case CMD_SET_COUNTRY_CODE: 2802 case CMD_SET_FREQUENCY_BAND: 2803 case CMD_START_PACKET_FILTERING: 2804 case CMD_STOP_PACKET_FILTERING: 2805 deferMessage(message); 2806 break; 2807 default: 2808 return NOT_HANDLED; 2809 } 2810 return HANDLED; 2811 } 2812 } 2813 2814 class SupplicantStartedState extends State { 2815 @Override 2816 public void enter() { 2817 /* Wifi is available as long as we have a connection to supplicant */ 2818 mNetworkInfo.setIsAvailable(true); 2819 2820 int defaultInterval = mContext.getResources().getInteger( 2821 R.integer.config_wifi_supplicant_scan_interval); 2822 2823 mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 2824 Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, 2825 defaultInterval); 2826 2827 mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000); 2828 } 2829 @Override 2830 public boolean processMessage(Message message) { 2831 switch(message.what) { 2832 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ 2833 if (mP2pSupported) { 2834 transitionTo(mWaitForP2pDisableState); 2835 } else { 2836 transitionTo(mSupplicantStoppingState); 2837 } 2838 break; 2839 case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ 2840 loge("Connection lost, restart supplicant"); 2841 handleSupplicantConnectionLoss(); 2842 handleNetworkDisconnect(); 2843 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2844 if (mP2pSupported) { 2845 transitionTo(mWaitForP2pDisableState); 2846 } else { 2847 transitionTo(mInitialState); 2848 } 2849 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 2850 break; 2851 case WifiMonitor.SCAN_RESULTS_EVENT: 2852 setScanResults(); 2853 sendScanResultsAvailableBroadcast(); 2854 mScanResultIsPending = false; 2855 break; 2856 case CMD_PING_SUPPLICANT: 2857 boolean ok = mWifiNative.ping(); 2858 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 2859 break; 2860 /* Cannot start soft AP while in client mode */ 2861 case CMD_START_AP: 2862 loge("Failed to start soft AP with a running supplicant"); 2863 setWifiApState(WIFI_AP_STATE_FAILED); 2864 break; 2865 case CMD_SET_OPERATIONAL_MODE: 2866 mOperationalMode = message.arg1; 2867 break; 2868 default: 2869 return NOT_HANDLED; 2870 } 2871 return HANDLED; 2872 } 2873 2874 @Override 2875 public void exit() { 2876 mNetworkInfo.setIsAvailable(false); 2877 } 2878 } 2879 2880 class SupplicantStoppingState extends State { 2881 @Override 2882 public void enter() { 2883 /* Send any reset commands to supplicant before shutting it down */ 2884 handleNetworkDisconnect(); 2885 if (mDhcpStateMachine != null) { 2886 mDhcpStateMachine.doQuit(); 2887 } 2888 2889 if (DBG) log("stopping supplicant"); 2890 mWifiMonitor.stopSupplicant(); 2891 2892 /* Send ourselves a delayed message to indicate failure after a wait time */ 2893 sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED, 2894 ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS); 2895 setWifiState(WIFI_STATE_DISABLING); 2896 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2897 } 2898 @Override 2899 public boolean processMessage(Message message) { 2900 switch(message.what) { 2901 case WifiMonitor.SUP_CONNECTION_EVENT: 2902 loge("Supplicant connection received while stopping"); 2903 break; 2904 case WifiMonitor.SUP_DISCONNECTION_EVENT: 2905 if (DBG) log("Supplicant connection lost"); 2906 handleSupplicantConnectionLoss(); 2907 transitionTo(mInitialState); 2908 break; 2909 case CMD_STOP_SUPPLICANT_FAILED: 2910 if (message.arg1 == mSupplicantStopFailureToken) { 2911 loge("Timed out on a supplicant stop, kill and proceed"); 2912 handleSupplicantConnectionLoss(); 2913 transitionTo(mInitialState); 2914 } 2915 break; 2916 case CMD_START_SUPPLICANT: 2917 case CMD_STOP_SUPPLICANT: 2918 case CMD_START_AP: 2919 case CMD_STOP_AP: 2920 case CMD_START_DRIVER: 2921 case CMD_STOP_DRIVER: 2922 case CMD_SET_OPERATIONAL_MODE: 2923 case CMD_SET_COUNTRY_CODE: 2924 case CMD_SET_FREQUENCY_BAND: 2925 case CMD_START_PACKET_FILTERING: 2926 case CMD_STOP_PACKET_FILTERING: 2927 deferMessage(message); 2928 break; 2929 default: 2930 return NOT_HANDLED; 2931 } 2932 return HANDLED; 2933 } 2934 } 2935 2936 class DriverStartingState extends State { 2937 private int mTries; 2938 @Override 2939 public void enter() { 2940 mTries = 1; 2941 /* Send ourselves a delayed message to start driver a second time */ 2942 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 2943 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 2944 } 2945 @Override 2946 public boolean processMessage(Message message) { 2947 switch(message.what) { 2948 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2949 SupplicantState state = handleSupplicantStateChange(message); 2950 /* If suplicant is exiting out of INTERFACE_DISABLED state into 2951 * a state that indicates driver has started, it is ready to 2952 * receive driver commands 2953 */ 2954 if (SupplicantState.isDriverActive(state)) { 2955 transitionTo(mDriverStartedState); 2956 } 2957 break; 2958 case CMD_DRIVER_START_TIMED_OUT: 2959 if (message.arg1 == mDriverStartToken) { 2960 if (mTries >= 2) { 2961 loge("Failed to start driver after " + mTries); 2962 transitionTo(mDriverStoppedState); 2963 } else { 2964 loge("Driver start failed, retrying"); 2965 mWakeLock.acquire(); 2966 mWifiNative.startDriver(); 2967 mWakeLock.release(); 2968 2969 ++mTries; 2970 /* Send ourselves a delayed message to start driver again */ 2971 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 2972 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 2973 } 2974 } 2975 break; 2976 /* Queue driver commands & connection events */ 2977 case CMD_START_DRIVER: 2978 case CMD_STOP_DRIVER: 2979 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2980 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2981 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 2982 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 2983 case WifiMonitor.WPS_OVERLAP_EVENT: 2984 case CMD_SET_COUNTRY_CODE: 2985 case CMD_SET_FREQUENCY_BAND: 2986 case CMD_START_PACKET_FILTERING: 2987 case CMD_STOP_PACKET_FILTERING: 2988 case CMD_START_SCAN: 2989 case CMD_DISCONNECT: 2990 case CMD_REASSOCIATE: 2991 case CMD_RECONNECT: 2992 deferMessage(message); 2993 break; 2994 default: 2995 return NOT_HANDLED; 2996 } 2997 return HANDLED; 2998 } 2999 } 3000 3001 class DriverStartedState extends State { 3002 @Override 3003 public void enter() { 3004 mIsRunning = true; 3005 mInDelayedStop = false; 3006 mDelayedStopCounter++; 3007 updateBatteryWorkSource(null); 3008 /** 3009 * Enable bluetooth coexistence scan mode when bluetooth connection is active. 3010 * When this mode is on, some of the low-level scan parameters used by the 3011 * driver are changed to reduce interference with bluetooth 3012 */ 3013 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 3014 /* set country code */ 3015 setCountryCode(); 3016 /* set frequency band of operation */ 3017 setFrequencyBand(); 3018 /* initialize network state */ 3019 setNetworkDetailedState(DetailedState.DISCONNECTED); 3020 3021 /* Remove any filtering on Multicast v6 at start */ 3022 mWifiNative.stopFilteringMulticastV6Packets(); 3023 3024 /* Reset Multicast v4 filtering state */ 3025 if (mFilteringMulticastV4Packets.get()) { 3026 mWifiNative.startFilteringMulticastV4Packets(); 3027 } else { 3028 mWifiNative.stopFilteringMulticastV4Packets(); 3029 } 3030 3031 mDhcpActive = false; 3032 3033 startBatchedScan(); 3034 3035 if (mOperationalMode != CONNECT_MODE) { 3036 mWifiNative.disconnect(); 3037 mWifiConfigStore.disableAllNetworks(); 3038 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 3039 setWifiState(WIFI_STATE_DISABLED); 3040 } 3041 transitionTo(mScanModeState); 3042 } else { 3043 /* Driver stop may have disabled networks, enable right after start */ 3044 mWifiConfigStore.enableAllNetworks(); 3045 3046 if (DBG) log("Attempting to reconnect to wifi network .."); 3047 mWifiNative.reconnect(); 3048 3049 // Status pulls in the current supplicant state and network connection state 3050 // events over the monitor connection. This helps framework sync up with 3051 // current supplicant state 3052 mWifiNative.status(); 3053 transitionTo(mDisconnectedState); 3054 } 3055 3056 // We may have missed screen update at boot 3057 if (mScreenBroadcastReceived.get() == false) { 3058 PowerManager powerManager = (PowerManager)mContext.getSystemService( 3059 Context.POWER_SERVICE); 3060 handleScreenStateChanged(powerManager.isScreenOn()); 3061 } else { 3062 // Set the right suspend mode settings 3063 mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0 3064 && mUserWantsSuspendOpt.get()); 3065 } 3066 mWifiNative.setPowerSave(true); 3067 3068 if (mP2pSupported) { 3069 if (mOperationalMode == CONNECT_MODE) { 3070 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); 3071 } else { 3072 // P2P statemachine starts in disabled state, and is not enabled until 3073 // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to 3074 // keep it disabled. 3075 } 3076 } 3077 3078 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 3079 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3080 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED); 3081 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3082 } 3083 3084 @Override 3085 public boolean processMessage(Message message) { 3086 switch(message.what) { 3087 case CMD_START_SCAN: 3088 noteScanStart(message.arg1, (WorkSource) message.obj); 3089 startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP); 3090 break; 3091 case CMD_SET_BATCHED_SCAN: 3092 if (recordBatchedScanSettings(message.arg1, message.arg2, 3093 (Bundle)message.obj)) { 3094 startBatchedScan(); 3095 } 3096 break; 3097 case CMD_SET_COUNTRY_CODE: 3098 String country = (String) message.obj; 3099 if (DBG) log("set country code " + country); 3100 if (country != null) { 3101 country = country.toUpperCase(Locale.ROOT); 3102 if (mLastSetCountryCode == null 3103 || country.equals(mLastSetCountryCode) == false) { 3104 if (mWifiNative.setCountryCode(country)) { 3105 mLastSetCountryCode = country; 3106 } else { 3107 loge("Failed to set country code " + country); 3108 } 3109 } 3110 } 3111 break; 3112 case CMD_SET_FREQUENCY_BAND: 3113 int band = message.arg1; 3114 if (DBG) log("set frequency band " + band); 3115 if (mWifiNative.setBand(band)) { 3116 mFrequencyBand.set(band); 3117 // flush old data - like scan results 3118 mWifiNative.bssFlush(); 3119 //Fetch the latest scan results when frequency band is set 3120 startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP); 3121 } else { 3122 loge("Failed to set frequency band " + band); 3123 } 3124 break; 3125 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 3126 mBluetoothConnectionActive = (message.arg1 != 3127 BluetoothAdapter.STATE_DISCONNECTED); 3128 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 3129 break; 3130 case CMD_STOP_DRIVER: 3131 int mode = message.arg1; 3132 3133 /* Already doing a delayed stop */ 3134 if (mInDelayedStop) { 3135 if (DBG) log("Already in delayed stop"); 3136 break; 3137 } 3138 /* disconnect right now, but leave the driver running for a bit */ 3139 mWifiConfigStore.disableAllNetworks(); 3140 3141 mInDelayedStop = true; 3142 mDelayedStopCounter++; 3143 if (DBG) log("Delayed stop message " + mDelayedStopCounter); 3144 3145 /* send regular delayed shut down */ 3146 Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); 3147 driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); 3148 mDriverStopIntent = PendingIntent.getBroadcast(mContext, 3149 DRIVER_STOP_REQUEST, driverStopIntent, 3150 PendingIntent.FLAG_UPDATE_CURRENT); 3151 3152 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 3153 + mDriverStopDelayMs, mDriverStopIntent); 3154 break; 3155 case CMD_START_DRIVER: 3156 if (mInDelayedStop) { 3157 mInDelayedStop = false; 3158 mDelayedStopCounter++; 3159 mAlarmManager.cancel(mDriverStopIntent); 3160 if (DBG) log("Delayed stop ignored due to start"); 3161 if (mOperationalMode == CONNECT_MODE) { 3162 mWifiConfigStore.enableAllNetworks(); 3163 } 3164 } 3165 break; 3166 case CMD_DELAYED_STOP_DRIVER: 3167 if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter); 3168 if (message.arg1 != mDelayedStopCounter) break; 3169 if (getCurrentState() != mDisconnectedState) { 3170 mWifiNative.disconnect(); 3171 handleNetworkDisconnect(); 3172 } 3173 mWakeLock.acquire(); 3174 mWifiNative.stopDriver(); 3175 mWakeLock.release(); 3176 if (mP2pSupported) { 3177 transitionTo(mWaitForP2pDisableState); 3178 } else { 3179 transitionTo(mDriverStoppingState); 3180 } 3181 break; 3182 case CMD_START_PACKET_FILTERING: 3183 if (message.arg1 == MULTICAST_V6) { 3184 mWifiNative.startFilteringMulticastV6Packets(); 3185 } else if (message.arg1 == MULTICAST_V4) { 3186 mWifiNative.startFilteringMulticastV4Packets(); 3187 } else { 3188 loge("Illegal arugments to CMD_START_PACKET_FILTERING"); 3189 } 3190 break; 3191 case CMD_STOP_PACKET_FILTERING: 3192 if (message.arg1 == MULTICAST_V6) { 3193 mWifiNative.stopFilteringMulticastV6Packets(); 3194 } else if (message.arg1 == MULTICAST_V4) { 3195 mWifiNative.stopFilteringMulticastV4Packets(); 3196 } else { 3197 loge("Illegal arugments to CMD_STOP_PACKET_FILTERING"); 3198 } 3199 break; 3200 case CMD_SET_SUSPEND_OPT_ENABLED: 3201 if (message.arg1 == 1) { 3202 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true); 3203 mSuspendWakeLock.release(); 3204 } else { 3205 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false); 3206 } 3207 break; 3208 case CMD_SET_HIGH_PERF_MODE: 3209 if (message.arg1 == 1) { 3210 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false); 3211 } else { 3212 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true); 3213 } 3214 break; 3215 case CMD_ENABLE_TDLS: 3216 if (message.obj != null) { 3217 String remoteAddress = (String) message.obj; 3218 boolean enable = (message.arg1 == 1); 3219 mWifiNative.startTdls(remoteAddress, enable); 3220 } 3221 break; 3222 default: 3223 return NOT_HANDLED; 3224 } 3225 return HANDLED; 3226 } 3227 @Override 3228 public void exit() { 3229 mIsRunning = false; 3230 updateBatteryWorkSource(null); 3231 mScanResults = new ArrayList<ScanResult>(); 3232 3233 stopBatchedScan(); 3234 3235 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 3236 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3237 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 3238 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3239 noteScanEnd(); // wrap up any pending request. 3240 3241 mLastSetCountryCode = null; 3242 } 3243 } 3244 3245 class WaitForP2pDisableState extends State { 3246 private State mTransitionToState; 3247 @Override 3248 public void enter() { 3249 switch (getCurrentMessage().what) { 3250 case WifiMonitor.SUP_DISCONNECTION_EVENT: 3251 mTransitionToState = mInitialState; 3252 break; 3253 case CMD_DELAYED_STOP_DRIVER: 3254 mTransitionToState = mDriverStoppingState; 3255 break; 3256 case CMD_STOP_SUPPLICANT: 3257 mTransitionToState = mSupplicantStoppingState; 3258 break; 3259 default: 3260 mTransitionToState = mDriverStoppingState; 3261 break; 3262 } 3263 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ); 3264 } 3265 @Override 3266 public boolean processMessage(Message message) { 3267 switch(message.what) { 3268 case WifiStateMachine.CMD_DISABLE_P2P_RSP: 3269 transitionTo(mTransitionToState); 3270 break; 3271 /* Defer wifi start/shut and driver commands */ 3272 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3273 case CMD_START_SUPPLICANT: 3274 case CMD_STOP_SUPPLICANT: 3275 case CMD_START_AP: 3276 case CMD_STOP_AP: 3277 case CMD_START_DRIVER: 3278 case CMD_STOP_DRIVER: 3279 case CMD_SET_OPERATIONAL_MODE: 3280 case CMD_SET_COUNTRY_CODE: 3281 case CMD_SET_FREQUENCY_BAND: 3282 case CMD_START_PACKET_FILTERING: 3283 case CMD_STOP_PACKET_FILTERING: 3284 case CMD_START_SCAN: 3285 case CMD_DISCONNECT: 3286 case CMD_REASSOCIATE: 3287 case CMD_RECONNECT: 3288 deferMessage(message); 3289 break; 3290 default: 3291 return NOT_HANDLED; 3292 } 3293 return HANDLED; 3294 } 3295 } 3296 3297 class DriverStoppingState extends State { 3298 @Override 3299 public boolean processMessage(Message message) { 3300 switch(message.what) { 3301 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3302 SupplicantState state = handleSupplicantStateChange(message); 3303 if (state == SupplicantState.INTERFACE_DISABLED) { 3304 transitionTo(mDriverStoppedState); 3305 } 3306 break; 3307 /* Queue driver commands */ 3308 case CMD_START_DRIVER: 3309 case CMD_STOP_DRIVER: 3310 case CMD_SET_COUNTRY_CODE: 3311 case CMD_SET_FREQUENCY_BAND: 3312 case CMD_START_PACKET_FILTERING: 3313 case CMD_STOP_PACKET_FILTERING: 3314 case CMD_START_SCAN: 3315 case CMD_DISCONNECT: 3316 case CMD_REASSOCIATE: 3317 case CMD_RECONNECT: 3318 deferMessage(message); 3319 break; 3320 default: 3321 return NOT_HANDLED; 3322 } 3323 return HANDLED; 3324 } 3325 } 3326 3327 class DriverStoppedState extends State { 3328 @Override 3329 public boolean processMessage(Message message) { 3330 switch (message.what) { 3331 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3332 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 3333 SupplicantState state = stateChangeResult.state; 3334 // A WEXT bug means that we can be back to driver started state 3335 // unexpectedly 3336 if (SupplicantState.isDriverActive(state)) { 3337 transitionTo(mDriverStartedState); 3338 } 3339 break; 3340 case CMD_START_DRIVER: 3341 mWakeLock.acquire(); 3342 mWifiNative.startDriver(); 3343 mWakeLock.release(); 3344 transitionTo(mDriverStartingState); 3345 break; 3346 default: 3347 return NOT_HANDLED; 3348 } 3349 return HANDLED; 3350 } 3351 } 3352 3353 class ScanModeState extends State { 3354 private int mLastOperationMode; 3355 @Override 3356 public void enter() { 3357 mLastOperationMode = mOperationalMode; 3358 } 3359 @Override 3360 public boolean processMessage(Message message) { 3361 switch(message.what) { 3362 case CMD_SET_OPERATIONAL_MODE: 3363 if (message.arg1 == CONNECT_MODE) { 3364 3365 if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 3366 setWifiState(WIFI_STATE_ENABLED); 3367 // Load and re-enable networks when going back to enabled state 3368 // This is essential for networks to show up after restore 3369 mWifiConfigStore.loadAndEnableAllNetworks(); 3370 mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P); 3371 } else { 3372 mWifiConfigStore.enableAllNetworks(); 3373 } 3374 3375 mWifiNative.reconnect(); 3376 3377 mOperationalMode = CONNECT_MODE; 3378 transitionTo(mDisconnectedState); 3379 } else { 3380 // Nothing to do 3381 return HANDLED; 3382 } 3383 break; 3384 // Handle scan. All the connection related commands are 3385 // handled only in ConnectModeState 3386 case CMD_START_SCAN: 3387 noteScanStart(message.arg1, (WorkSource) message.obj); 3388 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP); 3389 break; 3390 default: 3391 return NOT_HANDLED; 3392 } 3393 return HANDLED; 3394 } 3395 } 3396 3397 class ConnectModeState extends State { 3398 @Override 3399 public boolean processMessage(Message message) { 3400 WifiConfiguration config; 3401 boolean ok; 3402 switch(message.what) { 3403 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 3404 mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT); 3405 break; 3406 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 3407 mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT); 3408 break; 3409 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3410 SupplicantState state = handleSupplicantStateChange(message); 3411 // A driver/firmware hang can now put the interface in a down state. 3412 // We detect the interface going down and recover from it 3413 if (!SupplicantState.isDriverActive(state)) { 3414 if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 3415 handleNetworkDisconnect(); 3416 } 3417 log("Detected an interface down, restart driver"); 3418 transitionTo(mDriverStoppedState); 3419 sendMessage(CMD_START_DRIVER); 3420 break; 3421 } 3422 3423 // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT 3424 // when authentication times out after a successful connection, 3425 // we can figure this from the supplicant state. If supplicant 3426 // state is DISCONNECTED, but the mNetworkInfo says we are not 3427 // disconnected, we need to handle a disconnection 3428 if (state == SupplicantState.DISCONNECTED && 3429 mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 3430 if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect"); 3431 handleNetworkDisconnect(); 3432 transitionTo(mDisconnectedState); 3433 } 3434 break; 3435 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 3436 if (message.arg1 == 1) { 3437 mWifiNative.disconnect(); 3438 mTemporarilyDisconnectWifi = true; 3439 } else { 3440 mWifiNative.reconnect(); 3441 mTemporarilyDisconnectWifi = false; 3442 } 3443 break; 3444 case CMD_ADD_OR_UPDATE_NETWORK: 3445 config = (WifiConfiguration) message.obj; 3446 replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, 3447 mWifiConfigStore.addOrUpdateNetwork(config)); 3448 break; 3449 case CMD_REMOVE_NETWORK: 3450 ok = mWifiConfigStore.removeNetwork(message.arg1); 3451 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 3452 break; 3453 case CMD_ENABLE_NETWORK: 3454 ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); 3455 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 3456 break; 3457 case CMD_ENABLE_ALL_NETWORKS: 3458 long time = android.os.SystemClock.elapsedRealtime(); 3459 if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { 3460 mWifiConfigStore.enableAllNetworks(); 3461 mLastEnableAllNetworksTime = time; 3462 } 3463 break; 3464 case WifiManager.DISABLE_NETWORK: 3465 if (mWifiConfigStore.disableNetwork(message.arg1, 3466 WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) { 3467 replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); 3468 } else { 3469 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 3470 WifiManager.ERROR); 3471 } 3472 break; 3473 case CMD_BLACKLIST_NETWORK: 3474 mWifiNative.addToBlacklist((String)message.obj); 3475 break; 3476 case CMD_CLEAR_BLACKLIST: 3477 mWifiNative.clearBlacklist(); 3478 break; 3479 case CMD_SAVE_CONFIG: 3480 ok = mWifiConfigStore.saveConfig(); 3481 replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); 3482 3483 // Inform the backup manager about a data change 3484 IBackupManager ibm = IBackupManager.Stub.asInterface( 3485 ServiceManager.getService(Context.BACKUP_SERVICE)); 3486 if (ibm != null) { 3487 try { 3488 ibm.dataChanged("com.android.providers.settings"); 3489 } catch (Exception e) { 3490 // Try again later 3491 } 3492 } 3493 break; 3494 case CMD_GET_CONFIGURED_NETWORKS: 3495 replyToMessage(message, message.what, 3496 mWifiConfigStore.getConfiguredNetworks()); 3497 break; 3498 /* Do a redundant disconnect without transition */ 3499 case CMD_DISCONNECT: 3500 mWifiNative.disconnect(); 3501 break; 3502 case CMD_RECONNECT: 3503 mWifiNative.reconnect(); 3504 break; 3505 case CMD_REASSOCIATE: 3506 mWifiNative.reassociate(); 3507 break; 3508 case CMD_RELOAD_TLS_AND_RECONNECT: 3509 if (mWifiConfigStore.needsUnlockedKeyStore()) { 3510 logd("Reconnecting to give a chance to un-connected TLS networks"); 3511 mWifiNative.disconnect(); 3512 mWifiNative.reconnect(); 3513 } 3514 break; 3515 case WifiManager.CONNECT_NETWORK: 3516 /* The connect message can contain a network id passed as arg1 on message or 3517 * or a config passed as obj on message. 3518 * For a new network, a config is passed to create and connect. 3519 * For an existing network, a network id is passed 3520 */ 3521 int netId = message.arg1; 3522 config = (WifiConfiguration) message.obj; 3523 3524 /* Save the network config */ 3525 if (config != null) { 3526 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 3527 netId = result.getNetworkId(); 3528 } 3529 3530 if (mWifiConfigStore.selectNetwork(netId) && 3531 mWifiNative.reconnect()) { 3532 /* The state tracker handles enabling networks upon completion/failure */ 3533 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 3534 replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 3535 /* Expect a disconnection from the old connection */ 3536 transitionTo(mDisconnectingState); 3537 } else { 3538 loge("Failed to connect config: " + config + " netId: " + netId); 3539 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 3540 WifiManager.ERROR); 3541 break; 3542 } 3543 break; 3544 case WifiManager.SAVE_NETWORK: 3545 config = (WifiConfiguration) message.obj; 3546 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 3547 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 3548 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 3549 } else { 3550 loge("Failed to save network"); 3551 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 3552 WifiManager.ERROR); 3553 } 3554 break; 3555 case WifiManager.FORGET_NETWORK: 3556 if (mWifiConfigStore.forgetNetwork(message.arg1)) { 3557 replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); 3558 } else { 3559 loge("Failed to forget network"); 3560 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 3561 WifiManager.ERROR); 3562 } 3563 break; 3564 case WifiManager.START_WPS: 3565 WpsInfo wpsInfo = (WpsInfo) message.obj; 3566 WpsResult wpsResult; 3567 switch (wpsInfo.setup) { 3568 case WpsInfo.PBC: 3569 wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo); 3570 break; 3571 case WpsInfo.KEYPAD: 3572 wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); 3573 break; 3574 case WpsInfo.DISPLAY: 3575 wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); 3576 break; 3577 default: 3578 wpsResult = new WpsResult(Status.FAILURE); 3579 loge("Invalid setup for WPS"); 3580 break; 3581 } 3582 if (wpsResult.status == Status.SUCCESS) { 3583 replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult); 3584 transitionTo(mWpsRunningState); 3585 } else { 3586 loge("Failed to start WPS with config " + wpsInfo.toString()); 3587 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR); 3588 } 3589 break; 3590 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3591 if (DBG) log("Network connection established"); 3592 mLastNetworkId = message.arg1; 3593 mLastBssid = (String) message.obj; 3594 3595 mWifiInfo.setBSSID(mLastBssid); 3596 mWifiInfo.setNetworkId(mLastNetworkId); 3597 /* send event to CM & network change broadcast */ 3598 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 3599 sendNetworkStateChangeBroadcast(mLastBssid); 3600 transitionTo(mObtainingIpState); 3601 break; 3602 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 3603 if (DBG) log("Network connection lost"); 3604 handleNetworkDisconnect(); 3605 transitionTo(mDisconnectedState); 3606 break; 3607 default: 3608 return NOT_HANDLED; 3609 } 3610 return HANDLED; 3611 } 3612 } 3613 3614 class L2ConnectedState extends State { 3615 @Override 3616 public void enter() { 3617 mRssiPollToken++; 3618 if (mEnableRssiPolling) { 3619 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0); 3620 } 3621 } 3622 3623 @Override 3624 public void exit() { 3625 handleNetworkDisconnect(); 3626 } 3627 3628 @Override 3629 public boolean processMessage(Message message) { 3630 switch (message.what) { 3631 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 3632 handlePreDhcpSetup(); 3633 break; 3634 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 3635 handlePostDhcpSetup(); 3636 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 3637 if (DBG) log("DHCP successful"); 3638 handleSuccessfulIpConfiguration((DhcpResults) message.obj); 3639 transitionTo(mVerifyingLinkState); 3640 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { 3641 if (DBG) log("DHCP failed"); 3642 handleFailedIpConfiguration(); 3643 transitionTo(mDisconnectingState); 3644 } 3645 break; 3646 case CMD_DISCONNECT: 3647 mWifiNative.disconnect(); 3648 transitionTo(mDisconnectingState); 3649 break; 3650 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 3651 if (message.arg1 == 1) { 3652 mWifiNative.disconnect(); 3653 mTemporarilyDisconnectWifi = true; 3654 transitionTo(mDisconnectingState); 3655 } 3656 break; 3657 case CMD_SET_OPERATIONAL_MODE: 3658 if (message.arg1 != CONNECT_MODE) { 3659 sendMessage(CMD_DISCONNECT); 3660 deferMessage(message); 3661 } 3662 break; 3663 case CMD_START_SCAN: 3664 /* Do not attempt to connect when we are already connected */ 3665 noteScanStart(message.arg1, (WorkSource) message.obj); 3666 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP); 3667 break; 3668 /* Ignore connection to same network */ 3669 case WifiManager.CONNECT_NETWORK: 3670 int netId = message.arg1; 3671 if (mWifiInfo.getNetworkId() == netId) { 3672 break; 3673 } 3674 return NOT_HANDLED; 3675 case WifiManager.SAVE_NETWORK: 3676 WifiConfiguration config = (WifiConfiguration) message.obj; 3677 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 3678 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 3679 if (result.hasIpChanged()) { 3680 log("Reconfiguring IP on connection"); 3681 transitionTo(mObtainingIpState); 3682 } 3683 if (result.hasProxyChanged()) { 3684 log("Reconfiguring proxy on connection"); 3685 updateLinkProperties(); 3686 } 3687 } 3688 3689 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 3690 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 3691 } else { 3692 loge("Failed to save network"); 3693 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 3694 WifiManager.ERROR); 3695 } 3696 break; 3697 /* Ignore */ 3698 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3699 break; 3700 case CMD_RSSI_POLL: 3701 if (message.arg1 == mRssiPollToken) { 3702 // Get Info and continue polling 3703 fetchRssiAndLinkSpeedNative(); 3704 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 3705 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 3706 } else { 3707 // Polling has completed 3708 } 3709 break; 3710 case CMD_ENABLE_RSSI_POLL: 3711 mEnableRssiPolling = (message.arg1 == 1); 3712 mRssiPollToken++; 3713 if (mEnableRssiPolling) { 3714 // first poll 3715 fetchRssiAndLinkSpeedNative(); 3716 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 3717 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 3718 } 3719 break; 3720 case WifiManager.RSSI_PKTCNT_FETCH: 3721 RssiPacketCountInfo info = new RssiPacketCountInfo(); 3722 fetchRssiAndLinkSpeedNative(); 3723 info.rssi = mWifiInfo.getRssi(); 3724 fetchPktcntNative(info); 3725 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info); 3726 break; 3727 default: 3728 return NOT_HANDLED; 3729 } 3730 3731 return HANDLED; 3732 } 3733 } 3734 3735 class ObtainingIpState extends State { 3736 @Override 3737 public void enter() { 3738 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 3739 // TODO: If we're switching between static IP configuration and DHCP, remove the 3740 // static configuration first. 3741 startDhcp(); 3742 } else { 3743 // stop any running dhcp before assigning static IP 3744 stopDhcp(); 3745 DhcpResults dhcpResults = new DhcpResults( 3746 mWifiConfigStore.getLinkProperties(mLastNetworkId)); 3747 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 3748 Iterator<LinkAddress> addrs = 3749 dhcpResults.linkProperties.getLinkAddresses().iterator(); 3750 if (!addrs.hasNext()) { 3751 loge("Static IP lacks address"); 3752 sendMessage(CMD_STATIC_IP_FAILURE); 3753 } else { 3754 ifcg.setLinkAddress(addrs.next()); 3755 ifcg.setInterfaceUp(); 3756 try { 3757 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 3758 if (DBG) log("Static IP configuration succeeded"); 3759 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults); 3760 } catch (RemoteException re) { 3761 loge("Static IP configuration failed: " + re); 3762 sendMessage(CMD_STATIC_IP_FAILURE); 3763 } catch (IllegalStateException e) { 3764 loge("Static IP configuration failed: " + e); 3765 sendMessage(CMD_STATIC_IP_FAILURE); 3766 } 3767 } 3768 } 3769 } 3770 @Override 3771 public boolean processMessage(Message message) { 3772 if (DBG) log(getName() + message.toString() + "\n"); 3773 switch(message.what) { 3774 case CMD_STATIC_IP_SUCCESS: 3775 handleSuccessfulIpConfiguration((DhcpResults) message.obj); 3776 transitionTo(mVerifyingLinkState); 3777 break; 3778 case CMD_STATIC_IP_FAILURE: 3779 handleFailedIpConfiguration(); 3780 transitionTo(mDisconnectingState); 3781 break; 3782 case WifiManager.SAVE_NETWORK: 3783 deferMessage(message); 3784 break; 3785 /* Defer any power mode changes since we must keep active power mode at DHCP */ 3786 case CMD_SET_HIGH_PERF_MODE: 3787 deferMessage(message); 3788 break; 3789 /* Defer scan request since we should not switch to other channels at DHCP */ 3790 case CMD_START_SCAN: 3791 deferMessage(message); 3792 break; 3793 default: 3794 return NOT_HANDLED; 3795 } 3796 return HANDLED; 3797 } 3798 } 3799 3800 class VerifyingLinkState extends State { 3801 @Override 3802 public void enter() { 3803 log(getName() + " enter"); 3804 setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); 3805 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); 3806 sendNetworkStateChangeBroadcast(mLastBssid); 3807 } 3808 @Override 3809 public boolean processMessage(Message message) { 3810 switch (message.what) { 3811 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 3812 //stay here 3813 log(getName() + " POOR_LINK_DETECTED: no transition"); 3814 break; 3815 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 3816 log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); 3817 // Send out a broadcast with the CAPTIVE_PORTAL_CHECK to preserve 3818 // existing behaviour. The captive portal check really happens after we 3819 // transition into DetailedState.CONNECTED. 3820 setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); 3821 mWifiConfigStore.updateStatus(mLastNetworkId, 3822 DetailedState.CAPTIVE_PORTAL_CHECK); 3823 sendNetworkStateChangeBroadcast(mLastBssid); 3824 3825 // NOTE: This might look like an odd place to enable IPV6 but this is in 3826 // response to transitioning into GOOD_LINK_DETECTED. Similarly, we disable 3827 // ipv6 when we transition into POOR_LINK_DETECTED in mConnectedState. 3828 try { 3829 mNwService.enableIpv6(mInterfaceName); 3830 } catch (RemoteException re) { 3831 loge("Failed to enable IPv6: " + re); 3832 } catch (IllegalStateException e) { 3833 loge("Failed to enable IPv6: " + e); 3834 } 3835 3836 log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED"); 3837 setNetworkDetailedState(DetailedState.CONNECTED); 3838 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); 3839 sendNetworkStateChangeBroadcast(mLastBssid); 3840 transitionTo(mConnectedState); 3841 3842 break; 3843 default: 3844 if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); 3845 return NOT_HANDLED; 3846 } 3847 return HANDLED; 3848 } 3849 } 3850 3851 class ConnectedState extends State { 3852 @Override 3853 public boolean processMessage(Message message) { 3854 switch (message.what) { 3855 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 3856 if (DBG) log("Watchdog reports poor link"); 3857 try { 3858 mNwService.disableIpv6(mInterfaceName); 3859 } catch (RemoteException re) { 3860 loge("Failed to disable IPv6: " + re); 3861 } catch (IllegalStateException e) { 3862 loge("Failed to disable IPv6: " + e); 3863 } 3864 /* Report a disconnect */ 3865 setNetworkDetailedState(DetailedState.DISCONNECTED); 3866 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 3867 sendNetworkStateChangeBroadcast(mLastBssid); 3868 3869 transitionTo(mVerifyingLinkState); 3870 break; 3871 default: 3872 return NOT_HANDLED; 3873 } 3874 return HANDLED; 3875 } 3876 3877 @Override 3878 public void exit() { 3879 /* Request a CS wakelock during transition to mobile */ 3880 checkAndSetConnectivityInstance(); 3881 mCm.requestNetworkTransitionWakelock(getName()); 3882 } 3883 } 3884 3885 class DisconnectingState extends State { 3886 @Override 3887 public boolean processMessage(Message message) { 3888 switch (message.what) { 3889 case CMD_SET_OPERATIONAL_MODE: 3890 if (message.arg1 != CONNECT_MODE) { 3891 deferMessage(message); 3892 } 3893 break; 3894 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3895 /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT 3896 * we have missed the network disconnection, transition to mDisconnectedState 3897 * and handle the rest of the events there 3898 */ 3899 deferMessage(message); 3900 handleNetworkDisconnect(); 3901 transitionTo(mDisconnectedState); 3902 break; 3903 default: 3904 return NOT_HANDLED; 3905 } 3906 return HANDLED; 3907 } 3908 } 3909 3910 class DisconnectedState extends State { 3911 private boolean mAlarmEnabled = false; 3912 /* This is set from the overlay config file or from a secure setting. 3913 * A value of 0 disables scanning in the framework. 3914 */ 3915 private long mFrameworkScanIntervalMs; 3916 3917 private void setScanAlarm(boolean enabled) { 3918 if (enabled == mAlarmEnabled) return; 3919 if (enabled) { 3920 if (mFrameworkScanIntervalMs > 0) { 3921 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 3922 System.currentTimeMillis() + mFrameworkScanIntervalMs, 3923 mFrameworkScanIntervalMs, 3924 mScanIntent); 3925 mAlarmEnabled = true; 3926 } 3927 } else { 3928 mAlarmManager.cancel(mScanIntent); 3929 mAlarmEnabled = false; 3930 } 3931 } 3932 3933 @Override 3934 public void enter() { 3935 // We dont scan frequently if this is a temporary disconnect 3936 // due to p2p 3937 if (mTemporarilyDisconnectWifi) { 3938 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 3939 return; 3940 } 3941 3942 mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 3943 Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS, 3944 mDefaultFrameworkScanIntervalMs); 3945 /* 3946 * We initiate background scanning if it is enabled, otherwise we 3947 * initiate an infrequent scan that wakes up the device to ensure 3948 * a user connects to an access point on the move 3949 */ 3950 if (mEnableBackgroundScan) { 3951 /* If a regular scan result is pending, do not initiate background 3952 * scan until the scan results are returned. This is needed because 3953 * initiating a background scan will cancel the regular scan and 3954 * scan results will not be returned until background scanning is 3955 * cleared 3956 */ 3957 if (!mScanResultIsPending) { 3958 mWifiNative.enableBackgroundScan(true); 3959 } 3960 } else { 3961 setScanAlarm(true); 3962 } 3963 3964 /** 3965 * If we have no networks saved, the supplicant stops doing the periodic scan. 3966 * The scans are useful to notify the user of the presence of an open network. 3967 * Note that these are not wake up scans. 3968 */ 3969 if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) { 3970 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 3971 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 3972 } 3973 } 3974 @Override 3975 public boolean processMessage(Message message) { 3976 boolean ret = HANDLED; 3977 switch (message.what) { 3978 case CMD_NO_NETWORKS_PERIODIC_SCAN: 3979 if (mP2pConnected.get()) break; 3980 if (message.arg1 == mPeriodicScanToken && 3981 mWifiConfigStore.getConfiguredNetworks().size() == 0) { 3982 sendMessage(CMD_START_SCAN, UNKNOWN_SCAN_SOURCE, 0, (WorkSource) null); 3983 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 3984 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 3985 } 3986 break; 3987 case WifiManager.FORGET_NETWORK: 3988 case CMD_REMOVE_NETWORK: 3989 // Set up a delayed message here. After the forget/remove is handled 3990 // the handled delayed message will determine if there is a need to 3991 // scan and continue 3992 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 3993 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 3994 ret = NOT_HANDLED; 3995 break; 3996 case CMD_SET_OPERATIONAL_MODE: 3997 if (message.arg1 != CONNECT_MODE) { 3998 mOperationalMode = message.arg1; 3999 4000 mWifiConfigStore.disableAllNetworks(); 4001 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 4002 mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); 4003 setWifiState(WIFI_STATE_DISABLED); 4004 } 4005 4006 transitionTo(mScanModeState); 4007 } 4008 break; 4009 case CMD_ENABLE_BACKGROUND_SCAN: 4010 mEnableBackgroundScan = (message.arg1 == 1); 4011 if (mEnableBackgroundScan) { 4012 mWifiNative.enableBackgroundScan(true); 4013 setScanAlarm(false); 4014 } else { 4015 mWifiNative.enableBackgroundScan(false); 4016 setScanAlarm(true); 4017 } 4018 break; 4019 /* Ignore network disconnect */ 4020 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 4021 break; 4022 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4023 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 4024 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 4025 /* ConnectModeState does the rest of the handling */ 4026 ret = NOT_HANDLED; 4027 break; 4028 case CMD_START_SCAN: 4029 /* Disable background scan temporarily during a regular scan */ 4030 if (mEnableBackgroundScan) { 4031 mWifiNative.enableBackgroundScan(false); 4032 } 4033 /* Handled in parent state */ 4034 ret = NOT_HANDLED; 4035 break; 4036 case WifiMonitor.SCAN_RESULTS_EVENT: 4037 /* Re-enable background scan when a pending scan result is received */ 4038 if (mEnableBackgroundScan && mScanResultIsPending) { 4039 mWifiNative.enableBackgroundScan(true); 4040 } 4041 /* Handled in parent state */ 4042 ret = NOT_HANDLED; 4043 break; 4044 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 4045 NetworkInfo info = (NetworkInfo) message.obj; 4046 mP2pConnected.set(info.isConnected()); 4047 if (mP2pConnected.get()) { 4048 int defaultInterval = mContext.getResources().getInteger( 4049 R.integer.config_wifi_scan_interval_p2p_connected); 4050 long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 4051 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 4052 defaultInterval); 4053 mWifiNative.setScanInterval((int) scanIntervalMs/1000); 4054 } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { 4055 if (DBG) log("Turn on scanning after p2p disconnected"); 4056 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 4057 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 4058 } 4059 case CMD_RECONNECT: 4060 case CMD_REASSOCIATE: 4061 if (mTemporarilyDisconnectWifi) { 4062 // Drop a third party reconnect/reassociate if STA is 4063 // temporarily disconnected for p2p 4064 break; 4065 } else { 4066 // ConnectModeState handles it 4067 ret = NOT_HANDLED; 4068 } 4069 break; 4070 default: 4071 ret = NOT_HANDLED; 4072 } 4073 return ret; 4074 } 4075 4076 @Override 4077 public void exit() { 4078 /* No need for a background scan upon exit from a disconnected state */ 4079 if (mEnableBackgroundScan) { 4080 mWifiNative.enableBackgroundScan(false); 4081 } 4082 setScanAlarm(false); 4083 } 4084 } 4085 4086 class WpsRunningState extends State { 4087 //Tracks the source to provide a reply 4088 private Message mSourceMessage; 4089 @Override 4090 public void enter() { 4091 mSourceMessage = Message.obtain(getCurrentMessage()); 4092 } 4093 @Override 4094 public boolean processMessage(Message message) { 4095 switch (message.what) { 4096 case WifiMonitor.WPS_SUCCESS_EVENT: 4097 // Ignore intermediate success, wait for full connection 4098 break; 4099 case WifiMonitor.NETWORK_CONNECTION_EVENT: 4100 replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED); 4101 mSourceMessage.recycle(); 4102 mSourceMessage = null; 4103 deferMessage(message); 4104 transitionTo(mDisconnectedState); 4105 break; 4106 case WifiMonitor.WPS_OVERLAP_EVENT: 4107 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 4108 WifiManager.WPS_OVERLAP_ERROR); 4109 mSourceMessage.recycle(); 4110 mSourceMessage = null; 4111 transitionTo(mDisconnectedState); 4112 break; 4113 case WifiMonitor.WPS_FAIL_EVENT: 4114 //arg1 has the reason for the failure 4115 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1); 4116 mSourceMessage.recycle(); 4117 mSourceMessage = null; 4118 transitionTo(mDisconnectedState); 4119 break; 4120 case WifiMonitor.WPS_TIMEOUT_EVENT: 4121 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 4122 WifiManager.WPS_TIMED_OUT); 4123 mSourceMessage.recycle(); 4124 mSourceMessage = null; 4125 transitionTo(mDisconnectedState); 4126 break; 4127 case WifiManager.START_WPS: 4128 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS); 4129 break; 4130 case WifiManager.CANCEL_WPS: 4131 if (mWifiNative.cancelWps()) { 4132 replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED); 4133 } else { 4134 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR); 4135 } 4136 transitionTo(mDisconnectedState); 4137 break; 4138 /* Defer all commands that can cause connections to a different network 4139 * or put the state machine out of connect mode 4140 */ 4141 case CMD_STOP_DRIVER: 4142 case CMD_SET_OPERATIONAL_MODE: 4143 case WifiManager.CONNECT_NETWORK: 4144 case CMD_ENABLE_NETWORK: 4145 case CMD_RECONNECT: 4146 case CMD_REASSOCIATE: 4147 deferMessage(message); 4148 break; 4149 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 4150 if (DBG) log("Network connection lost"); 4151 handleNetworkDisconnect(); 4152 break; 4153 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 4154 if (DBG) log("Ignore Assoc reject event during WPS Connection"); 4155 break; 4156 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 4157 // Disregard auth failure events during WPS connection. The 4158 // EAP sequence is retried several times, and there might be 4159 // failures (especially for wps pin). We will get a WPS_XXX 4160 // event at the end of the sequence anyway. 4161 if (DBG) log("Ignore auth failure during WPS connection"); 4162 break; 4163 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4164 //Throw away supplicant state changes when WPS is running. 4165 //We will start getting supplicant state changes once we get 4166 //a WPS success or failure 4167 break; 4168 default: 4169 return NOT_HANDLED; 4170 } 4171 return HANDLED; 4172 } 4173 4174 @Override 4175 public void exit() { 4176 mWifiConfigStore.enableAllNetworks(); 4177 mWifiConfigStore.loadConfiguredNetworks(); 4178 } 4179 } 4180 4181 class SoftApStartingState extends State { 4182 @Override 4183 public void enter() { 4184 final Message message = getCurrentMessage(); 4185 if (message.what == CMD_START_AP) { 4186 final WifiConfiguration config = (WifiConfiguration) message.obj; 4187 4188 if (config == null) { 4189 mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); 4190 } else { 4191 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 4192 startSoftApWithConfig(config); 4193 } 4194 } else { 4195 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); 4196 } 4197 } 4198 @Override 4199 public boolean processMessage(Message message) { 4200 switch(message.what) { 4201 case CMD_START_SUPPLICANT: 4202 case CMD_STOP_SUPPLICANT: 4203 case CMD_START_AP: 4204 case CMD_STOP_AP: 4205 case CMD_START_DRIVER: 4206 case CMD_STOP_DRIVER: 4207 case CMD_SET_OPERATIONAL_MODE: 4208 case CMD_SET_COUNTRY_CODE: 4209 case CMD_SET_FREQUENCY_BAND: 4210 case CMD_START_PACKET_FILTERING: 4211 case CMD_STOP_PACKET_FILTERING: 4212 case CMD_TETHER_STATE_CHANGE: 4213 deferMessage(message); 4214 break; 4215 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: 4216 WifiConfiguration config = (WifiConfiguration) message.obj; 4217 if (config != null) { 4218 startSoftApWithConfig(config); 4219 } else { 4220 loge("Softap config is null!"); 4221 sendMessage(CMD_START_AP_FAILURE); 4222 } 4223 break; 4224 case CMD_START_AP_SUCCESS: 4225 setWifiApState(WIFI_AP_STATE_ENABLED); 4226 transitionTo(mSoftApStartedState); 4227 break; 4228 case CMD_START_AP_FAILURE: 4229 setWifiApState(WIFI_AP_STATE_FAILED); 4230 transitionTo(mInitialState); 4231 break; 4232 default: 4233 return NOT_HANDLED; 4234 } 4235 return HANDLED; 4236 } 4237 } 4238 4239 class SoftApStartedState extends State { 4240 @Override 4241 public boolean processMessage(Message message) { 4242 switch(message.what) { 4243 case CMD_STOP_AP: 4244 if (DBG) log("Stopping Soft AP"); 4245 /* We have not tethered at this point, so we just shutdown soft Ap */ 4246 try { 4247 mNwService.stopAccessPoint(mInterfaceName); 4248 } catch(Exception e) { 4249 loge("Exception in stopAccessPoint()"); 4250 } 4251 setWifiApState(WIFI_AP_STATE_DISABLED); 4252 transitionTo(mInitialState); 4253 break; 4254 case CMD_START_AP: 4255 // Ignore a start on a running access point 4256 break; 4257 /* Fail client mode operation when soft AP is enabled */ 4258 case CMD_START_SUPPLICANT: 4259 loge("Cannot start supplicant with a running soft AP"); 4260 setWifiState(WIFI_STATE_UNKNOWN); 4261 break; 4262 case CMD_TETHER_STATE_CHANGE: 4263 TetherStateChange stateChange = (TetherStateChange) message.obj; 4264 if (startTethering(stateChange.available)) { 4265 transitionTo(mTetheringState); 4266 } 4267 break; 4268 default: 4269 return NOT_HANDLED; 4270 } 4271 return HANDLED; 4272 } 4273 } 4274 4275 class TetheringState extends State { 4276 @Override 4277 public void enter() { 4278 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 4279 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 4280 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 4281 } 4282 @Override 4283 public boolean processMessage(Message message) { 4284 switch(message.what) { 4285 case CMD_TETHER_STATE_CHANGE: 4286 TetherStateChange stateChange = (TetherStateChange) message.obj; 4287 if (isWifiTethered(stateChange.active)) { 4288 transitionTo(mTetheredState); 4289 } 4290 return HANDLED; 4291 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 4292 if (message.arg1 == mTetherToken) { 4293 loge("Failed to get tether update, shutdown soft access point"); 4294 transitionTo(mSoftApStartedState); 4295 // Needs to be first thing handled 4296 sendMessageAtFrontOfQueue(CMD_STOP_AP); 4297 } 4298 break; 4299 case CMD_START_SUPPLICANT: 4300 case CMD_STOP_SUPPLICANT: 4301 case CMD_START_AP: 4302 case CMD_STOP_AP: 4303 case CMD_START_DRIVER: 4304 case CMD_STOP_DRIVER: 4305 case CMD_SET_OPERATIONAL_MODE: 4306 case CMD_SET_COUNTRY_CODE: 4307 case CMD_SET_FREQUENCY_BAND: 4308 case CMD_START_PACKET_FILTERING: 4309 case CMD_STOP_PACKET_FILTERING: 4310 deferMessage(message); 4311 break; 4312 default: 4313 return NOT_HANDLED; 4314 } 4315 return HANDLED; 4316 } 4317 } 4318 4319 class TetheredState extends State { 4320 @Override 4321 public boolean processMessage(Message message) { 4322 switch(message.what) { 4323 case CMD_TETHER_STATE_CHANGE: 4324 TetherStateChange stateChange = (TetherStateChange) message.obj; 4325 if (!isWifiTethered(stateChange.active)) { 4326 loge("Tethering reports wifi as untethered!, shut down soft Ap"); 4327 setHostApRunning(null, false); 4328 setHostApRunning(null, true); 4329 } 4330 return HANDLED; 4331 case CMD_STOP_AP: 4332 if (DBG) log("Untethering before stopping AP"); 4333 setWifiApState(WIFI_AP_STATE_DISABLING); 4334 stopTethering(); 4335 transitionTo(mUntetheringState); 4336 // More work to do after untethering 4337 deferMessage(message); 4338 break; 4339 default: 4340 return NOT_HANDLED; 4341 } 4342 return HANDLED; 4343 } 4344 } 4345 4346 class UntetheringState extends State { 4347 @Override 4348 public void enter() { 4349 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 4350 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 4351 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 4352 4353 } 4354 @Override 4355 public boolean processMessage(Message message) { 4356 switch(message.what) { 4357 case CMD_TETHER_STATE_CHANGE: 4358 TetherStateChange stateChange = (TetherStateChange) message.obj; 4359 4360 /* Wait till wifi is untethered */ 4361 if (isWifiTethered(stateChange.active)) break; 4362 4363 transitionTo(mSoftApStartedState); 4364 break; 4365 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 4366 if (message.arg1 == mTetherToken) { 4367 loge("Failed to get tether update, force stop access point"); 4368 transitionTo(mSoftApStartedState); 4369 } 4370 break; 4371 case CMD_START_SUPPLICANT: 4372 case CMD_STOP_SUPPLICANT: 4373 case CMD_START_AP: 4374 case CMD_STOP_AP: 4375 case CMD_START_DRIVER: 4376 case CMD_STOP_DRIVER: 4377 case CMD_SET_OPERATIONAL_MODE: 4378 case CMD_SET_COUNTRY_CODE: 4379 case CMD_SET_FREQUENCY_BAND: 4380 case CMD_START_PACKET_FILTERING: 4381 case CMD_STOP_PACKET_FILTERING: 4382 deferMessage(message); 4383 break; 4384 default: 4385 return NOT_HANDLED; 4386 } 4387 return HANDLED; 4388 } 4389 } 4390 4391 //State machine initiated requests can have replyTo set to null indicating 4392 //there are no recepients, we ignore those reply actions 4393 private void replyToMessage(Message msg, int what) { 4394 if (msg.replyTo == null) return; 4395 Message dstMsg = obtainMessageWithArg2(msg); 4396 dstMsg.what = what; 4397 mReplyChannel.replyToMessage(msg, dstMsg); 4398 } 4399 4400 private void replyToMessage(Message msg, int what, int arg1) { 4401 if (msg.replyTo == null) return; 4402 Message dstMsg = obtainMessageWithArg2(msg); 4403 dstMsg.what = what; 4404 dstMsg.arg1 = arg1; 4405 mReplyChannel.replyToMessage(msg, dstMsg); 4406 } 4407 4408 private void replyToMessage(Message msg, int what, Object obj) { 4409 if (msg.replyTo == null) return; 4410 Message dstMsg = obtainMessageWithArg2(msg); 4411 dstMsg.what = what; 4412 dstMsg.obj = obj; 4413 mReplyChannel.replyToMessage(msg, dstMsg); 4414 } 4415 4416 /** 4417 * arg2 on the source message has a unique id that needs to be retained in replies 4418 * to match the request 4419 4420 * see WifiManager for details 4421 */ 4422 private Message obtainMessageWithArg2(Message srcMsg) { 4423 Message msg = Message.obtain(); 4424 msg.arg2 = srcMsg.arg2; 4425 return msg; 4426 } 4427} 4428