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