WifiStateMachine.java revision 3fb4ba616edb114b3197936eb67f481eb86b7cae
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 return mScanResults; 895 } 896 897 /** 898 * Disconnect from Access Point 899 */ 900 public void disconnectCommand() { 901 sendMessage(CMD_DISCONNECT); 902 } 903 904 /** 905 * Initiate a reconnection to AP 906 */ 907 public void reconnectCommand() { 908 sendMessage(CMD_RECONNECT); 909 } 910 911 /** 912 * Initiate a re-association to AP 913 */ 914 public void reassociateCommand() { 915 sendMessage(CMD_REASSOCIATE); 916 } 917 918 /** 919 * Add a network synchronously 920 * 921 * @return network id of the new network 922 */ 923 public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) { 924 Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config); 925 int result = resultMsg.arg1; 926 resultMsg.recycle(); 927 return result; 928 } 929 930 public List<WifiConfiguration> syncGetConfiguredNetworks(AsyncChannel channel) { 931 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS); 932 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 933 resultMsg.recycle(); 934 return result; 935 } 936 937 /** 938 * Delete a network 939 * 940 * @param networkId id of the network to be removed 941 */ 942 public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) { 943 Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId); 944 boolean result = (resultMsg.arg1 != FAILURE); 945 resultMsg.recycle(); 946 return result; 947 } 948 949 /** 950 * Enable a network 951 * 952 * @param netId network id of the network 953 * @param disableOthers true, if all other networks have to be disabled 954 * @return {@code true} if the operation succeeds, {@code false} otherwise 955 */ 956 public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) { 957 Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId, 958 disableOthers ? 1 : 0); 959 boolean result = (resultMsg.arg1 != FAILURE); 960 resultMsg.recycle(); 961 return result; 962 } 963 964 /** 965 * Disable a network 966 * 967 * @param netId network id of the network 968 * @return {@code true} if the operation succeeds, {@code false} otherwise 969 */ 970 public boolean syncDisableNetwork(AsyncChannel channel, int netId) { 971 Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId); 972 boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED); 973 resultMsg.recycle(); 974 return result; 975 } 976 977 /** 978 * Blacklist a BSSID. This will avoid the AP if there are 979 * alternate APs to connect 980 * 981 * @param bssid BSSID of the network 982 */ 983 public void addToBlacklist(String bssid) { 984 sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid)); 985 } 986 987 /** 988 * Clear the blacklist list 989 * 990 */ 991 public void clearBlacklist() { 992 sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST)); 993 } 994 995 public void enableRssiPolling(boolean enabled) { 996 sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0)); 997 } 998 999 public void enableBackgroundScanCommand(boolean enabled) { 1000 sendMessage(obtainMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0)); 1001 } 1002 1003 public void enableAllNetworks() { 1004 sendMessage(CMD_ENABLE_ALL_NETWORKS); 1005 } 1006 1007 /** 1008 * Start filtering Multicast v4 packets 1009 */ 1010 public void startFilteringMulticastV4Packets() { 1011 mFilteringMulticastV4Packets.set(true); 1012 sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0)); 1013 } 1014 1015 /** 1016 * Stop filtering Multicast v4 packets 1017 */ 1018 public void stopFilteringMulticastV4Packets() { 1019 mFilteringMulticastV4Packets.set(false); 1020 sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0)); 1021 } 1022 1023 /** 1024 * Start filtering Multicast v4 packets 1025 */ 1026 public void startFilteringMulticastV6Packets() { 1027 sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0)); 1028 } 1029 1030 /** 1031 * Stop filtering Multicast v4 packets 1032 */ 1033 public void stopFilteringMulticastV6Packets() { 1034 sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0)); 1035 } 1036 1037 /** 1038 * Set high performance mode of operation. 1039 * Enabling would set active power mode and disable suspend optimizations; 1040 * disabling would set auto power mode and enable suspend optimizations 1041 * @param enable true if enable, false otherwise 1042 */ 1043 public void setHighPerfModeEnabled(boolean enable) { 1044 sendMessage(obtainMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0)); 1045 } 1046 1047 /** 1048 * Set the country code 1049 * @param countryCode following ISO 3166 format 1050 * @param persist {@code true} if the setting should be remembered. 1051 */ 1052 public void setCountryCode(String countryCode, boolean persist) { 1053 if (persist) { 1054 Settings.Secure.putString(mContext.getContentResolver(), 1055 Settings.Secure.WIFI_COUNTRY_CODE, 1056 countryCode); 1057 } 1058 sendMessage(obtainMessage(CMD_SET_COUNTRY_CODE, countryCode)); 1059 } 1060 1061 /** 1062 * Set the operational frequency band 1063 * @param band 1064 * @param persist {@code true} if the setting should be remembered. 1065 */ 1066 public void setFrequencyBand(int band, boolean persist) { 1067 if (persist) { 1068 Settings.Secure.putInt(mContext.getContentResolver(), 1069 Settings.Secure.WIFI_FREQUENCY_BAND, 1070 band); 1071 } 1072 sendMessage(obtainMessage(CMD_SET_FREQUENCY_BAND, band, 0)); 1073 } 1074 1075 /** 1076 * Returns the operational frequency band 1077 */ 1078 public int getFrequencyBand() { 1079 return mFrequencyBand.get(); 1080 } 1081 1082 /** 1083 * Returns the wifi configuration file 1084 */ 1085 public String getConfigFile() { 1086 return mWifiConfigStore.getConfigFile(); 1087 } 1088 1089 /** 1090 * Send a message indicating bluetooth adapter connection state changed 1091 */ 1092 public void sendBluetoothAdapterStateChange(int state) { 1093 sendMessage(obtainMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0)); 1094 } 1095 1096 /** 1097 * Save configuration on supplicant 1098 * 1099 * @return {@code true} if the operation succeeds, {@code false} otherwise 1100 * 1101 * TODO: deprecate this 1102 */ 1103 public boolean syncSaveConfig(AsyncChannel channel) { 1104 Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG); 1105 boolean result = (resultMsg.arg1 != FAILURE); 1106 resultMsg.recycle(); 1107 return result; 1108 } 1109 1110 public void updateBatteryWorkSource(WorkSource newSource) { 1111 synchronized (mRunningWifiUids) { 1112 try { 1113 if (newSource != null) { 1114 mRunningWifiUids.set(newSource); 1115 } 1116 if (mIsRunning) { 1117 if (mReportedRunning) { 1118 // If the work source has changed since last time, need 1119 // to remove old work from battery stats. 1120 if (mLastRunningWifiUids.diff(mRunningWifiUids)) { 1121 mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids, 1122 mRunningWifiUids); 1123 mLastRunningWifiUids.set(mRunningWifiUids); 1124 } 1125 } else { 1126 // Now being started, report it. 1127 mBatteryStats.noteWifiRunning(mRunningWifiUids); 1128 mLastRunningWifiUids.set(mRunningWifiUids); 1129 mReportedRunning = true; 1130 } 1131 } else { 1132 if (mReportedRunning) { 1133 // Last reported we were running, time to stop. 1134 mBatteryStats.noteWifiStopped(mLastRunningWifiUids); 1135 mLastRunningWifiUids.clear(); 1136 mReportedRunning = false; 1137 } 1138 } 1139 mWakeLock.setWorkSource(newSource); 1140 } catch (RemoteException ignore) { 1141 } 1142 } 1143 } 1144 1145 @Override 1146 public String toString() { 1147 StringBuffer sb = new StringBuffer(); 1148 String LS = System.getProperty("line.separator"); 1149 sb.append("current HSM state: ").append(getCurrentState().getName()).append(LS); 1150 sb.append("mLinkProperties ").append(mLinkProperties).append(LS); 1151 sb.append("mWifiInfo ").append(mWifiInfo).append(LS); 1152 sb.append("mDhcpInfoInternal ").append(mDhcpInfoInternal).append(LS); 1153 sb.append("mNetworkInfo ").append(mNetworkInfo).append(LS); 1154 sb.append("mLastSignalLevel ").append(mLastSignalLevel).append(LS); 1155 sb.append("mLastBssid ").append(mLastBssid).append(LS); 1156 sb.append("mLastNetworkId ").append(mLastNetworkId).append(LS); 1157 sb.append("mReconnectCount ").append(mReconnectCount).append(LS); 1158 sb.append("mIsScanMode ").append(mIsScanMode).append(LS); 1159 sb.append("mHighPerfMode").append(mHighPerfMode).append(LS); 1160 sb.append("mSuspendOptEnabled").append(mSuspendOptEnabled).append(LS); 1161 sb.append("Supplicant status").append(LS) 1162 .append(mWifiNative.status()).append(LS).append(LS); 1163 1164 sb.append(mWifiConfigStore.dump()); 1165 return sb.toString(); 1166 } 1167 1168 @Override 1169 protected boolean recordLogRec(Message msg) { 1170 //Ignore screen on/off & common messages when driver has started 1171 if (getCurrentState() == mConnectedState || getCurrentState() == mDisconnectedState) { 1172 switch (msg.what) { 1173 case CMD_LOAD_DRIVER: 1174 case CMD_START_SUPPLICANT: 1175 case CMD_START_DRIVER: 1176 case CMD_SET_SCAN_MODE: 1177 case CMD_SET_HIGH_PERF_MODE: 1178 case CMD_SET_SUSPEND_OPTIMIZATIONS: 1179 case CMD_CLEAR_SUSPEND_OPTIMIZATIONS: 1180 case CMD_ENABLE_BACKGROUND_SCAN: 1181 case CMD_ENABLE_ALL_NETWORKS: 1182 return false; 1183 } 1184 } 1185 1186 switch (msg.what) { 1187 case CMD_START_SCAN: 1188 case CMD_ENABLE_RSSI_POLL: 1189 case CMD_RSSI_POLL: 1190 case CMD_DELAYED_STOP_DRIVER: 1191 case WifiMonitor.SCAN_RESULTS_EVENT: 1192 case WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH: 1193 return false; 1194 default: 1195 return true; 1196 } 1197 } 1198 1199 /********************************************************* 1200 * Internal private functions 1201 ********************************************************/ 1202 1203 private void checkAndSetConnectivityInstance() { 1204 if (mCm == null) { 1205 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 1206 } 1207 } 1208 1209 private boolean startTethering(ArrayList<String> available) { 1210 1211 boolean wifiAvailable = false; 1212 1213 checkAndSetConnectivityInstance(); 1214 1215 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 1216 1217 for (String intf : available) { 1218 for (String regex : wifiRegexs) { 1219 if (intf.matches(regex)) { 1220 1221 InterfaceConfiguration ifcg = null; 1222 try { 1223 ifcg = mNwService.getInterfaceConfig(intf); 1224 if (ifcg != null) { 1225 /* IP/netmask: 192.168.43.1/255.255.255.0 */ 1226 ifcg.setLinkAddress(new LinkAddress( 1227 NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); 1228 ifcg.setInterfaceUp(); 1229 1230 mNwService.setInterfaceConfig(intf, ifcg); 1231 } 1232 } catch (Exception e) { 1233 loge("Error configuring interface " + intf + ", :" + e); 1234 return false; 1235 } 1236 1237 if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 1238 loge("Error tethering on " + intf); 1239 return false; 1240 } 1241 mTetherInterfaceName = intf; 1242 return true; 1243 } 1244 } 1245 } 1246 // We found no interfaces to tether 1247 return false; 1248 } 1249 1250 private void stopTethering() { 1251 1252 checkAndSetConnectivityInstance(); 1253 1254 /* Clear the interface config to allow dhcp correctly configure new 1255 ip settings */ 1256 InterfaceConfiguration ifcg = null; 1257 try { 1258 ifcg = mNwService.getInterfaceConfig(mInterfaceName); 1259 if (ifcg != null) { 1260 ifcg.setLinkAddress( 1261 new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); 1262 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 1263 } 1264 } catch (Exception e) { 1265 loge("Error resetting interface " + mInterfaceName + ", :" + e); 1266 } 1267 1268 if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 1269 loge("Untether initiate failed!"); 1270 } 1271 } 1272 1273 private boolean isWifiTethered(ArrayList<String> active) { 1274 1275 checkAndSetConnectivityInstance(); 1276 1277 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 1278 for (String intf : active) { 1279 for (String regex : wifiRegexs) { 1280 if (intf.matches(regex)) { 1281 return true; 1282 } 1283 } 1284 } 1285 // We found no interfaces that are tethered 1286 return false; 1287 } 1288 1289 /** 1290 * Set the country code from the system setting value, if any. 1291 */ 1292 private void setCountryCode() { 1293 String countryCode = Settings.Secure.getString(mContext.getContentResolver(), 1294 Settings.Secure.WIFI_COUNTRY_CODE); 1295 if (countryCode != null && !countryCode.isEmpty()) { 1296 setCountryCode(countryCode, false); 1297 } else { 1298 //use driver default 1299 } 1300 } 1301 1302 /** 1303 * Set the frequency band from the system setting value, if any. 1304 */ 1305 private void setFrequencyBand() { 1306 int band = Settings.Secure.getInt(mContext.getContentResolver(), 1307 Settings.Secure.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO); 1308 setFrequencyBand(band, false); 1309 } 1310 1311 private void setWifiState(int wifiState) { 1312 final int previousWifiState = mWifiState.get(); 1313 1314 try { 1315 if (wifiState == WIFI_STATE_ENABLED) { 1316 mBatteryStats.noteWifiOn(); 1317 } else if (wifiState == WIFI_STATE_DISABLED) { 1318 mBatteryStats.noteWifiOff(); 1319 } 1320 } catch (RemoteException e) { 1321 loge("Failed to note battery stats in wifi"); 1322 } 1323 1324 mWifiState.set(wifiState); 1325 1326 if (DBG) log("setWifiState: " + syncGetWifiStateByName()); 1327 1328 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 1329 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1330 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 1331 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 1332 mContext.sendStickyBroadcast(intent); 1333 } 1334 1335 private void setWifiApState(int wifiApState) { 1336 final int previousWifiApState = mWifiApState.get(); 1337 1338 try { 1339 if (wifiApState == WIFI_AP_STATE_ENABLED) { 1340 mBatteryStats.noteWifiOn(); 1341 } else if (wifiApState == WIFI_AP_STATE_DISABLED) { 1342 mBatteryStats.noteWifiOff(); 1343 } 1344 } catch (RemoteException e) { 1345 loge("Failed to note battery stats in wifi"); 1346 } 1347 1348 // Update state 1349 mWifiApState.set(wifiApState); 1350 1351 if (DBG) log("setWifiApState: " + syncGetWifiApStateByName()); 1352 1353 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 1354 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1355 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); 1356 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); 1357 mContext.sendStickyBroadcast(intent); 1358 } 1359 1360 /** 1361 * Parse the scan result line passed to us by wpa_supplicant (helper). 1362 * @param line the line to parse 1363 * @return the {@link ScanResult} object 1364 */ 1365 private ScanResult parseScanResult(String line) { 1366 ScanResult scanResult = null; 1367 if (line != null) { 1368 /* 1369 * Cache implementation (LinkedHashMap) is not synchronized, thus, 1370 * must synchronized here! 1371 */ 1372 synchronized (mScanResultCache) { 1373 String[] result = scanResultPattern.split(line); 1374 if (3 <= result.length && result.length <= 5) { 1375 String bssid = result[0]; 1376 // bssid | frequency | level | flags | ssid 1377 int frequency; 1378 int level; 1379 try { 1380 frequency = Integer.parseInt(result[1]); 1381 level = Integer.parseInt(result[2]); 1382 /* some implementations avoid negative values by adding 256 1383 * so we need to adjust for that here. 1384 */ 1385 if (level > 0) level -= 256; 1386 } catch (NumberFormatException e) { 1387 frequency = 0; 1388 level = 0; 1389 } 1390 1391 /* 1392 * The formatting of the results returned by 1393 * wpa_supplicant is intended to make the fields 1394 * line up nicely when printed, 1395 * not to make them easy to parse. So we have to 1396 * apply some heuristics to figure out which field 1397 * is the SSID and which field is the flags. 1398 */ 1399 String ssid; 1400 String flags; 1401 if (result.length == 4) { 1402 if (result[3].charAt(0) == '[') { 1403 flags = result[3]; 1404 ssid = ""; 1405 } else { 1406 flags = ""; 1407 ssid = result[3]; 1408 } 1409 } else if (result.length == 5) { 1410 flags = result[3]; 1411 ssid = result[4]; 1412 } else { 1413 // Here, we must have 3 fields: no flags and ssid 1414 // set 1415 flags = ""; 1416 ssid = ""; 1417 } 1418 1419 // bssid + ssid is the hash key 1420 String key = bssid + ssid; 1421 scanResult = mScanResultCache.get(key); 1422 if (scanResult != null) { 1423 scanResult.level = level; 1424 scanResult.SSID = ssid; 1425 scanResult.capabilities = flags; 1426 scanResult.frequency = frequency; 1427 } else { 1428 // Do not add scan results that have no SSID set 1429 if (0 < ssid.trim().length()) { 1430 scanResult = 1431 new ScanResult( 1432 ssid, bssid, flags, level, frequency); 1433 mScanResultCache.put(key, scanResult); 1434 } 1435 } 1436 } else { 1437 loge("Misformatted scan result text with " + 1438 result.length + " fields: " + line); 1439 } 1440 } 1441 } 1442 1443 return scanResult; 1444 } 1445 1446 /** 1447 * scanResults input format 1448 * 00:bb:cc:dd:cc:ee 2427 166 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net1 1449 * 00:bb:cc:dd:cc:ff 2412 165 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net2 1450 */ 1451 private void setScanResults(String scanResults) { 1452 if (scanResults == null) { 1453 return; 1454 } 1455 1456 List<ScanResult> scanList = new ArrayList<ScanResult>(); 1457 1458 int lineCount = 0; 1459 1460 int scanResultsLen = scanResults.length(); 1461 // Parse the result string, keeping in mind that the last line does 1462 // not end with a newline. 1463 for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) { 1464 if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') { 1465 ++lineCount; 1466 1467 if (lineCount == 1) { 1468 lineBeg = lineEnd + 1; 1469 continue; 1470 } 1471 if (lineEnd > lineBeg) { 1472 String line = scanResults.substring(lineBeg, lineEnd); 1473 ScanResult scanResult = parseScanResult(line); 1474 if (scanResult != null) { 1475 scanList.add(scanResult); 1476 } else { 1477 //TODO: hidden network handling 1478 } 1479 } 1480 lineBeg = lineEnd + 1; 1481 } 1482 } 1483 1484 mScanResults = scanList; 1485 } 1486 1487 /* 1488 * Fetch RSSI and linkspeed on current connection 1489 */ 1490 private void fetchRssiAndLinkSpeedNative() { 1491 int newRssi = -1; 1492 int newLinkSpeed = -1; 1493 1494 String signalPoll = mWifiNative.signalPoll(); 1495 1496 if (signalPoll != null) { 1497 String[] lines = signalPoll.split("\n"); 1498 for (String line : lines) { 1499 String[] prop = line.split("="); 1500 if (prop.length < 2) continue; 1501 try { 1502 if (prop[0].equals("RSSI")) { 1503 newRssi = Integer.parseInt(prop[1]); 1504 } else if (prop[0].equals("LINKSPEED")) { 1505 newLinkSpeed = Integer.parseInt(prop[1]); 1506 } 1507 } catch (NumberFormatException e) { 1508 //Ignore, defaults on rssi and linkspeed are assigned 1509 } 1510 } 1511 } 1512 1513 if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values 1514 /* some implementations avoid negative values by adding 256 1515 * so we need to adjust for that here. 1516 */ 1517 if (newRssi > 0) newRssi -= 256; 1518 mWifiInfo.setRssi(newRssi); 1519 /* 1520 * Rather then sending the raw RSSI out every time it 1521 * changes, we precalculate the signal level that would 1522 * be displayed in the status bar, and only send the 1523 * broadcast if that much more coarse-grained number 1524 * changes. This cuts down greatly on the number of 1525 * broadcasts, at the cost of not informing others 1526 * interested in RSSI of all the changes in signal 1527 * level. 1528 */ 1529 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); 1530 if (newSignalLevel != mLastSignalLevel) { 1531 sendRssiChangeBroadcast(newRssi); 1532 } 1533 mLastSignalLevel = newSignalLevel; 1534 } else { 1535 mWifiInfo.setRssi(MIN_RSSI); 1536 } 1537 1538 if (newLinkSpeed != -1) { 1539 mWifiInfo.setLinkSpeed(newLinkSpeed); 1540 } 1541 } 1542 1543 /* 1544 * Fetch TX packet counters on current connection 1545 */ 1546 private void fetchPktcntNative(RssiPktcntStat stat) { 1547 String pktcntPoll = mWifiNative.pktcntPoll(); 1548 1549 if (pktcntPoll != null) { 1550 String[] lines = pktcntPoll.split("\n"); 1551 for (String line : lines) { 1552 String[] prop = line.split("="); 1553 if (prop.length < 2) continue; 1554 try { 1555 if (prop[0].equals("TXGOOD")) { 1556 stat.txgood = Integer.parseInt(prop[1]); 1557 } else if (prop[0].equals("TXBAD")) { 1558 stat.txbad = Integer.parseInt(prop[1]); 1559 } 1560 } catch (NumberFormatException e) { 1561 //Ignore 1562 } 1563 } 1564 } 1565 } 1566 1567 private void configureLinkProperties() { 1568 if (mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 1569 mLinkProperties = mWifiConfigStore.getLinkProperties(mLastNetworkId); 1570 } else { 1571 synchronized (mDhcpInfoInternal) { 1572 mLinkProperties = mDhcpInfoInternal.makeLinkProperties(); 1573 } 1574 mLinkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); 1575 } 1576 mLinkProperties.setInterfaceName(mInterfaceName); 1577 if (DBG) { 1578 log("netId=" + mLastNetworkId + " Link configured: " + 1579 mLinkProperties.toString()); 1580 } 1581 } 1582 1583 private int getMaxDhcpRetries() { 1584 return Settings.Secure.getInt(mContext.getContentResolver(), 1585 Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT, 1586 DEFAULT_MAX_DHCP_RETRIES); 1587 } 1588 1589 private void sendScanResultsAvailableBroadcast() { 1590 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 1591 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1592 mContext.sendBroadcast(intent); 1593 } 1594 1595 private void sendRssiChangeBroadcast(final int newRssi) { 1596 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); 1597 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1598 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); 1599 mContext.sendBroadcast(intent); 1600 } 1601 1602 private void sendNetworkStateChangeBroadcast(String bssid) { 1603 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); 1604 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1605 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 1606 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties)); 1607 if (bssid != null) 1608 intent.putExtra(WifiManager.EXTRA_BSSID, bssid); 1609 if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK || 1610 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { 1611 intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo)); 1612 } 1613 mContext.sendStickyBroadcast(intent); 1614 } 1615 1616 private void sendLinkConfigurationChangedBroadcast() { 1617 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); 1618 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1619 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); 1620 mContext.sendBroadcast(intent); 1621 } 1622 1623 private void sendSupplicantConnectionChangedBroadcast(boolean connected) { 1624 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 1625 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1626 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); 1627 mContext.sendBroadcast(intent); 1628 } 1629 1630 /** 1631 * Record the detailed state of a network. 1632 * @param state the new {@code DetailedState} 1633 */ 1634 private void setNetworkDetailedState(NetworkInfo.DetailedState state) { 1635 if (DBG) { 1636 log("setDetailed state, old =" 1637 + mNetworkInfo.getDetailedState() + " and new state=" + state); 1638 } 1639 1640 if (state != mNetworkInfo.getDetailedState()) { 1641 mNetworkInfo.setDetailedState(state, null, null); 1642 } 1643 } 1644 1645 private DetailedState getNetworkDetailedState() { 1646 return mNetworkInfo.getDetailedState(); 1647 } 1648 1649 1650 private SupplicantState handleSupplicantStateChange(Message message) { 1651 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 1652 SupplicantState state = stateChangeResult.state; 1653 // Supplicant state change 1654 // [31-13] Reserved for future use 1655 // [8 - 0] Supplicant state (as defined in SupplicantState.java) 1656 // 50023 supplicant_state_changed (custom|1|5) 1657 EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, state.ordinal()); 1658 mWifiInfo.setSupplicantState(state); 1659 // Network id is only valid when we start connecting 1660 if (SupplicantState.isConnecting(state)) { 1661 mWifiInfo.setNetworkId(stateChangeResult.networkId); 1662 } else { 1663 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 1664 } 1665 1666 mWifiInfo.setBSSID(stateChangeResult.BSSID); 1667 mWifiInfo.setSSID(stateChangeResult.SSID); 1668 1669 mSupplicantStateTracker.sendMessage(Message.obtain(message)); 1670 1671 return state; 1672 } 1673 1674 /** 1675 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 1676 * using the interface, stopping DHCP & disabling interface 1677 */ 1678 private void handleNetworkDisconnect() { 1679 if (DBG) log("Stopping DHCP and clearing IP"); 1680 1681 /* 1682 * stop DHCP 1683 */ 1684 if (mDhcpStateMachine != null) { 1685 /* In case we were in middle of DHCP operation 1686 restore back powermode */ 1687 handlePostDhcpSetup(); 1688 1689 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); 1690 mDhcpStateMachine.doQuit(); 1691 mDhcpStateMachine = null; 1692 } 1693 1694 try { 1695 mNwService.clearInterfaceAddresses(mInterfaceName); 1696 mNwService.disableIpv6(mInterfaceName); 1697 } catch (Exception e) { 1698 loge("Failed to clear addresses or disable ipv6" + e); 1699 } 1700 1701 /* Reset data structures */ 1702 mWifiInfo.setInetAddress(null); 1703 mWifiInfo.setBSSID(null); 1704 mWifiInfo.setSSID(null); 1705 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 1706 mWifiInfo.setRssi(MIN_RSSI); 1707 mWifiInfo.setLinkSpeed(-1); 1708 mWifiInfo.setMeteredHint(false); 1709 1710 setNetworkDetailedState(DetailedState.DISCONNECTED); 1711 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 1712 1713 /* send event to CM & network change broadcast */ 1714 sendNetworkStateChangeBroadcast(mLastBssid); 1715 1716 /* Clear network properties */ 1717 mLinkProperties.clear(); 1718 /* Clear IP settings if the network used DHCP */ 1719 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 1720 mWifiConfigStore.clearIpConfiguration(mLastNetworkId); 1721 } 1722 1723 mLastBssid= null; 1724 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 1725 } 1726 1727 void handlePreDhcpSetup() { 1728 if (!mBluetoothConnectionActive) { 1729 /* 1730 * There are problems setting the Wi-Fi driver's power 1731 * mode to active when bluetooth coexistence mode is 1732 * enabled or sense. 1733 * <p> 1734 * We set Wi-Fi to active mode when 1735 * obtaining an IP address because we've found 1736 * compatibility issues with some routers with low power 1737 * mode. 1738 * <p> 1739 * In order for this active power mode to properly be set, 1740 * we disable coexistence mode until we're done with 1741 * obtaining an IP address. One exception is if we 1742 * are currently connected to a headset, since disabling 1743 * coexistence would interrupt that connection. 1744 */ 1745 // Disable the coexistence mode 1746 mWifiNative.setBluetoothCoexistenceMode( 1747 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); 1748 } 1749 1750 /* Disable power save during DHCP */ 1751 if (mPowerSaveEnabled) { 1752 mPowerSaveEnabled = false; 1753 mWifiNative.setPowerSave(mPowerSaveEnabled); 1754 } 1755 } 1756 1757 1758 void handlePostDhcpSetup() { 1759 /* Restore power save */ 1760 mPowerSaveEnabled = true; 1761 mWifiNative.setPowerSave(mPowerSaveEnabled); 1762 1763 // Set the coexistence mode back to its default value 1764 mWifiNative.setBluetoothCoexistenceMode( 1765 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); 1766 } 1767 1768 private void handleSuccessfulIpConfiguration(DhcpInfoInternal dhcpInfoInternal) { 1769 synchronized (mDhcpInfoInternal) { 1770 mDhcpInfoInternal = dhcpInfoInternal; 1771 } 1772 mLastSignalLevel = -1; // force update of signal strength 1773 mReconnectCount = 0; //Reset IP failure tracking 1774 mWifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal); 1775 InetAddress addr = NetworkUtils.numericToInetAddress(dhcpInfoInternal.ipAddress); 1776 mWifiInfo.setInetAddress(addr); 1777 mWifiInfo.setMeteredHint(dhcpInfoInternal.hasMeteredHint()); 1778 if (getNetworkDetailedState() == DetailedState.CONNECTED) { 1779 //DHCP renewal in connected state 1780 LinkProperties linkProperties = dhcpInfoInternal.makeLinkProperties(); 1781 linkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); 1782 linkProperties.setInterfaceName(mInterfaceName); 1783 if (!linkProperties.equals(mLinkProperties)) { 1784 if (DBG) { 1785 log("Link configuration changed for netId: " + mLastNetworkId 1786 + " old: " + mLinkProperties + "new: " + linkProperties); 1787 } 1788 mLinkProperties = linkProperties; 1789 sendLinkConfigurationChangedBroadcast(); 1790 } 1791 } else { 1792 configureLinkProperties(); 1793 } 1794 } 1795 1796 private void handleFailedIpConfiguration() { 1797 loge("IP configuration failed"); 1798 1799 mWifiInfo.setInetAddress(null); 1800 mWifiInfo.setMeteredHint(false); 1801 /** 1802 * If we've exceeded the maximum number of retries for DHCP 1803 * to a given network, disable the network 1804 */ 1805 int maxRetries = getMaxDhcpRetries(); 1806 // maxRetries == 0 means keep trying forever 1807 if (maxRetries > 0 && ++mReconnectCount > maxRetries) { 1808 loge("Failed " + 1809 mReconnectCount + " times, Disabling " + mLastNetworkId); 1810 mWifiConfigStore.disableNetwork(mLastNetworkId, 1811 WifiConfiguration.DISABLED_DHCP_FAILURE); 1812 mReconnectCount = 0; 1813 } 1814 1815 /* DHCP times out after about 30 seconds, we do a 1816 * disconnect and an immediate reconnect to try again 1817 */ 1818 mWifiNative.disconnect(); 1819 mWifiNative.reconnect(); 1820 } 1821 1822 /* Current design is to not set the config on a running hostapd but instead 1823 * stop and start tethering when user changes config on a running access point 1824 * 1825 * TODO: Add control channel setup through hostapd that allows changing config 1826 * on a running daemon 1827 */ 1828 private void startSoftApWithConfig(final WifiConfiguration config) { 1829 // start hostapd on a seperate thread 1830 new Thread(new Runnable() { 1831 public void run() { 1832 try { 1833 mNwService.startAccessPoint(config, mInterfaceName); 1834 } catch (Exception e) { 1835 loge("Exception in softap start " + e); 1836 try { 1837 mNwService.stopAccessPoint(mInterfaceName); 1838 mNwService.startAccessPoint(config, mInterfaceName); 1839 } catch (Exception e1) { 1840 loge("Exception in softap re-start " + e1); 1841 sendMessage(CMD_START_AP_FAILURE); 1842 return; 1843 } 1844 } 1845 if (DBG) log("Soft AP start successful"); 1846 sendMessage(CMD_START_AP_SUCCESS); 1847 } 1848 }).start(); 1849 } 1850 1851 /******************************************************** 1852 * HSM states 1853 *******************************************************/ 1854 1855 class DefaultState extends State { 1856 @Override 1857 public boolean processMessage(Message message) { 1858 if (DBG) log(getName() + message.toString() + "\n"); 1859 switch (message.what) { 1860 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 1861 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 1862 mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 1863 } else { 1864 loge("WifiP2pService connection failure, error=" + message.arg1); 1865 } 1866 break; 1867 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 1868 loge("WifiP2pService channel lost, message.arg1 =" + message.arg1); 1869 //TODO: Re-establish connection to state machine after a delay 1870 //mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger()); 1871 break; 1872 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 1873 mBluetoothConnectionActive = (message.arg1 != 1874 BluetoothAdapter.STATE_DISCONNECTED); 1875 break; 1876 /* Synchronous call returns */ 1877 case CMD_PING_SUPPLICANT: 1878 case CMD_ENABLE_NETWORK: 1879 case CMD_ADD_OR_UPDATE_NETWORK: 1880 case CMD_REMOVE_NETWORK: 1881 case CMD_SAVE_CONFIG: 1882 replyToMessage(message, message.what, FAILURE); 1883 break; 1884 case CMD_GET_CONFIGURED_NETWORKS: 1885 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 1886 break; 1887 case CMD_ENABLE_RSSI_POLL: 1888 mEnableRssiPolling = (message.arg1 == 1); 1889 break; 1890 case CMD_ENABLE_BACKGROUND_SCAN: 1891 mEnableBackgroundScan = (message.arg1 == 1); 1892 break; 1893 case CMD_SET_HIGH_PERF_MODE: 1894 mHighPerfMode = (message.arg1 == 1); 1895 break; 1896 /* Discard */ 1897 case CMD_LOAD_DRIVER: 1898 case CMD_UNLOAD_DRIVER: 1899 case CMD_START_SUPPLICANT: 1900 case CMD_STOP_SUPPLICANT: 1901 case CMD_STOP_SUPPLICANT_FAILED: 1902 case CMD_START_DRIVER: 1903 case CMD_STOP_DRIVER: 1904 case CMD_DELAYED_STOP_DRIVER: 1905 case CMD_DRIVER_START_TIMED_OUT: 1906 case CMD_START_AP: 1907 case CMD_START_AP_SUCCESS: 1908 case CMD_START_AP_FAILURE: 1909 case CMD_STOP_AP: 1910 case CMD_TETHER_STATE_CHANGE: 1911 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 1912 case CMD_START_SCAN: 1913 case CMD_DISCONNECT: 1914 case CMD_RECONNECT: 1915 case CMD_REASSOCIATE: 1916 case WifiMonitor.SUP_CONNECTION_EVENT: 1917 case WifiMonitor.SUP_DISCONNECTION_EVENT: 1918 case WifiMonitor.NETWORK_CONNECTION_EVENT: 1919 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 1920 case WifiMonitor.SCAN_RESULTS_EVENT: 1921 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 1922 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 1923 case WifiMonitor.WPS_OVERLAP_EVENT: 1924 case CMD_BLACKLIST_NETWORK: 1925 case CMD_CLEAR_BLACKLIST: 1926 case CMD_SET_SCAN_MODE: 1927 case CMD_SET_SCAN_TYPE: 1928 case CMD_SET_COUNTRY_CODE: 1929 case CMD_SET_FREQUENCY_BAND: 1930 case CMD_RSSI_POLL: 1931 case CMD_ENABLE_ALL_NETWORKS: 1932 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 1933 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 1934 /* Handled by WifiApConfigStore */ 1935 case CMD_SET_AP_CONFIG: 1936 case CMD_SET_AP_CONFIG_COMPLETED: 1937 case CMD_REQUEST_AP_CONFIG: 1938 case CMD_RESPONSE_AP_CONFIG: 1939 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 1940 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 1941 case CMD_CLEAR_SUSPEND_OPTIMIZATIONS: 1942 case CMD_NO_NETWORKS_PERIODIC_SCAN: 1943 break; 1944 case CMD_SET_SUSPEND_OPTIMIZATIONS: 1945 mSuspendWakeLock.release(); 1946 break; 1947 case WifiMonitor.DRIVER_HUNG_EVENT: 1948 setWifiEnabled(false); 1949 setWifiEnabled(true); 1950 break; 1951 case WifiManager.CONNECT_NETWORK: 1952 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 1953 WifiManager.BUSY); 1954 break; 1955 case WifiManager.FORGET_NETWORK: 1956 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 1957 WifiManager.BUSY); 1958 break; 1959 case WifiManager.SAVE_NETWORK: 1960 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 1961 WifiManager.BUSY); 1962 break; 1963 case WifiManager.START_WPS: 1964 replyToMessage(message, WifiManager.WPS_FAILED, 1965 WifiManager.BUSY); 1966 break; 1967 case WifiManager.CANCEL_WPS: 1968 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, 1969 WifiManager.BUSY); 1970 break; 1971 case WifiManager.DISABLE_NETWORK: 1972 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 1973 WifiManager.BUSY); 1974 break; 1975 case WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH: 1976 replyToMessage(message, WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH_FAILED); 1977 break; 1978 default: 1979 loge("Error! unhandled message" + message); 1980 break; 1981 } 1982 return HANDLED; 1983 } 1984 } 1985 1986 class InitialState extends State { 1987 @Override 1988 //TODO: could move logging into a common class 1989 public void enter() { 1990 if (DBG) log(getName() + "\n"); 1991 // [31-8] Reserved for future use 1992 // [7 - 0] HSM state change 1993 // 50021 wifi_state_changed (custom|1|5) 1994 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1995 1996 if (mWifiNative.isDriverLoaded()) { 1997 transitionTo(mDriverLoadedState); 1998 } 1999 else { 2000 transitionTo(mDriverUnloadedState); 2001 } 2002 2003 //Connect to WifiP2pService 2004 mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE); 2005 mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger()); 2006 2007 /* IPv6 is disabled at boot time and is controlled by framework 2008 * to be enabled only as long as we are connected to an access point 2009 * 2010 * This fixes issues, a few being: 2011 * - IPv6 addresses and routes stick around after disconnection 2012 * - When connected, the kernel is unaware and can fail to start IPv6 negotiation 2013 * - The kernel sometimes starts autoconfiguration when 802.1x is not complete 2014 */ 2015 try { 2016 mNwService.disableIpv6(mInterfaceName); 2017 } catch (RemoteException re) { 2018 loge("Failed to disable IPv6: " + re); 2019 } catch (IllegalStateException e) { 2020 loge("Failed to disable IPv6: " + e); 2021 } 2022 } 2023 } 2024 2025 class DriverLoadingState extends State { 2026 @Override 2027 public void enter() { 2028 if (DBG) log(getName() + "\n"); 2029 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2030 2031 final Message message = new Message(); 2032 message.copyFrom(getCurrentMessage()); 2033 /* TODO: add a timeout to fail when driver load is hung. 2034 * Similarly for driver unload. 2035 */ 2036 new Thread(new Runnable() { 2037 public void run() { 2038 mWakeLock.acquire(); 2039 //enabling state 2040 switch(message.arg1) { 2041 case WIFI_STATE_ENABLING: 2042 setWifiState(WIFI_STATE_ENABLING); 2043 break; 2044 case WIFI_AP_STATE_ENABLING: 2045 setWifiApState(WIFI_AP_STATE_ENABLING); 2046 break; 2047 } 2048 2049 if(mWifiNative.loadDriver()) { 2050 if (DBG) log("Driver load successful"); 2051 sendMessage(CMD_LOAD_DRIVER_SUCCESS); 2052 } else { 2053 loge("Failed to load driver!"); 2054 switch(message.arg1) { 2055 case WIFI_STATE_ENABLING: 2056 setWifiState(WIFI_STATE_UNKNOWN); 2057 break; 2058 case WIFI_AP_STATE_ENABLING: 2059 setWifiApState(WIFI_AP_STATE_FAILED); 2060 break; 2061 } 2062 sendMessage(CMD_LOAD_DRIVER_FAILURE); 2063 } 2064 mWakeLock.release(); 2065 } 2066 }).start(); 2067 } 2068 2069 @Override 2070 public boolean processMessage(Message message) { 2071 if (DBG) log(getName() + message.toString() + "\n"); 2072 switch (message.what) { 2073 case CMD_LOAD_DRIVER_SUCCESS: 2074 transitionTo(mDriverLoadedState); 2075 break; 2076 case CMD_LOAD_DRIVER_FAILURE: 2077 transitionTo(mDriverFailedState); 2078 break; 2079 case CMD_LOAD_DRIVER: 2080 case CMD_UNLOAD_DRIVER: 2081 case CMD_START_SUPPLICANT: 2082 case CMD_STOP_SUPPLICANT: 2083 case CMD_START_AP: 2084 case CMD_STOP_AP: 2085 case CMD_START_DRIVER: 2086 case CMD_STOP_DRIVER: 2087 case CMD_SET_SCAN_MODE: 2088 case CMD_SET_SCAN_TYPE: 2089 case CMD_SET_COUNTRY_CODE: 2090 case CMD_SET_FREQUENCY_BAND: 2091 case CMD_START_PACKET_FILTERING: 2092 case CMD_STOP_PACKET_FILTERING: 2093 deferMessage(message); 2094 break; 2095 default: 2096 return NOT_HANDLED; 2097 } 2098 return HANDLED; 2099 } 2100 } 2101 2102 class DriverLoadedState extends State { 2103 @Override 2104 public void enter() { 2105 if (DBG) log(getName() + "\n"); 2106 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2107 } 2108 @Override 2109 public boolean processMessage(Message message) { 2110 if (DBG) log(getName() + message.toString() + "\n"); 2111 switch(message.what) { 2112 case CMD_UNLOAD_DRIVER: 2113 transitionTo(mDriverUnloadingState); 2114 break; 2115 case CMD_START_SUPPLICANT: 2116 try { 2117 mNwService.wifiFirmwareReload(mInterfaceName, "STA"); 2118 } catch (Exception e) { 2119 loge("Failed to reload STA firmware " + e); 2120 // continue 2121 } 2122 try { 2123 //A runtime crash can leave the interface up and 2124 //this affects connectivity when supplicant starts up. 2125 //Ensure interface is down before a supplicant start. 2126 mNwService.setInterfaceDown(mInterfaceName); 2127 //Set privacy extensions 2128 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); 2129 } catch (RemoteException re) { 2130 loge("Unable to change interface settings: " + re); 2131 } catch (IllegalStateException ie) { 2132 loge("Unable to change interface settings: " + ie); 2133 } 2134 2135 if(mWifiNative.startSupplicant(mP2pSupported)) { 2136 if (DBG) log("Supplicant start successful"); 2137 mWifiMonitor.startMonitoring(); 2138 transitionTo(mSupplicantStartingState); 2139 } else { 2140 loge("Failed to start supplicant!"); 2141 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0)); 2142 } 2143 break; 2144 case CMD_START_AP: 2145 transitionTo(mSoftApStartingState); 2146 break; 2147 default: 2148 return NOT_HANDLED; 2149 } 2150 return HANDLED; 2151 } 2152 } 2153 2154 class DriverUnloadingState extends State { 2155 @Override 2156 public void enter() { 2157 if (DBG) log(getName() + "\n"); 2158 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2159 2160 final Message message = new Message(); 2161 message.copyFrom(getCurrentMessage()); 2162 new Thread(new Runnable() { 2163 public void run() { 2164 if (DBG) log(getName() + message.toString() + "\n"); 2165 mWakeLock.acquire(); 2166 if(mWifiNative.unloadDriver()) { 2167 if (DBG) log("Driver unload successful"); 2168 sendMessage(CMD_UNLOAD_DRIVER_SUCCESS); 2169 2170 switch(message.arg1) { 2171 case WIFI_STATE_DISABLED: 2172 case WIFI_STATE_UNKNOWN: 2173 setWifiState(message.arg1); 2174 break; 2175 case WIFI_AP_STATE_DISABLED: 2176 case WIFI_AP_STATE_FAILED: 2177 setWifiApState(message.arg1); 2178 break; 2179 } 2180 } else { 2181 loge("Failed to unload driver!"); 2182 sendMessage(CMD_UNLOAD_DRIVER_FAILURE); 2183 2184 switch(message.arg1) { 2185 case WIFI_STATE_DISABLED: 2186 case WIFI_STATE_UNKNOWN: 2187 setWifiState(WIFI_STATE_UNKNOWN); 2188 break; 2189 case WIFI_AP_STATE_DISABLED: 2190 case WIFI_AP_STATE_FAILED: 2191 setWifiApState(WIFI_AP_STATE_FAILED); 2192 break; 2193 } 2194 } 2195 mWakeLock.release(); 2196 } 2197 }).start(); 2198 } 2199 2200 @Override 2201 public boolean processMessage(Message message) { 2202 if (DBG) log(getName() + message.toString() + "\n"); 2203 switch (message.what) { 2204 case CMD_UNLOAD_DRIVER_SUCCESS: 2205 transitionTo(mDriverUnloadedState); 2206 break; 2207 case CMD_UNLOAD_DRIVER_FAILURE: 2208 transitionTo(mDriverFailedState); 2209 break; 2210 case CMD_LOAD_DRIVER: 2211 case CMD_UNLOAD_DRIVER: 2212 case CMD_START_SUPPLICANT: 2213 case CMD_STOP_SUPPLICANT: 2214 case CMD_START_AP: 2215 case CMD_STOP_AP: 2216 case CMD_START_DRIVER: 2217 case CMD_STOP_DRIVER: 2218 case CMD_SET_SCAN_MODE: 2219 case CMD_SET_SCAN_TYPE: 2220 case CMD_SET_COUNTRY_CODE: 2221 case CMD_SET_FREQUENCY_BAND: 2222 case CMD_START_PACKET_FILTERING: 2223 case CMD_STOP_PACKET_FILTERING: 2224 deferMessage(message); 2225 break; 2226 default: 2227 return NOT_HANDLED; 2228 } 2229 return HANDLED; 2230 } 2231 } 2232 2233 class DriverUnloadedState extends State { 2234 @Override 2235 public void enter() { 2236 if (DBG) log(getName() + "\n"); 2237 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2238 } 2239 @Override 2240 public boolean processMessage(Message message) { 2241 if (DBG) log(getName() + message.toString() + "\n"); 2242 switch (message.what) { 2243 case CMD_LOAD_DRIVER: 2244 transitionTo(mDriverLoadingState); 2245 break; 2246 default: 2247 return NOT_HANDLED; 2248 } 2249 return HANDLED; 2250 } 2251 } 2252 2253 class DriverFailedState extends State { 2254 @Override 2255 public void enter() { 2256 loge(getName() + "\n"); 2257 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2258 } 2259 @Override 2260 public boolean processMessage(Message message) { 2261 if (DBG) log(getName() + message.toString() + "\n"); 2262 return NOT_HANDLED; 2263 } 2264 } 2265 2266 2267 class SupplicantStartingState extends State { 2268 @Override 2269 public void enter() { 2270 if (DBG) log(getName() + "\n"); 2271 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2272 } 2273 2274 private void initializeWpsDetails() { 2275 String detail; 2276 detail = SystemProperties.get("ro.product.name", ""); 2277 if (!mWifiNative.setDeviceName(detail)) { 2278 loge("Failed to set device name " + detail); 2279 } 2280 detail = SystemProperties.get("ro.product.manufacturer", ""); 2281 if (!mWifiNative.setManufacturer(detail)) { 2282 loge("Failed to set manufacturer " + detail); 2283 } 2284 detail = SystemProperties.get("ro.product.model", ""); 2285 if (!mWifiNative.setModelName(detail)) { 2286 loge("Failed to set model name " + detail); 2287 } 2288 detail = SystemProperties.get("ro.product.model", ""); 2289 if (!mWifiNative.setModelNumber(detail)) { 2290 loge("Failed to set model number " + detail); 2291 } 2292 detail = SystemProperties.get("ro.serialno", ""); 2293 if (!mWifiNative.setSerialNumber(detail)) { 2294 loge("Failed to set serial number " + detail); 2295 } 2296 if (!mWifiNative.setConfigMethods("physical_display virtual_push_button keypad")) { 2297 loge("Failed to set WPS config methods"); 2298 } 2299 if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) { 2300 loge("Failed to set primary device type " + mPrimaryDeviceType); 2301 } 2302 } 2303 2304 @Override 2305 public boolean processMessage(Message message) { 2306 if (DBG) log(getName() + message.toString() + "\n"); 2307 switch(message.what) { 2308 case WifiMonitor.SUP_CONNECTION_EVENT: 2309 if (DBG) log("Supplicant connection established"); 2310 setWifiState(WIFI_STATE_ENABLED); 2311 mSupplicantRestartCount = 0; 2312 /* Reset the supplicant state to indicate the supplicant 2313 * state is not known at this time */ 2314 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2315 /* Initialize data structures */ 2316 mLastBssid = null; 2317 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 2318 mLastSignalLevel = -1; 2319 2320 mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); 2321 mWifiConfigStore.initialize(); 2322 initializeWpsDetails(); 2323 2324 sendSupplicantConnectionChangedBroadcast(true); 2325 transitionTo(mDriverStartedState); 2326 break; 2327 case WifiMonitor.SUP_DISCONNECTION_EVENT: 2328 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { 2329 loge("Failed to setup control channel, restart supplicant"); 2330 mWifiNative.killSupplicant(); 2331 transitionTo(mDriverLoadedState); 2332 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 2333 } else { 2334 loge("Failed " + mSupplicantRestartCount + 2335 " times to start supplicant, unload driver"); 2336 mSupplicantRestartCount = 0; 2337 transitionTo(mDriverLoadedState); 2338 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0)); 2339 } 2340 break; 2341 case CMD_LOAD_DRIVER: 2342 case CMD_UNLOAD_DRIVER: 2343 case CMD_START_SUPPLICANT: 2344 case CMD_STOP_SUPPLICANT: 2345 case CMD_START_AP: 2346 case CMD_STOP_AP: 2347 case CMD_START_DRIVER: 2348 case CMD_STOP_DRIVER: 2349 case CMD_SET_SCAN_MODE: 2350 case CMD_SET_SCAN_TYPE: 2351 case CMD_SET_COUNTRY_CODE: 2352 case CMD_SET_FREQUENCY_BAND: 2353 case CMD_START_PACKET_FILTERING: 2354 case CMD_STOP_PACKET_FILTERING: 2355 deferMessage(message); 2356 break; 2357 default: 2358 return NOT_HANDLED; 2359 } 2360 return HANDLED; 2361 } 2362 } 2363 2364 class SupplicantStartedState extends State { 2365 @Override 2366 public void enter() { 2367 if (DBG) log(getName() + "\n"); 2368 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2369 /* Initialize for connect mode operation at start */ 2370 mIsScanMode = false; 2371 /* Wifi is available as long as we have a connection to supplicant */ 2372 mNetworkInfo.setIsAvailable(true); 2373 2374 int defaultInterval = mContext.getResources().getInteger( 2375 com.android.internal.R.integer.config_wifi_supplicant_scan_interval); 2376 2377 mSupplicantScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(), 2378 Settings.Secure.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, 2379 defaultInterval); 2380 2381 mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000); 2382 } 2383 @Override 2384 public boolean processMessage(Message message) { 2385 if (DBG) log(getName() + message.toString() + "\n"); 2386 WifiConfiguration config; 2387 switch(message.what) { 2388 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ 2389 transitionTo(mSupplicantStoppingState); 2390 break; 2391 case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ 2392 loge("Connection lost, restart supplicant"); 2393 mWifiNative.killSupplicant(); 2394 mWifiNative.closeSupplicantConnection(); 2395 mNetworkInfo.setIsAvailable(false); 2396 handleNetworkDisconnect(); 2397 sendSupplicantConnectionChangedBroadcast(false); 2398 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2399 transitionTo(mDriverLoadedState); 2400 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 2401 break; 2402 case WifiMonitor.SCAN_RESULTS_EVENT: 2403 setScanResults(mWifiNative.scanResults()); 2404 sendScanResultsAvailableBroadcast(); 2405 mScanResultIsPending = false; 2406 break; 2407 case CMD_PING_SUPPLICANT: 2408 boolean ok = mWifiNative.ping(); 2409 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 2410 break; 2411 case CMD_ADD_OR_UPDATE_NETWORK: 2412 config = (WifiConfiguration) message.obj; 2413 replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, 2414 mWifiConfigStore.addOrUpdateNetwork(config)); 2415 break; 2416 case CMD_REMOVE_NETWORK: 2417 ok = mWifiConfigStore.removeNetwork(message.arg1); 2418 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 2419 break; 2420 case CMD_ENABLE_NETWORK: 2421 ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); 2422 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 2423 break; 2424 case CMD_ENABLE_ALL_NETWORKS: 2425 long time = android.os.SystemClock.elapsedRealtime(); 2426 if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { 2427 mWifiConfigStore.enableAllNetworks(); 2428 mLastEnableAllNetworksTime = time; 2429 } 2430 break; 2431 case WifiManager.DISABLE_NETWORK: 2432 if (mWifiConfigStore.disableNetwork(message.arg1, 2433 WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) { 2434 replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); 2435 } else { 2436 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 2437 WifiManager.ERROR); 2438 } 2439 break; 2440 case CMD_BLACKLIST_NETWORK: 2441 mWifiNative.addToBlacklist((String)message.obj); 2442 break; 2443 case CMD_CLEAR_BLACKLIST: 2444 mWifiNative.clearBlacklist(); 2445 break; 2446 case CMD_SAVE_CONFIG: 2447 ok = mWifiConfigStore.saveConfig(); 2448 replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); 2449 2450 // Inform the backup manager about a data change 2451 IBackupManager ibm = IBackupManager.Stub.asInterface( 2452 ServiceManager.getService(Context.BACKUP_SERVICE)); 2453 if (ibm != null) { 2454 try { 2455 ibm.dataChanged("com.android.providers.settings"); 2456 } catch (Exception e) { 2457 // Try again later 2458 } 2459 } 2460 break; 2461 case CMD_GET_CONFIGURED_NETWORKS: 2462 replyToMessage(message, message.what, 2463 mWifiConfigStore.getConfiguredNetworks()); 2464 break; 2465 /* Cannot start soft AP while in client mode */ 2466 case CMD_START_AP: 2467 loge("Failed to start soft AP with a running supplicant"); 2468 setWifiApState(WIFI_AP_STATE_FAILED); 2469 break; 2470 case CMD_SET_SCAN_MODE: 2471 mIsScanMode = (message.arg1 == SCAN_ONLY_MODE); 2472 break; 2473 case WifiManager.SAVE_NETWORK: 2474 config = (WifiConfiguration) message.obj; 2475 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 2476 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 2477 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 2478 } else { 2479 loge("Failed to save network"); 2480 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 2481 WifiManager.ERROR); 2482 } 2483 break; 2484 case WifiManager.FORGET_NETWORK: 2485 if (mWifiConfigStore.forgetNetwork(message.arg1)) { 2486 replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); 2487 } else { 2488 loge("Failed to forget network"); 2489 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 2490 WifiManager.ERROR); 2491 } 2492 break; 2493 default: 2494 return NOT_HANDLED; 2495 } 2496 return HANDLED; 2497 } 2498 2499 @Override 2500 public void exit() { 2501 mNetworkInfo.setIsAvailable(false); 2502 } 2503 } 2504 2505 class SupplicantStoppingState extends State { 2506 @Override 2507 public void enter() { 2508 if (DBG) log(getName() + "\n"); 2509 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2510 2511 /* Send any reset commands to supplicant before shutting it down */ 2512 handleNetworkDisconnect(); 2513 2514 if (DBG) log("stopping supplicant"); 2515 if (!mWifiNative.stopSupplicant()) { 2516 loge("Failed to stop supplicant"); 2517 } 2518 2519 /* Send ourselves a delayed message to indicate failure after a wait time */ 2520 sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED, 2521 ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS); 2522 2523 mNetworkInfo.setIsAvailable(false); 2524 setWifiState(WIFI_STATE_DISABLING); 2525 sendSupplicantConnectionChangedBroadcast(false); 2526 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2527 } 2528 @Override 2529 public boolean processMessage(Message message) { 2530 if (DBG) log(getName() + message.toString() + "\n"); 2531 switch(message.what) { 2532 case WifiMonitor.SUP_CONNECTION_EVENT: 2533 loge("Supplicant connection received while stopping"); 2534 break; 2535 case WifiMonitor.SUP_DISCONNECTION_EVENT: 2536 if (DBG) log("Supplicant connection lost"); 2537 /* Socket connection can be lost when we do a graceful shutdown 2538 * or when the driver is hung. Ensure supplicant is stopped here. 2539 */ 2540 mWifiNative.killSupplicant(); 2541 mWifiNative.closeSupplicantConnection(); 2542 transitionTo(mDriverLoadedState); 2543 break; 2544 case CMD_STOP_SUPPLICANT_FAILED: 2545 if (message.arg1 == mSupplicantStopFailureToken) { 2546 loge("Timed out on a supplicant stop, kill and proceed"); 2547 mWifiNative.killSupplicant(); 2548 mWifiNative.closeSupplicantConnection(); 2549 transitionTo(mDriverLoadedState); 2550 } 2551 break; 2552 case CMD_LOAD_DRIVER: 2553 case CMD_UNLOAD_DRIVER: 2554 case CMD_START_SUPPLICANT: 2555 case CMD_STOP_SUPPLICANT: 2556 case CMD_START_AP: 2557 case CMD_STOP_AP: 2558 case CMD_START_DRIVER: 2559 case CMD_STOP_DRIVER: 2560 case CMD_SET_SCAN_MODE: 2561 case CMD_SET_SCAN_TYPE: 2562 case CMD_SET_COUNTRY_CODE: 2563 case CMD_SET_FREQUENCY_BAND: 2564 case CMD_START_PACKET_FILTERING: 2565 case CMD_STOP_PACKET_FILTERING: 2566 deferMessage(message); 2567 break; 2568 default: 2569 return NOT_HANDLED; 2570 } 2571 return HANDLED; 2572 } 2573 } 2574 2575 class DriverStartingState extends State { 2576 private int mTries; 2577 @Override 2578 public void enter() { 2579 if (DBG) log(getName() + "\n"); 2580 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2581 2582 mTries = 1; 2583 /* Send ourselves a delayed message to start driver a second time */ 2584 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 2585 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 2586 } 2587 @Override 2588 public boolean processMessage(Message message) { 2589 if (DBG) log(getName() + message.toString() + "\n"); 2590 switch(message.what) { 2591 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2592 SupplicantState state = handleSupplicantStateChange(message); 2593 /* If suplicant is exiting out of INTERFACE_DISABLED state into 2594 * a state that indicates driver has started, it is ready to 2595 * receive driver commands 2596 */ 2597 if (SupplicantState.isDriverActive(state)) { 2598 transitionTo(mDriverStartedState); 2599 } 2600 break; 2601 case CMD_DRIVER_START_TIMED_OUT: 2602 if (message.arg1 == mDriverStartToken) { 2603 if (mTries >= 2) { 2604 loge("Failed to start driver after " + mTries); 2605 transitionTo(mDriverStoppedState); 2606 } else { 2607 loge("Driver start failed, retrying"); 2608 mWakeLock.acquire(); 2609 mWifiNative.startDriver(); 2610 mWakeLock.release(); 2611 2612 ++mTries; 2613 /* Send ourselves a delayed message to start driver again */ 2614 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 2615 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 2616 } 2617 } 2618 break; 2619 /* Queue driver commands & connection events */ 2620 case CMD_START_DRIVER: 2621 case CMD_STOP_DRIVER: 2622 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2623 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2624 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 2625 case WifiMonitor.WPS_OVERLAP_EVENT: 2626 case CMD_SET_SCAN_TYPE: 2627 case CMD_SET_COUNTRY_CODE: 2628 case CMD_SET_FREQUENCY_BAND: 2629 case CMD_START_PACKET_FILTERING: 2630 case CMD_STOP_PACKET_FILTERING: 2631 case CMD_START_SCAN: 2632 case CMD_DISCONNECT: 2633 case CMD_REASSOCIATE: 2634 case CMD_RECONNECT: 2635 deferMessage(message); 2636 break; 2637 default: 2638 return NOT_HANDLED; 2639 } 2640 return HANDLED; 2641 } 2642 } 2643 2644 class DriverStartedState extends State { 2645 @Override 2646 public void enter() { 2647 if (DBG) log(getName() + "\n"); 2648 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2649 2650 mIsRunning = true; 2651 mInDelayedStop = false; 2652 updateBatteryWorkSource(null); 2653 2654 /** 2655 * Enable bluetooth coexistence scan mode when bluetooth connection is active. 2656 * When this mode is on, some of the low-level scan parameters used by the 2657 * driver are changed to reduce interference with bluetooth 2658 */ 2659 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 2660 /* set country code */ 2661 setCountryCode(); 2662 /* set frequency band of operation */ 2663 setFrequencyBand(); 2664 /* initialize network state */ 2665 setNetworkDetailedState(DetailedState.DISCONNECTED); 2666 2667 /* Remove any filtering on Multicast v6 at start */ 2668 mWifiNative.stopFilteringMulticastV6Packets(); 2669 2670 /* Reset Multicast v4 filtering state */ 2671 if (mFilteringMulticastV4Packets.get()) { 2672 mWifiNative.startFilteringMulticastV4Packets(); 2673 } else { 2674 mWifiNative.stopFilteringMulticastV4Packets(); 2675 } 2676 2677 mWifiNative.setPowerSave(mPowerSaveEnabled); 2678 2679 if (mIsScanMode) { 2680 mWifiNative.setScanResultHandling(SCAN_ONLY_MODE); 2681 mWifiNative.disconnect(); 2682 transitionTo(mScanModeState); 2683 } else { 2684 mWifiNative.setScanResultHandling(CONNECT_MODE); 2685 mWifiNative.reconnect(); 2686 // Status pulls in the current supplicant state and network connection state 2687 // events over the monitor connection. This helps framework sync up with 2688 // current supplicant state 2689 mWifiNative.status(); 2690 transitionTo(mDisconnectedState); 2691 } 2692 2693 if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); 2694 2695 mContext.registerReceiver(mScreenReceiver, mScreenFilter); 2696 } 2697 @Override 2698 public boolean processMessage(Message message) { 2699 if (DBG) log(getName() + message.toString() + "\n"); 2700 switch(message.what) { 2701 case CMD_SET_SCAN_TYPE: 2702 mSetScanActive = (message.arg1 == SCAN_ACTIVE); 2703 mWifiNative.setScanMode(mSetScanActive); 2704 break; 2705 case CMD_START_SCAN: 2706 boolean forceActive = (message.arg1 == SCAN_ACTIVE); 2707 if (forceActive && !mSetScanActive) { 2708 mWifiNative.setScanMode(forceActive); 2709 } 2710 mWifiNative.scan(); 2711 if (forceActive && !mSetScanActive) { 2712 mWifiNative.setScanMode(mSetScanActive); 2713 } 2714 mScanResultIsPending = true; 2715 break; 2716 case CMD_SET_COUNTRY_CODE: 2717 String country = (String) message.obj; 2718 if (DBG) log("set country code " + country); 2719 if (!mWifiNative.setCountryCode(country.toUpperCase())) { 2720 loge("Failed to set country code " + country); 2721 } 2722 break; 2723 case CMD_SET_FREQUENCY_BAND: 2724 int band = message.arg1; 2725 if (DBG) log("set frequency band " + band); 2726 if (mWifiNative.setBand(band)) { 2727 mFrequencyBand.set(band); 2728 //Fetch the latest scan results when frequency band is set 2729 startScan(true); 2730 } else { 2731 loge("Failed to set frequency band " + band); 2732 } 2733 break; 2734 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 2735 mBluetoothConnectionActive = (message.arg1 != 2736 BluetoothAdapter.STATE_DISCONNECTED); 2737 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 2738 break; 2739 case CMD_STOP_DRIVER: 2740 int mode = message.arg1; 2741 2742 /* Already doing a delayed stop && not in ecm state */ 2743 if (mInDelayedStop && mode != IN_ECM_STATE) { 2744 if (DBG) log("Already in delayed stop"); 2745 break; 2746 } 2747 mInDelayedStop = true; 2748 mDelayedStopCounter++; 2749 if (DBG) log("Delayed stop message " + mDelayedStopCounter); 2750 2751 if (mode == IN_ECM_STATE) { 2752 /* send a shut down immediately */ 2753 sendMessage(obtainMessage(CMD_DELAYED_STOP_DRIVER, mDelayedStopCounter, 0)); 2754 } else { 2755 /* send regular delayed shut down */ 2756 Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); 2757 driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); 2758 mDriverStopIntent = PendingIntent.getBroadcast(mContext, 2759 DRIVER_STOP_REQUEST, driverStopIntent, 2760 PendingIntent.FLAG_UPDATE_CURRENT); 2761 2762 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 2763 + mDriverStopDelayMs, mDriverStopIntent); 2764 } 2765 break; 2766 case CMD_START_DRIVER: 2767 if (mInDelayedStop) { 2768 mInDelayedStop = false; 2769 mDelayedStopCounter++; 2770 mAlarmManager.cancel(mDriverStopIntent); 2771 if (DBG) log("Delayed stop ignored due to start"); 2772 } 2773 break; 2774 case CMD_DELAYED_STOP_DRIVER: 2775 if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter); 2776 if (message.arg1 != mDelayedStopCounter) break; 2777 if (getCurrentState() != mDisconnectedState) { 2778 mWifiNative.disconnect(); 2779 handleNetworkDisconnect(); 2780 } 2781 mWakeLock.acquire(); 2782 mWifiNative.stopDriver(); 2783 transitionTo(mDriverStoppingState); 2784 mWakeLock.release(); 2785 break; 2786 case CMD_START_PACKET_FILTERING: 2787 if (message.arg1 == MULTICAST_V6) { 2788 mWifiNative.startFilteringMulticastV6Packets(); 2789 } else if (message.arg1 == MULTICAST_V4) { 2790 mWifiNative.startFilteringMulticastV4Packets(); 2791 } else { 2792 loge("Illegal arugments to CMD_START_PACKET_FILTERING"); 2793 } 2794 break; 2795 case CMD_STOP_PACKET_FILTERING: 2796 if (message.arg1 == MULTICAST_V6) { 2797 mWifiNative.stopFilteringMulticastV6Packets(); 2798 } else if (message.arg1 == MULTICAST_V4) { 2799 mWifiNative.stopFilteringMulticastV4Packets(); 2800 } else { 2801 loge("Illegal arugments to CMD_STOP_PACKET_FILTERING"); 2802 } 2803 break; 2804 case CMD_SET_SUSPEND_OPTIMIZATIONS: 2805 if (!mHighPerfMode) { 2806 mWifiNative.setSuspendOptimizations(true); 2807 } 2808 mSuspendWakeLock.release(); 2809 break; 2810 case CMD_CLEAR_SUSPEND_OPTIMIZATIONS: 2811 mWifiNative.setSuspendOptimizations(false); 2812 break; 2813 case CMD_SET_HIGH_PERF_MODE: 2814 mHighPerfMode = (message.arg1 == 1); 2815 if (mHighPerfMode) { 2816 //Disable any suspend optimizations 2817 mWifiNative.setSuspendOptimizations(false); 2818 } 2819 break; 2820 default: 2821 return NOT_HANDLED; 2822 } 2823 return HANDLED; 2824 } 2825 @Override 2826 public void exit() { 2827 if (DBG) log(getName() + "\n"); 2828 mIsRunning = false; 2829 updateBatteryWorkSource(null); 2830 mScanResults = null; 2831 2832 if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P); 2833 mContext.unregisterReceiver(mScreenReceiver); 2834 } 2835 } 2836 2837 class DriverStoppingState extends State { 2838 @Override 2839 public void enter() { 2840 if (DBG) log(getName() + "\n"); 2841 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2842 } 2843 @Override 2844 public boolean processMessage(Message message) { 2845 if (DBG) log(getName() + message.toString() + "\n"); 2846 switch(message.what) { 2847 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2848 SupplicantState state = handleSupplicantStateChange(message); 2849 if (state == SupplicantState.INTERFACE_DISABLED) { 2850 transitionTo(mDriverStoppedState); 2851 } 2852 break; 2853 /* Queue driver commands */ 2854 case CMD_START_DRIVER: 2855 case CMD_STOP_DRIVER: 2856 case CMD_SET_SCAN_TYPE: 2857 case CMD_SET_COUNTRY_CODE: 2858 case CMD_SET_FREQUENCY_BAND: 2859 case CMD_START_PACKET_FILTERING: 2860 case CMD_STOP_PACKET_FILTERING: 2861 case CMD_START_SCAN: 2862 case CMD_DISCONNECT: 2863 case CMD_REASSOCIATE: 2864 case CMD_RECONNECT: 2865 deferMessage(message); 2866 break; 2867 default: 2868 return NOT_HANDLED; 2869 } 2870 return HANDLED; 2871 } 2872 } 2873 2874 class DriverStoppedState extends State { 2875 @Override 2876 public void enter() { 2877 if (DBG) log(getName() + "\n"); 2878 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2879 } 2880 @Override 2881 public boolean processMessage(Message message) { 2882 if (DBG) log(getName() + message.toString() + "\n"); 2883 switch (message.what) { 2884 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2885 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 2886 SupplicantState state = stateChangeResult.state; 2887 // A WEXT bug means that we can be back to driver started state 2888 // unexpectedly 2889 if (SupplicantState.isDriverActive(state)) { 2890 transitionTo(mDriverStartedState); 2891 } 2892 break; 2893 case CMD_START_DRIVER: 2894 mWakeLock.acquire(); 2895 mWifiNative.startDriver(); 2896 mWakeLock.release(); 2897 transitionTo(mDriverStartingState); 2898 break; 2899 default: 2900 return NOT_HANDLED; 2901 } 2902 return HANDLED; 2903 } 2904 } 2905 2906 class ScanModeState extends State { 2907 @Override 2908 public void enter() { 2909 if (DBG) log(getName() + "\n"); 2910 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2911 } 2912 @Override 2913 public boolean processMessage(Message message) { 2914 if (DBG) log(getName() + message.toString() + "\n"); 2915 switch(message.what) { 2916 case CMD_SET_SCAN_MODE: 2917 if (message.arg1 == SCAN_ONLY_MODE) { 2918 /* Ignore */ 2919 return HANDLED; 2920 } else { 2921 mWifiNative.setScanResultHandling(message.arg1); 2922 mWifiNative.reconnect(); 2923 mIsScanMode = false; 2924 transitionTo(mDisconnectedState); 2925 } 2926 break; 2927 /* Ignore */ 2928 case CMD_DISCONNECT: 2929 case CMD_RECONNECT: 2930 case CMD_REASSOCIATE: 2931 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2932 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2933 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2934 break; 2935 default: 2936 return NOT_HANDLED; 2937 } 2938 return HANDLED; 2939 } 2940 } 2941 2942 class ConnectModeState extends State { 2943 @Override 2944 public void enter() { 2945 if (DBG) log(getName() + "\n"); 2946 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2947 } 2948 @Override 2949 public boolean processMessage(Message message) { 2950 if (DBG) log(getName() + message.toString() + "\n"); 2951 StateChangeResult stateChangeResult; 2952 switch(message.what) { 2953 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 2954 mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT); 2955 break; 2956 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2957 SupplicantState state = handleSupplicantStateChange(message); 2958 // A driver/firmware hang can now put the interface in a down state. 2959 // We detect the interface going down and recover from it 2960 if (!SupplicantState.isDriverActive(state)) { 2961 if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 2962 handleNetworkDisconnect(); 2963 } 2964 log("Detected an interface down, restart driver"); 2965 transitionTo(mDriverStoppedState); 2966 sendMessage(CMD_START_DRIVER); 2967 break; 2968 } 2969 2970 // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT 2971 // when authentication times out after a successful connection, 2972 // we can figure this from the supplicant state. If supplicant 2973 // state is DISCONNECTED, but the mNetworkInfo says we are not 2974 // disconnected, we need to handle a disconnection 2975 if (state == SupplicantState.DISCONNECTED && 2976 mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 2977 if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect"); 2978 handleNetworkDisconnect(); 2979 transitionTo(mDisconnectedState); 2980 } 2981 break; 2982 /* Do a redundant disconnect without transition */ 2983 case CMD_DISCONNECT: 2984 mWifiNative.disconnect(); 2985 break; 2986 case CMD_RECONNECT: 2987 mWifiNative.reconnect(); 2988 break; 2989 case CMD_REASSOCIATE: 2990 mWifiNative.reassociate(); 2991 break; 2992 case WifiManager.CONNECT_NETWORK: 2993 /* The connect message can contain a network id passed as arg1 on message or 2994 * or a config passed as obj on message. 2995 * For a new network, a config is passed to create and connect. 2996 * For an existing network, a network id is passed 2997 */ 2998 int netId = message.arg1; 2999 WifiConfiguration config = (WifiConfiguration) message.obj; 3000 3001 /* Save the network config */ 3002 if (config != null) { 3003 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 3004 netId = result.getNetworkId(); 3005 } 3006 3007 if (mWifiConfigStore.selectNetwork(netId) && 3008 mWifiNative.reconnect()) { 3009 /* The state tracker handles enabling networks upon completion/failure */ 3010 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 3011 replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 3012 /* Expect a disconnection from the old connection */ 3013 transitionTo(mDisconnectingState); 3014 } else { 3015 loge("Failed to connect config: " + config + " netId: " + netId); 3016 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 3017 WifiManager.ERROR); 3018 break; 3019 } 3020 break; 3021 case WifiManager.START_WPS: 3022 WpsInfo wpsInfo = (WpsInfo) message.obj; 3023 WpsResult result; 3024 switch (wpsInfo.setup) { 3025 case WpsInfo.PBC: 3026 result = mWifiConfigStore.startWpsPbc(wpsInfo); 3027 break; 3028 case WpsInfo.KEYPAD: 3029 result = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); 3030 break; 3031 case WpsInfo.DISPLAY: 3032 result = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); 3033 break; 3034 default: 3035 result = new WpsResult(Status.FAILURE); 3036 Log.e(TAG, "Invalid setup for WPS"); 3037 break; 3038 } 3039 if (result.status == Status.SUCCESS) { 3040 replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, result); 3041 transitionTo(mWpsRunningState); 3042 } else { 3043 Log.e(TAG, "Failed to start WPS with config " + wpsInfo.toString()); 3044 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR); 3045 } 3046 break; 3047 case WifiMonitor.SCAN_RESULTS_EVENT: 3048 /* Set the scan setting back to "connect" mode */ 3049 mWifiNative.setScanResultHandling(CONNECT_MODE); 3050 /* Handle scan results */ 3051 return NOT_HANDLED; 3052 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3053 if (DBG) log("Network connection established"); 3054 mLastNetworkId = message.arg1; 3055 mLastBssid = (String) message.obj; 3056 3057 mWifiInfo.setBSSID(mLastBssid); 3058 mWifiInfo.setNetworkId(mLastNetworkId); 3059 /* send event to CM & network change broadcast */ 3060 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 3061 sendNetworkStateChangeBroadcast(mLastBssid); 3062 transitionTo(mObtainingIpState); 3063 break; 3064 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 3065 if (DBG) log("Network connection lost"); 3066 handleNetworkDisconnect(); 3067 transitionTo(mDisconnectedState); 3068 break; 3069 default: 3070 return NOT_HANDLED; 3071 } 3072 return HANDLED; 3073 } 3074 } 3075 3076 class L2ConnectedState extends State { 3077 @Override 3078 public void enter() { 3079 if (DBG) log(getName() + "\n"); 3080 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 3081 mRssiPollToken++; 3082 if (mEnableRssiPolling) { 3083 sendMessage(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0)); 3084 } 3085 } 3086 3087 @Override 3088 public boolean processMessage(Message message) { 3089 if (DBG) log(getName() + message.toString() + "\n"); 3090 switch (message.what) { 3091 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 3092 handlePreDhcpSetup(); 3093 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE); 3094 break; 3095 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 3096 handlePostDhcpSetup(); 3097 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 3098 if (DBG) log("DHCP successful"); 3099 handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj); 3100 transitionTo(mVerifyingLinkState); 3101 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { 3102 if (DBG) log("DHCP failed"); 3103 handleFailedIpConfiguration(); 3104 transitionTo(mDisconnectingState); 3105 } 3106 break; 3107 case CMD_DISCONNECT: 3108 mWifiNative.disconnect(); 3109 transitionTo(mDisconnectingState); 3110 break; 3111 case CMD_SET_SCAN_MODE: 3112 if (message.arg1 == SCAN_ONLY_MODE) { 3113 sendMessage(CMD_DISCONNECT); 3114 deferMessage(message); 3115 } 3116 break; 3117 case CMD_START_SCAN: 3118 /* When the network is connected, re-scanning can trigger 3119 * a reconnection. Put it in scan-only mode during scan. 3120 * When scan results are received, the mode is switched 3121 * back to CONNECT_MODE. 3122 */ 3123 mWifiNative.setScanResultHandling(SCAN_ONLY_MODE); 3124 /* Have the parent state handle the rest */ 3125 return NOT_HANDLED; 3126 /* Ignore connection to same network */ 3127 case WifiManager.CONNECT_NETWORK: 3128 int netId = message.arg1; 3129 if (mWifiInfo.getNetworkId() == netId) { 3130 break; 3131 } 3132 return NOT_HANDLED; 3133 case WifiManager.SAVE_NETWORK: 3134 WifiConfiguration config = (WifiConfiguration) message.obj; 3135 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 3136 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 3137 if (result.hasIpChanged()) { 3138 log("Reconfiguring IP on connection"); 3139 transitionTo(mObtainingIpState); 3140 } 3141 if (result.hasProxyChanged()) { 3142 log("Reconfiguring proxy on connection"); 3143 configureLinkProperties(); 3144 sendLinkConfigurationChangedBroadcast(); 3145 } 3146 } 3147 3148 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 3149 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 3150 } else { 3151 loge("Failed to save network"); 3152 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 3153 WifiManager.ERROR); 3154 } 3155 break; 3156 /* Ignore */ 3157 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3158 break; 3159 case CMD_RSSI_POLL: 3160 if (message.arg1 == mRssiPollToken) { 3161 // Get Info and continue polling 3162 fetchRssiAndLinkSpeedNative(); 3163 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 3164 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 3165 } else { 3166 // Polling has completed 3167 } 3168 break; 3169 case CMD_ENABLE_RSSI_POLL: 3170 mEnableRssiPolling = (message.arg1 == 1); 3171 mRssiPollToken++; 3172 if (mEnableRssiPolling) { 3173 // first poll 3174 fetchRssiAndLinkSpeedNative(); 3175 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 3176 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 3177 } 3178 break; 3179 case WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH: 3180 RssiPktcntStat stat = (RssiPktcntStat) message.obj; 3181 fetchRssiAndLinkSpeedNative(); 3182 stat.rssi = mWifiInfo.getRssi(); 3183 fetchPktcntNative(stat); 3184 replyToMessage(message, WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH_SUCCEEDED, 3185 stat); 3186 break; 3187 default: 3188 return NOT_HANDLED; 3189 } 3190 3191 return HANDLED; 3192 } 3193 3194 @Override 3195 public void exit() { 3196 /* If a scan result is pending in connected state, the supplicant 3197 * is in SCAN_ONLY_MODE. Restore CONNECT_MODE on exit 3198 */ 3199 if (mScanResultIsPending) { 3200 mWifiNative.setScanResultHandling(CONNECT_MODE); 3201 } 3202 } 3203 } 3204 3205 class ObtainingIpState extends State { 3206 @Override 3207 public void enter() { 3208 if (DBG) log(getName() + "\n"); 3209 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 3210 3211 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 3212 //start DHCP 3213 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 3214 mContext, WifiStateMachine.this, mInterfaceName); 3215 mDhcpStateMachine.registerForPreDhcpNotification(); 3216 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); 3217 } else { 3218 DhcpInfoInternal dhcpInfoInternal = mWifiConfigStore.getIpConfiguration( 3219 mLastNetworkId); 3220 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 3221 ifcg.setLinkAddress(dhcpInfoInternal.makeLinkAddress()); 3222 ifcg.setInterfaceUp(); 3223 try { 3224 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 3225 if (DBG) log("Static IP configuration succeeded"); 3226 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal); 3227 } catch (RemoteException re) { 3228 loge("Static IP configuration failed: " + re); 3229 sendMessage(CMD_STATIC_IP_FAILURE); 3230 } catch (IllegalStateException e) { 3231 loge("Static IP configuration failed: " + e); 3232 sendMessage(CMD_STATIC_IP_FAILURE); 3233 } 3234 } 3235 } 3236 @Override 3237 public boolean processMessage(Message message) { 3238 if (DBG) log(getName() + message.toString() + "\n"); 3239 switch(message.what) { 3240 case CMD_STATIC_IP_SUCCESS: 3241 handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj); 3242 transitionTo(mVerifyingLinkState); 3243 break; 3244 case CMD_STATIC_IP_FAILURE: 3245 handleFailedIpConfiguration(); 3246 transitionTo(mDisconnectingState); 3247 break; 3248 case WifiManager.SAVE_NETWORK: 3249 deferMessage(message); 3250 break; 3251 /* Defer any power mode changes since we must keep active power mode at DHCP */ 3252 case CMD_SET_HIGH_PERF_MODE: 3253 deferMessage(message); 3254 break; 3255 default: 3256 return NOT_HANDLED; 3257 } 3258 return HANDLED; 3259 } 3260 } 3261 3262 class VerifyingLinkState extends State { 3263 @Override 3264 public void enter() { 3265 if (DBG) log(getName() + "\n"); 3266 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 3267 setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); 3268 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); 3269 sendNetworkStateChangeBroadcast(mLastBssid); 3270 } 3271 @Override 3272 public boolean processMessage(Message message) { 3273 switch (message.what) { 3274 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 3275 //stay here 3276 break; 3277 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 3278 try { 3279 mNwService.enableIpv6(mInterfaceName); 3280 } catch (RemoteException re) { 3281 loge("Failed to enable IPv6: " + re); 3282 } catch (IllegalStateException e) { 3283 loge("Failed to enable IPv6: " + e); 3284 } 3285 3286 setNetworkDetailedState(DetailedState.CONNECTED); 3287 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); 3288 sendNetworkStateChangeBroadcast(mLastBssid); 3289 transitionTo(mConnectedState); 3290 break; 3291 default: 3292 return NOT_HANDLED; 3293 } 3294 return HANDLED; 3295 } 3296 } 3297 3298 class ConnectedState extends State { 3299 @Override 3300 public void enter() { 3301 if (DBG) log(getName() + "\n"); 3302 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 3303 } 3304 @Override 3305 public boolean processMessage(Message message) { 3306 if (DBG) log(getName() + message.toString() + "\n"); 3307 switch (message.what) { 3308 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 3309 if (DBG) log("Watchdog reports poor link"); 3310 try { 3311 mNwService.disableIpv6(mInterfaceName); 3312 } catch (RemoteException re) { 3313 loge("Failed to disable IPv6: " + re); 3314 } catch (IllegalStateException e) { 3315 loge("Failed to disable IPv6: " + e); 3316 } 3317 /* Report a disconnect */ 3318 setNetworkDetailedState(DetailedState.DISCONNECTED); 3319 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 3320 sendNetworkStateChangeBroadcast(mLastBssid); 3321 3322 transitionTo(mVerifyingLinkState); 3323 break; 3324 default: 3325 return NOT_HANDLED; 3326 } 3327 return HANDLED; 3328 } 3329 @Override 3330 public void exit() { 3331 /* Request a CS wakelock during transition to mobile */ 3332 checkAndSetConnectivityInstance(); 3333 mCm.requestNetworkTransitionWakelock(TAG); 3334 } 3335 } 3336 3337 class DisconnectingState extends State { 3338 @Override 3339 public void enter() { 3340 if (DBG) log(getName() + "\n"); 3341 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 3342 } 3343 @Override 3344 public boolean processMessage(Message message) { 3345 if (DBG) log(getName() + message.toString() + "\n"); 3346 switch (message.what) { 3347 case CMD_SET_SCAN_MODE: 3348 if (message.arg1 == SCAN_ONLY_MODE) { 3349 deferMessage(message); 3350 } 3351 break; 3352 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3353 /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT 3354 * we have missed the network disconnection, transition to mDisconnectedState 3355 * and handle the rest of the events there 3356 */ 3357 deferMessage(message); 3358 handleNetworkDisconnect(); 3359 transitionTo(mDisconnectedState); 3360 break; 3361 default: 3362 return NOT_HANDLED; 3363 } 3364 return HANDLED; 3365 } 3366 } 3367 3368 class DisconnectedState extends State { 3369 private boolean mAlarmEnabled = false; 3370 /* This is set from the overlay config file or from a secure setting. 3371 * A value of 0 disables scanning in the framework. 3372 */ 3373 private long mFrameworkScanIntervalMs; 3374 3375 private void setScanAlarm(boolean enabled) { 3376 if (enabled == mAlarmEnabled) return; 3377 if (enabled) { 3378 if (mFrameworkScanIntervalMs > 0) { 3379 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 3380 System.currentTimeMillis() + mFrameworkScanIntervalMs, 3381 mFrameworkScanIntervalMs, 3382 mScanIntent); 3383 mAlarmEnabled = true; 3384 } 3385 } else { 3386 mAlarmManager.cancel(mScanIntent); 3387 mAlarmEnabled = false; 3388 } 3389 } 3390 3391 @Override 3392 public void enter() { 3393 if (DBG) log(getName() + "\n"); 3394 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 3395 3396 mFrameworkScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(), 3397 Settings.Secure.WIFI_FRAMEWORK_SCAN_INTERVAL_MS, 3398 mDefaultFrameworkScanIntervalMs); 3399 /* 3400 * We initiate background scanning if it is enabled, otherwise we 3401 * initiate an infrequent scan that wakes up the device to ensure 3402 * a user connects to an access point on the move 3403 */ 3404 if (mEnableBackgroundScan) { 3405 /* If a regular scan result is pending, do not initiate background 3406 * scan until the scan results are returned. This is needed because 3407 * initiating a background scan will cancel the regular scan and 3408 * scan results will not be returned until background scanning is 3409 * cleared 3410 */ 3411 if (!mScanResultIsPending) { 3412 mWifiNative.enableBackgroundScan(true); 3413 } 3414 } else { 3415 setScanAlarm(true); 3416 } 3417 3418 /** 3419 * If we have no networks saved, the supplicant stops doing the periodic scan. 3420 * The scans are useful to notify the user of the presence of an open network. 3421 * Note that these are not wake up scans. 3422 */ 3423 if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { 3424 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 3425 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 3426 } 3427 } 3428 @Override 3429 public boolean processMessage(Message message) { 3430 if (DBG) log(getName() + message.toString() + "\n"); 3431 boolean ret = HANDLED; 3432 switch (message.what) { 3433 case CMD_NO_NETWORKS_PERIODIC_SCAN: 3434 if (message.arg1 == mPeriodicScanToken && 3435 mWifiConfigStore.getConfiguredNetworks().size() == 0) { 3436 sendMessage(CMD_START_SCAN); 3437 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 3438 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 3439 } 3440 break; 3441 case WifiManager.FORGET_NETWORK: 3442 case CMD_REMOVE_NETWORK: 3443 // Set up a delayed message here. After the forget/remove is handled 3444 // the handled delayed message will determine if there is a need to 3445 // scan and continue 3446 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 3447 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 3448 ret = NOT_HANDLED; 3449 break; 3450 case CMD_SET_SCAN_MODE: 3451 if (message.arg1 == SCAN_ONLY_MODE) { 3452 mWifiNative.setScanResultHandling(message.arg1); 3453 //Supplicant disconnect to prevent further connects 3454 mWifiNative.disconnect(); 3455 mIsScanMode = true; 3456 transitionTo(mScanModeState); 3457 } 3458 break; 3459 case CMD_ENABLE_BACKGROUND_SCAN: 3460 mEnableBackgroundScan = (message.arg1 == 1); 3461 if (mEnableBackgroundScan) { 3462 mWifiNative.enableBackgroundScan(true); 3463 setScanAlarm(false); 3464 } else { 3465 mWifiNative.enableBackgroundScan(false); 3466 setScanAlarm(true); 3467 } 3468 break; 3469 /* Ignore network disconnect */ 3470 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 3471 break; 3472 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3473 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 3474 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 3475 /* ConnectModeState does the rest of the handling */ 3476 ret = NOT_HANDLED; 3477 break; 3478 case CMD_START_SCAN: 3479 /* Disable background scan temporarily during a regular scan */ 3480 if (mEnableBackgroundScan) { 3481 mWifiNative.enableBackgroundScan(false); 3482 } 3483 /* Handled in parent state */ 3484 ret = NOT_HANDLED; 3485 break; 3486 case WifiMonitor.SCAN_RESULTS_EVENT: 3487 /* Re-enable background scan when a pending scan result is received */ 3488 if (mEnableBackgroundScan && mScanResultIsPending) { 3489 mWifiNative.enableBackgroundScan(true); 3490 } 3491 /* Handled in parent state */ 3492 ret = NOT_HANDLED; 3493 break; 3494 default: 3495 ret = NOT_HANDLED; 3496 } 3497 return ret; 3498 } 3499 3500 @Override 3501 public void exit() { 3502 /* No need for a background scan upon exit from a disconnected state */ 3503 if (mEnableBackgroundScan) { 3504 mWifiNative.enableBackgroundScan(false); 3505 } 3506 setScanAlarm(false); 3507 } 3508 } 3509 3510 class WpsRunningState extends State { 3511 //Tracks the source to provide a reply 3512 private Message mSourceMessage; 3513 @Override 3514 public void enter() { 3515 if (DBG) log(getName() + "\n"); 3516 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 3517 mSourceMessage = Message.obtain(getCurrentMessage()); 3518 } 3519 @Override 3520 public boolean processMessage(Message message) { 3521 if (DBG) log(getName() + message.toString() + "\n"); 3522 switch (message.what) { 3523 case WifiMonitor.WPS_SUCCESS_EVENT: 3524 replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED); 3525 mSourceMessage.recycle(); 3526 mSourceMessage = null; 3527 transitionTo(mDisconnectedState); 3528 break; 3529 case WifiMonitor.WPS_OVERLAP_EVENT: 3530 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 3531 WifiManager.WPS_OVERLAP_ERROR); 3532 mSourceMessage.recycle(); 3533 mSourceMessage = null; 3534 transitionTo(mDisconnectedState); 3535 break; 3536 case WifiMonitor.WPS_FAIL_EVENT: 3537 //arg1 has the reason for the failure 3538 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1); 3539 mSourceMessage.recycle(); 3540 mSourceMessage = null; 3541 transitionTo(mDisconnectedState); 3542 break; 3543 case WifiMonitor.WPS_TIMEOUT_EVENT: 3544 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 3545 WifiManager.WPS_TIMED_OUT); 3546 mSourceMessage.recycle(); 3547 mSourceMessage = null; 3548 transitionTo(mDisconnectedState); 3549 break; 3550 case WifiManager.START_WPS: 3551 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS); 3552 break; 3553 case WifiManager.CANCEL_WPS: 3554 if (mWifiNative.cancelWps()) { 3555 replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED); 3556 } else { 3557 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR); 3558 } 3559 transitionTo(mDisconnectedState); 3560 break; 3561 /* Defer all commands that can cause connections to a different network 3562 * or put the state machine out of connect mode 3563 */ 3564 case CMD_STOP_DRIVER: 3565 case CMD_SET_SCAN_MODE: 3566 case WifiManager.CONNECT_NETWORK: 3567 case CMD_ENABLE_NETWORK: 3568 case CMD_RECONNECT: 3569 case CMD_REASSOCIATE: 3570 case WifiMonitor.NETWORK_CONNECTION_EVENT: /* Handled after exiting WPS state */ 3571 deferMessage(message); 3572 break; 3573 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 3574 if (DBG) log("Network connection lost"); 3575 handleNetworkDisconnect(); 3576 break; 3577 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 3578 // EAP failures do not mean much during WPS 3579 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3580 //Throw away supplicant state changes when WPS is running. 3581 //We will start getting supplicant state changes once we get 3582 //a WPS success or failure 3583 break; 3584 default: 3585 return NOT_HANDLED; 3586 } 3587 return HANDLED; 3588 } 3589 3590 @Override 3591 public void exit() { 3592 mWifiConfigStore.enableAllNetworks(); 3593 mWifiConfigStore.loadConfiguredNetworks(); 3594 } 3595 } 3596 3597 class SoftApStartingState extends State { 3598 @Override 3599 public void enter() { 3600 if (DBG) log(getName() + "\n"); 3601 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 3602 3603 final Message message = getCurrentMessage(); 3604 if (message.what == CMD_START_AP) { 3605 final WifiConfiguration config = (WifiConfiguration) message.obj; 3606 3607 if (config == null) { 3608 mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); 3609 } else { 3610 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 3611 startSoftApWithConfig(config); 3612 } 3613 } else { 3614 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); 3615 } 3616 } 3617 @Override 3618 public boolean processMessage(Message message) { 3619 if (DBG) log(getName() + message.toString() + "\n"); 3620 switch(message.what) { 3621 case CMD_LOAD_DRIVER: 3622 case CMD_UNLOAD_DRIVER: 3623 case CMD_START_SUPPLICANT: 3624 case CMD_STOP_SUPPLICANT: 3625 case CMD_START_AP: 3626 case CMD_STOP_AP: 3627 case CMD_START_DRIVER: 3628 case CMD_STOP_DRIVER: 3629 case CMD_SET_SCAN_MODE: 3630 case CMD_SET_SCAN_TYPE: 3631 case CMD_SET_COUNTRY_CODE: 3632 case CMD_SET_FREQUENCY_BAND: 3633 case CMD_START_PACKET_FILTERING: 3634 case CMD_STOP_PACKET_FILTERING: 3635 case CMD_TETHER_STATE_CHANGE: 3636 deferMessage(message); 3637 break; 3638 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: 3639 WifiConfiguration config = (WifiConfiguration) message.obj; 3640 if (config != null) { 3641 startSoftApWithConfig(config); 3642 } else { 3643 loge("Softap config is null!"); 3644 sendMessage(CMD_START_AP_FAILURE); 3645 } 3646 break; 3647 case CMD_START_AP_SUCCESS: 3648 setWifiApState(WIFI_AP_STATE_ENABLED); 3649 transitionTo(mSoftApStartedState); 3650 break; 3651 case CMD_START_AP_FAILURE: 3652 // initiate driver unload 3653 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0)); 3654 break; 3655 default: 3656 return NOT_HANDLED; 3657 } 3658 return HANDLED; 3659 } 3660 } 3661 3662 class SoftApStartedState extends State { 3663 @Override 3664 public void enter() { 3665 if (DBG) log(getName() + "\n"); 3666 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 3667 } 3668 @Override 3669 public boolean processMessage(Message message) { 3670 if (DBG) log(getName() + message.toString() + "\n"); 3671 switch(message.what) { 3672 case CMD_STOP_AP: 3673 if (DBG) log("Stopping Soft AP"); 3674 setWifiApState(WIFI_AP_STATE_DISABLING); 3675 3676 /* We have not tethered at this point, so we just shutdown soft Ap */ 3677 try { 3678 mNwService.stopAccessPoint(mInterfaceName); 3679 } catch(Exception e) { 3680 loge("Exception in stopAccessPoint()"); 3681 } 3682 transitionTo(mDriverLoadedState); 3683 break; 3684 case CMD_START_AP: 3685 // Ignore a start on a running access point 3686 break; 3687 /* Fail client mode operation when soft AP is enabled */ 3688 case CMD_START_SUPPLICANT: 3689 loge("Cannot start supplicant with a running soft AP"); 3690 setWifiState(WIFI_STATE_UNKNOWN); 3691 break; 3692 case CMD_TETHER_STATE_CHANGE: 3693 TetherStateChange stateChange = (TetherStateChange) message.obj; 3694 if (startTethering(stateChange.available)) { 3695 transitionTo(mTetheringState); 3696 } 3697 break; 3698 default: 3699 return NOT_HANDLED; 3700 } 3701 return HANDLED; 3702 } 3703 } 3704 3705 class TetheringState extends State { 3706 @Override 3707 public void enter() { 3708 if (DBG) log(getName() + "\n"); 3709 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 3710 3711 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 3712 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 3713 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 3714 } 3715 @Override 3716 public boolean processMessage(Message message) { 3717 if (DBG) log(getName() + message.toString() + "\n"); 3718 switch(message.what) { 3719 case CMD_TETHER_STATE_CHANGE: 3720 TetherStateChange stateChange = (TetherStateChange) message.obj; 3721 if (isWifiTethered(stateChange.active)) { 3722 transitionTo(mTetheredState); 3723 } 3724 return HANDLED; 3725 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 3726 if (message.arg1 == mTetherToken) { 3727 loge("Failed to get tether update, shutdown soft access point"); 3728 setWifiApEnabled(null, false); 3729 } 3730 break; 3731 case CMD_LOAD_DRIVER: 3732 case CMD_UNLOAD_DRIVER: 3733 case CMD_START_SUPPLICANT: 3734 case CMD_STOP_SUPPLICANT: 3735 case CMD_START_AP: 3736 case CMD_STOP_AP: 3737 case CMD_START_DRIVER: 3738 case CMD_STOP_DRIVER: 3739 case CMD_SET_SCAN_MODE: 3740 case CMD_SET_SCAN_TYPE: 3741 case CMD_SET_COUNTRY_CODE: 3742 case CMD_SET_FREQUENCY_BAND: 3743 case CMD_START_PACKET_FILTERING: 3744 case CMD_STOP_PACKET_FILTERING: 3745 deferMessage(message); 3746 break; 3747 default: 3748 return NOT_HANDLED; 3749 } 3750 return HANDLED; 3751 } 3752 } 3753 3754 class TetheredState extends State { 3755 @Override 3756 public void enter() { 3757 if (DBG) log(getName() + "\n"); 3758 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 3759 } 3760 @Override 3761 public boolean processMessage(Message message) { 3762 if (DBG) log(getName() + message.toString() + "\n"); 3763 switch(message.what) { 3764 case CMD_TETHER_STATE_CHANGE: 3765 TetherStateChange stateChange = (TetherStateChange) message.obj; 3766 if (!isWifiTethered(stateChange.active)) { 3767 loge("Tethering reports wifi as untethered!, shut down soft Ap"); 3768 setWifiApEnabled(null, false); 3769 } 3770 return HANDLED; 3771 case CMD_STOP_AP: 3772 if (DBG) log("Untethering before stopping AP"); 3773 setWifiApState(WIFI_AP_STATE_DISABLING); 3774 stopTethering(); 3775 transitionTo(mSoftApStoppingState); 3776 break; 3777 default: 3778 return NOT_HANDLED; 3779 } 3780 return HANDLED; 3781 } 3782 } 3783 3784 class SoftApStoppingState extends State { 3785 @Override 3786 public void enter() { 3787 if (DBG) log(getName() + "\n"); 3788 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 3789 3790 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 3791 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 3792 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 3793 3794 } 3795 @Override 3796 public boolean processMessage(Message message) { 3797 if (DBG) log(getName() + message.toString() + "\n"); 3798 switch(message.what) { 3799 case CMD_TETHER_STATE_CHANGE: 3800 TetherStateChange stateChange = (TetherStateChange) message.obj; 3801 3802 /* Wait till wifi is untethered */ 3803 if (isWifiTethered(stateChange.active)) break; 3804 3805 try { 3806 mNwService.stopAccessPoint(mInterfaceName); 3807 } catch(Exception e) { 3808 loge("Exception in stopAccessPoint()"); 3809 } 3810 transitionTo(mDriverLoadedState); 3811 break; 3812 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 3813 if (message.arg1 == mTetherToken) { 3814 loge("Failed to get tether update, force stop access point"); 3815 try { 3816 mNwService.stopAccessPoint(mInterfaceName); 3817 } catch(Exception e) { 3818 loge("Exception in stopAccessPoint()"); 3819 } 3820 transitionTo(mDriverLoadedState); 3821 } 3822 break; 3823 case CMD_LOAD_DRIVER: 3824 case CMD_UNLOAD_DRIVER: 3825 case CMD_START_SUPPLICANT: 3826 case CMD_STOP_SUPPLICANT: 3827 case CMD_START_AP: 3828 case CMD_STOP_AP: 3829 case CMD_START_DRIVER: 3830 case CMD_STOP_DRIVER: 3831 case CMD_SET_SCAN_MODE: 3832 case CMD_SET_SCAN_TYPE: 3833 case CMD_SET_COUNTRY_CODE: 3834 case CMD_SET_FREQUENCY_BAND: 3835 case CMD_START_PACKET_FILTERING: 3836 case CMD_STOP_PACKET_FILTERING: 3837 deferMessage(message); 3838 break; 3839 default: 3840 return NOT_HANDLED; 3841 } 3842 return HANDLED; 3843 } 3844 } 3845 3846 //State machine initiated requests can have replyTo set to null indicating 3847 //there are no recepients, we ignore those reply actions 3848 private void replyToMessage(Message msg, int what) { 3849 if (msg.replyTo == null) return; 3850 Message dstMsg = obtainMessageWithArg2(msg); 3851 dstMsg.what = what; 3852 mReplyChannel.replyToMessage(msg, dstMsg); 3853 } 3854 3855 private void replyToMessage(Message msg, int what, int arg1) { 3856 if (msg.replyTo == null) return; 3857 Message dstMsg = obtainMessageWithArg2(msg); 3858 dstMsg.what = what; 3859 dstMsg.arg1 = arg1; 3860 mReplyChannel.replyToMessage(msg, dstMsg); 3861 } 3862 3863 private void replyToMessage(Message msg, int what, Object obj) { 3864 if (msg.replyTo == null) return; 3865 Message dstMsg = obtainMessageWithArg2(msg); 3866 dstMsg.what = what; 3867 dstMsg.obj = obj; 3868 mReplyChannel.replyToMessage(msg, dstMsg); 3869 } 3870 3871 /** 3872 * arg2 on the source message has a unique id that needs to be retained in replies 3873 * to match the request 3874 * 3875 * see WifiManager for details 3876 */ 3877 private Message obtainMessageWithArg2(Message srcMsg) { 3878 Message msg = Message.obtain(); 3879 msg.arg2 = srcMsg.arg2; 3880 return msg; 3881 } 3882 3883 private void log(String s) { 3884 Log.d(TAG, s); 3885 } 3886 3887 private void loge(String s) { 3888 Log.e(TAG, s); 3889 } 3890} 3891