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