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