WifiStateMachine.java revision f6307820c88e694e102824225b9d8caa6de75a30
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.RssiPacketCountInfo; 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 WifiManager.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(mTetherInterfaceName); 1259 if (ifcg != null) { 1260 ifcg.setLinkAddress( 1261 new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); 1262 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg); 1263 } 1264 } catch (Exception e) { 1265 loge("Error resetting interface " + mTetherInterfaceName + ", :" + 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(RssiPacketCountInfo info) { 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 info.txgood = Integer.parseInt(prop[1]); 1557 } else if (prop[0].equals("TXBAD")) { 1558 info.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 WifiManager.RSSI_PKTCNT_FETCH: 1976 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED, 1977 WifiManager.BUSY); 1978 break; 1979 default: 1980 loge("Error! unhandled message" + message); 1981 break; 1982 } 1983 return HANDLED; 1984 } 1985 } 1986 1987 class InitialState extends State { 1988 @Override 1989 //TODO: could move logging into a common class 1990 public void enter() { 1991 if (DBG) log(getName() + "\n"); 1992 // [31-8] Reserved for future use 1993 // [7 - 0] HSM state change 1994 // 50021 wifi_state_changed (custom|1|5) 1995 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1996 1997 if (mWifiNative.isDriverLoaded()) { 1998 transitionTo(mDriverLoadedState); 1999 } 2000 else { 2001 transitionTo(mDriverUnloadedState); 2002 } 2003 2004 //Connect to WifiP2pService 2005 mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE); 2006 mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger()); 2007 2008 /* IPv6 is disabled at boot time and is controlled by framework 2009 * to be enabled only as long as we are connected to an access point 2010 * 2011 * This fixes issues, a few being: 2012 * - IPv6 addresses and routes stick around after disconnection 2013 * - When connected, the kernel is unaware and can fail to start IPv6 negotiation 2014 * - The kernel sometimes starts autoconfiguration when 802.1x is not complete 2015 */ 2016 try { 2017 mNwService.disableIpv6(mInterfaceName); 2018 } catch (RemoteException re) { 2019 loge("Failed to disable IPv6: " + re); 2020 } catch (IllegalStateException e) { 2021 loge("Failed to disable IPv6: " + e); 2022 } 2023 } 2024 } 2025 2026 class DriverLoadingState extends State { 2027 @Override 2028 public void enter() { 2029 if (DBG) log(getName() + "\n"); 2030 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2031 2032 final Message message = new Message(); 2033 message.copyFrom(getCurrentMessage()); 2034 /* TODO: add a timeout to fail when driver load is hung. 2035 * Similarly for driver unload. 2036 */ 2037 new Thread(new Runnable() { 2038 public void run() { 2039 mWakeLock.acquire(); 2040 //enabling state 2041 switch(message.arg1) { 2042 case WIFI_STATE_ENABLING: 2043 setWifiState(WIFI_STATE_ENABLING); 2044 break; 2045 case WIFI_AP_STATE_ENABLING: 2046 setWifiApState(WIFI_AP_STATE_ENABLING); 2047 break; 2048 } 2049 2050 if(mWifiNative.loadDriver()) { 2051 if (DBG) log("Driver load successful"); 2052 sendMessage(CMD_LOAD_DRIVER_SUCCESS); 2053 } else { 2054 loge("Failed to load driver!"); 2055 switch(message.arg1) { 2056 case WIFI_STATE_ENABLING: 2057 setWifiState(WIFI_STATE_UNKNOWN); 2058 break; 2059 case WIFI_AP_STATE_ENABLING: 2060 setWifiApState(WIFI_AP_STATE_FAILED); 2061 break; 2062 } 2063 sendMessage(CMD_LOAD_DRIVER_FAILURE); 2064 } 2065 mWakeLock.release(); 2066 } 2067 }).start(); 2068 } 2069 2070 @Override 2071 public boolean processMessage(Message message) { 2072 if (DBG) log(getName() + message.toString() + "\n"); 2073 switch (message.what) { 2074 case CMD_LOAD_DRIVER_SUCCESS: 2075 transitionTo(mDriverLoadedState); 2076 break; 2077 case CMD_LOAD_DRIVER_FAILURE: 2078 transitionTo(mDriverFailedState); 2079 break; 2080 case CMD_LOAD_DRIVER: 2081 case CMD_UNLOAD_DRIVER: 2082 case CMD_START_SUPPLICANT: 2083 case CMD_STOP_SUPPLICANT: 2084 case CMD_START_AP: 2085 case CMD_STOP_AP: 2086 case CMD_START_DRIVER: 2087 case CMD_STOP_DRIVER: 2088 case CMD_SET_SCAN_MODE: 2089 case CMD_SET_SCAN_TYPE: 2090 case CMD_SET_COUNTRY_CODE: 2091 case CMD_SET_FREQUENCY_BAND: 2092 case CMD_START_PACKET_FILTERING: 2093 case CMD_STOP_PACKET_FILTERING: 2094 deferMessage(message); 2095 break; 2096 default: 2097 return NOT_HANDLED; 2098 } 2099 return HANDLED; 2100 } 2101 } 2102 2103 class DriverLoadedState extends State { 2104 @Override 2105 public void enter() { 2106 if (DBG) log(getName() + "\n"); 2107 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2108 } 2109 @Override 2110 public boolean processMessage(Message message) { 2111 if (DBG) log(getName() + message.toString() + "\n"); 2112 switch(message.what) { 2113 case CMD_UNLOAD_DRIVER: 2114 transitionTo(mDriverUnloadingState); 2115 break; 2116 case CMD_START_SUPPLICANT: 2117 try { 2118 mNwService.wifiFirmwareReload(mInterfaceName, "STA"); 2119 } catch (Exception e) { 2120 loge("Failed to reload STA firmware " + e); 2121 // continue 2122 } 2123 try { 2124 //A runtime crash can leave the interface up and 2125 //this affects connectivity when supplicant starts up. 2126 //Ensure interface is down before a supplicant start. 2127 mNwService.setInterfaceDown(mInterfaceName); 2128 //Set privacy extensions 2129 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); 2130 } catch (RemoteException re) { 2131 loge("Unable to change interface settings: " + re); 2132 } catch (IllegalStateException ie) { 2133 loge("Unable to change interface settings: " + ie); 2134 } 2135 2136 if(mWifiNative.startSupplicant(mP2pSupported)) { 2137 if (DBG) log("Supplicant start successful"); 2138 mWifiMonitor.startMonitoring(); 2139 transitionTo(mSupplicantStartingState); 2140 } else { 2141 loge("Failed to start supplicant!"); 2142 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0)); 2143 } 2144 break; 2145 case CMD_START_AP: 2146 transitionTo(mSoftApStartingState); 2147 break; 2148 default: 2149 return NOT_HANDLED; 2150 } 2151 return HANDLED; 2152 } 2153 } 2154 2155 class DriverUnloadingState extends State { 2156 @Override 2157 public void enter() { 2158 if (DBG) log(getName() + "\n"); 2159 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2160 2161 final Message message = new Message(); 2162 message.copyFrom(getCurrentMessage()); 2163 new Thread(new Runnable() { 2164 public void run() { 2165 if (DBG) log(getName() + message.toString() + "\n"); 2166 mWakeLock.acquire(); 2167 if(mWifiNative.unloadDriver()) { 2168 if (DBG) log("Driver unload successful"); 2169 sendMessage(CMD_UNLOAD_DRIVER_SUCCESS); 2170 2171 switch(message.arg1) { 2172 case WIFI_STATE_DISABLED: 2173 case WIFI_STATE_UNKNOWN: 2174 setWifiState(message.arg1); 2175 break; 2176 case WIFI_AP_STATE_DISABLED: 2177 case WIFI_AP_STATE_FAILED: 2178 setWifiApState(message.arg1); 2179 break; 2180 } 2181 } else { 2182 loge("Failed to unload driver!"); 2183 sendMessage(CMD_UNLOAD_DRIVER_FAILURE); 2184 2185 switch(message.arg1) { 2186 case WIFI_STATE_DISABLED: 2187 case WIFI_STATE_UNKNOWN: 2188 setWifiState(WIFI_STATE_UNKNOWN); 2189 break; 2190 case WIFI_AP_STATE_DISABLED: 2191 case WIFI_AP_STATE_FAILED: 2192 setWifiApState(WIFI_AP_STATE_FAILED); 2193 break; 2194 } 2195 } 2196 mWakeLock.release(); 2197 } 2198 }).start(); 2199 } 2200 2201 @Override 2202 public boolean processMessage(Message message) { 2203 if (DBG) log(getName() + message.toString() + "\n"); 2204 switch (message.what) { 2205 case CMD_UNLOAD_DRIVER_SUCCESS: 2206 transitionTo(mDriverUnloadedState); 2207 break; 2208 case CMD_UNLOAD_DRIVER_FAILURE: 2209 transitionTo(mDriverFailedState); 2210 break; 2211 case CMD_LOAD_DRIVER: 2212 case CMD_UNLOAD_DRIVER: 2213 case CMD_START_SUPPLICANT: 2214 case CMD_STOP_SUPPLICANT: 2215 case CMD_START_AP: 2216 case CMD_STOP_AP: 2217 case CMD_START_DRIVER: 2218 case CMD_STOP_DRIVER: 2219 case CMD_SET_SCAN_MODE: 2220 case CMD_SET_SCAN_TYPE: 2221 case CMD_SET_COUNTRY_CODE: 2222 case CMD_SET_FREQUENCY_BAND: 2223 case CMD_START_PACKET_FILTERING: 2224 case CMD_STOP_PACKET_FILTERING: 2225 deferMessage(message); 2226 break; 2227 default: 2228 return NOT_HANDLED; 2229 } 2230 return HANDLED; 2231 } 2232 } 2233 2234 class DriverUnloadedState extends State { 2235 @Override 2236 public void enter() { 2237 if (DBG) log(getName() + "\n"); 2238 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2239 } 2240 @Override 2241 public boolean processMessage(Message message) { 2242 if (DBG) log(getName() + message.toString() + "\n"); 2243 switch (message.what) { 2244 case CMD_LOAD_DRIVER: 2245 transitionTo(mDriverLoadingState); 2246 break; 2247 default: 2248 return NOT_HANDLED; 2249 } 2250 return HANDLED; 2251 } 2252 } 2253 2254 class DriverFailedState extends State { 2255 @Override 2256 public void enter() { 2257 loge(getName() + "\n"); 2258 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2259 } 2260 @Override 2261 public boolean processMessage(Message message) { 2262 if (DBG) log(getName() + message.toString() + "\n"); 2263 return NOT_HANDLED; 2264 } 2265 } 2266 2267 2268 class SupplicantStartingState extends State { 2269 @Override 2270 public void enter() { 2271 if (DBG) log(getName() + "\n"); 2272 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2273 } 2274 2275 private void initializeWpsDetails() { 2276 String detail; 2277 detail = SystemProperties.get("ro.product.name", ""); 2278 if (!mWifiNative.setDeviceName(detail)) { 2279 loge("Failed to set device name " + detail); 2280 } 2281 detail = SystemProperties.get("ro.product.manufacturer", ""); 2282 if (!mWifiNative.setManufacturer(detail)) { 2283 loge("Failed to set manufacturer " + detail); 2284 } 2285 detail = SystemProperties.get("ro.product.model", ""); 2286 if (!mWifiNative.setModelName(detail)) { 2287 loge("Failed to set model name " + detail); 2288 } 2289 detail = SystemProperties.get("ro.product.model", ""); 2290 if (!mWifiNative.setModelNumber(detail)) { 2291 loge("Failed to set model number " + detail); 2292 } 2293 detail = SystemProperties.get("ro.serialno", ""); 2294 if (!mWifiNative.setSerialNumber(detail)) { 2295 loge("Failed to set serial number " + detail); 2296 } 2297 if (!mWifiNative.setConfigMethods("physical_display virtual_push_button keypad")) { 2298 loge("Failed to set WPS config methods"); 2299 } 2300 if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) { 2301 loge("Failed to set primary device type " + mPrimaryDeviceType); 2302 } 2303 } 2304 2305 @Override 2306 public boolean processMessage(Message message) { 2307 if (DBG) log(getName() + message.toString() + "\n"); 2308 switch(message.what) { 2309 case WifiMonitor.SUP_CONNECTION_EVENT: 2310 if (DBG) log("Supplicant connection established"); 2311 setWifiState(WIFI_STATE_ENABLED); 2312 mSupplicantRestartCount = 0; 2313 /* Reset the supplicant state to indicate the supplicant 2314 * state is not known at this time */ 2315 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2316 /* Initialize data structures */ 2317 mLastBssid = null; 2318 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 2319 mLastSignalLevel = -1; 2320 2321 mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); 2322 mWifiConfigStore.initialize(); 2323 initializeWpsDetails(); 2324 2325 sendSupplicantConnectionChangedBroadcast(true); 2326 transitionTo(mDriverStartedState); 2327 break; 2328 case WifiMonitor.SUP_DISCONNECTION_EVENT: 2329 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { 2330 loge("Failed to setup control channel, restart supplicant"); 2331 mWifiNative.killSupplicant(); 2332 transitionTo(mDriverLoadedState); 2333 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 2334 } else { 2335 loge("Failed " + mSupplicantRestartCount + 2336 " times to start supplicant, unload driver"); 2337 mSupplicantRestartCount = 0; 2338 transitionTo(mDriverLoadedState); 2339 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0)); 2340 } 2341 break; 2342 case CMD_LOAD_DRIVER: 2343 case CMD_UNLOAD_DRIVER: 2344 case CMD_START_SUPPLICANT: 2345 case CMD_STOP_SUPPLICANT: 2346 case CMD_START_AP: 2347 case CMD_STOP_AP: 2348 case CMD_START_DRIVER: 2349 case CMD_STOP_DRIVER: 2350 case CMD_SET_SCAN_MODE: 2351 case CMD_SET_SCAN_TYPE: 2352 case CMD_SET_COUNTRY_CODE: 2353 case CMD_SET_FREQUENCY_BAND: 2354 case CMD_START_PACKET_FILTERING: 2355 case CMD_STOP_PACKET_FILTERING: 2356 deferMessage(message); 2357 break; 2358 default: 2359 return NOT_HANDLED; 2360 } 2361 return HANDLED; 2362 } 2363 } 2364 2365 class SupplicantStartedState extends State { 2366 @Override 2367 public void enter() { 2368 if (DBG) log(getName() + "\n"); 2369 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2370 /* Initialize for connect mode operation at start */ 2371 mIsScanMode = false; 2372 /* Wifi is available as long as we have a connection to supplicant */ 2373 mNetworkInfo.setIsAvailable(true); 2374 2375 int defaultInterval = mContext.getResources().getInteger( 2376 com.android.internal.R.integer.config_wifi_supplicant_scan_interval); 2377 2378 mSupplicantScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(), 2379 Settings.Secure.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, 2380 defaultInterval); 2381 2382 mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000); 2383 } 2384 @Override 2385 public boolean processMessage(Message message) { 2386 if (DBG) log(getName() + message.toString() + "\n"); 2387 WifiConfiguration config; 2388 switch(message.what) { 2389 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ 2390 transitionTo(mSupplicantStoppingState); 2391 break; 2392 case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ 2393 loge("Connection lost, restart supplicant"); 2394 mWifiNative.killSupplicant(); 2395 mWifiNative.closeSupplicantConnection(); 2396 mNetworkInfo.setIsAvailable(false); 2397 handleNetworkDisconnect(); 2398 sendSupplicantConnectionChangedBroadcast(false); 2399 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2400 transitionTo(mDriverLoadedState); 2401 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 2402 break; 2403 case WifiMonitor.SCAN_RESULTS_EVENT: 2404 setScanResults(mWifiNative.scanResults()); 2405 sendScanResultsAvailableBroadcast(); 2406 mScanResultIsPending = false; 2407 break; 2408 case CMD_PING_SUPPLICANT: 2409 boolean ok = mWifiNative.ping(); 2410 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 2411 break; 2412 case CMD_ADD_OR_UPDATE_NETWORK: 2413 config = (WifiConfiguration) message.obj; 2414 replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, 2415 mWifiConfigStore.addOrUpdateNetwork(config)); 2416 break; 2417 case CMD_REMOVE_NETWORK: 2418 ok = mWifiConfigStore.removeNetwork(message.arg1); 2419 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 2420 break; 2421 case CMD_ENABLE_NETWORK: 2422 ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); 2423 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 2424 break; 2425 case CMD_ENABLE_ALL_NETWORKS: 2426 long time = android.os.SystemClock.elapsedRealtime(); 2427 if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { 2428 mWifiConfigStore.enableAllNetworks(); 2429 mLastEnableAllNetworksTime = time; 2430 } 2431 break; 2432 case WifiManager.DISABLE_NETWORK: 2433 if (mWifiConfigStore.disableNetwork(message.arg1, 2434 WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) { 2435 replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); 2436 } else { 2437 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 2438 WifiManager.ERROR); 2439 } 2440 break; 2441 case CMD_BLACKLIST_NETWORK: 2442 mWifiNative.addToBlacklist((String)message.obj); 2443 break; 2444 case CMD_CLEAR_BLACKLIST: 2445 mWifiNative.clearBlacklist(); 2446 break; 2447 case CMD_SAVE_CONFIG: 2448 ok = mWifiConfigStore.saveConfig(); 2449 replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); 2450 2451 // Inform the backup manager about a data change 2452 IBackupManager ibm = IBackupManager.Stub.asInterface( 2453 ServiceManager.getService(Context.BACKUP_SERVICE)); 2454 if (ibm != null) { 2455 try { 2456 ibm.dataChanged("com.android.providers.settings"); 2457 } catch (Exception e) { 2458 // Try again later 2459 } 2460 } 2461 break; 2462 case CMD_GET_CONFIGURED_NETWORKS: 2463 replyToMessage(message, message.what, 2464 mWifiConfigStore.getConfiguredNetworks()); 2465 break; 2466 /* Cannot start soft AP while in client mode */ 2467 case CMD_START_AP: 2468 loge("Failed to start soft AP with a running supplicant"); 2469 setWifiApState(WIFI_AP_STATE_FAILED); 2470 break; 2471 case CMD_SET_SCAN_MODE: 2472 mIsScanMode = (message.arg1 == SCAN_ONLY_MODE); 2473 break; 2474 case WifiManager.SAVE_NETWORK: 2475 config = (WifiConfiguration) message.obj; 2476 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 2477 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 2478 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 2479 } else { 2480 loge("Failed to save network"); 2481 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 2482 WifiManager.ERROR); 2483 } 2484 break; 2485 case WifiManager.FORGET_NETWORK: 2486 if (mWifiConfigStore.forgetNetwork(message.arg1)) { 2487 replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); 2488 } else { 2489 loge("Failed to forget network"); 2490 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 2491 WifiManager.ERROR); 2492 } 2493 break; 2494 default: 2495 return NOT_HANDLED; 2496 } 2497 return HANDLED; 2498 } 2499 2500 @Override 2501 public void exit() { 2502 mNetworkInfo.setIsAvailable(false); 2503 } 2504 } 2505 2506 class SupplicantStoppingState extends State { 2507 @Override 2508 public void enter() { 2509 if (DBG) log(getName() + "\n"); 2510 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2511 2512 /* Send any reset commands to supplicant before shutting it down */ 2513 handleNetworkDisconnect(); 2514 2515 if (DBG) log("stopping supplicant"); 2516 if (!mWifiNative.stopSupplicant()) { 2517 loge("Failed to stop supplicant"); 2518 } 2519 2520 /* Send ourselves a delayed message to indicate failure after a wait time */ 2521 sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED, 2522 ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS); 2523 2524 mNetworkInfo.setIsAvailable(false); 2525 setWifiState(WIFI_STATE_DISABLING); 2526 sendSupplicantConnectionChangedBroadcast(false); 2527 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2528 } 2529 @Override 2530 public boolean processMessage(Message message) { 2531 if (DBG) log(getName() + message.toString() + "\n"); 2532 switch(message.what) { 2533 case WifiMonitor.SUP_CONNECTION_EVENT: 2534 loge("Supplicant connection received while stopping"); 2535 break; 2536 case WifiMonitor.SUP_DISCONNECTION_EVENT: 2537 if (DBG) log("Supplicant connection lost"); 2538 /* Socket connection can be lost when we do a graceful shutdown 2539 * or when the driver is hung. Ensure supplicant is stopped here. 2540 */ 2541 mWifiNative.killSupplicant(); 2542 mWifiNative.closeSupplicantConnection(); 2543 transitionTo(mDriverLoadedState); 2544 break; 2545 case CMD_STOP_SUPPLICANT_FAILED: 2546 if (message.arg1 == mSupplicantStopFailureToken) { 2547 loge("Timed out on a supplicant stop, kill and proceed"); 2548 mWifiNative.killSupplicant(); 2549 mWifiNative.closeSupplicantConnection(); 2550 transitionTo(mDriverLoadedState); 2551 } 2552 break; 2553 case CMD_LOAD_DRIVER: 2554 case CMD_UNLOAD_DRIVER: 2555 case CMD_START_SUPPLICANT: 2556 case CMD_STOP_SUPPLICANT: 2557 case CMD_START_AP: 2558 case CMD_STOP_AP: 2559 case CMD_START_DRIVER: 2560 case CMD_STOP_DRIVER: 2561 case CMD_SET_SCAN_MODE: 2562 case CMD_SET_SCAN_TYPE: 2563 case CMD_SET_COUNTRY_CODE: 2564 case CMD_SET_FREQUENCY_BAND: 2565 case CMD_START_PACKET_FILTERING: 2566 case CMD_STOP_PACKET_FILTERING: 2567 deferMessage(message); 2568 break; 2569 default: 2570 return NOT_HANDLED; 2571 } 2572 return HANDLED; 2573 } 2574 } 2575 2576 class DriverStartingState extends State { 2577 private int mTries; 2578 @Override 2579 public void enter() { 2580 if (DBG) log(getName() + "\n"); 2581 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2582 2583 mTries = 1; 2584 /* Send ourselves a delayed message to start driver a second time */ 2585 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 2586 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 2587 } 2588 @Override 2589 public boolean processMessage(Message message) { 2590 if (DBG) log(getName() + message.toString() + "\n"); 2591 switch(message.what) { 2592 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2593 SupplicantState state = handleSupplicantStateChange(message); 2594 /* If suplicant is exiting out of INTERFACE_DISABLED state into 2595 * a state that indicates driver has started, it is ready to 2596 * receive driver commands 2597 */ 2598 if (SupplicantState.isDriverActive(state)) { 2599 transitionTo(mDriverStartedState); 2600 } 2601 break; 2602 case CMD_DRIVER_START_TIMED_OUT: 2603 if (message.arg1 == mDriverStartToken) { 2604 if (mTries >= 2) { 2605 loge("Failed to start driver after " + mTries); 2606 transitionTo(mDriverStoppedState); 2607 } else { 2608 loge("Driver start failed, retrying"); 2609 mWakeLock.acquire(); 2610 mWifiNative.startDriver(); 2611 mWakeLock.release(); 2612 2613 ++mTries; 2614 /* Send ourselves a delayed message to start driver again */ 2615 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 2616 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 2617 } 2618 } 2619 break; 2620 /* Queue driver commands & connection events */ 2621 case CMD_START_DRIVER: 2622 case CMD_STOP_DRIVER: 2623 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2624 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2625 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 2626 case WifiMonitor.WPS_OVERLAP_EVENT: 2627 case CMD_SET_SCAN_TYPE: 2628 case CMD_SET_COUNTRY_CODE: 2629 case CMD_SET_FREQUENCY_BAND: 2630 case CMD_START_PACKET_FILTERING: 2631 case CMD_STOP_PACKET_FILTERING: 2632 case CMD_START_SCAN: 2633 case CMD_DISCONNECT: 2634 case CMD_REASSOCIATE: 2635 case CMD_RECONNECT: 2636 deferMessage(message); 2637 break; 2638 default: 2639 return NOT_HANDLED; 2640 } 2641 return HANDLED; 2642 } 2643 } 2644 2645 class DriverStartedState extends State { 2646 @Override 2647 public void enter() { 2648 if (DBG) log(getName() + "\n"); 2649 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2650 2651 mIsRunning = true; 2652 mInDelayedStop = false; 2653 updateBatteryWorkSource(null); 2654 2655 /** 2656 * Enable bluetooth coexistence scan mode when bluetooth connection is active. 2657 * When this mode is on, some of the low-level scan parameters used by the 2658 * driver are changed to reduce interference with bluetooth 2659 */ 2660 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 2661 /* set country code */ 2662 setCountryCode(); 2663 /* set frequency band of operation */ 2664 setFrequencyBand(); 2665 /* initialize network state */ 2666 setNetworkDetailedState(DetailedState.DISCONNECTED); 2667 2668 /* Remove any filtering on Multicast v6 at start */ 2669 mWifiNative.stopFilteringMulticastV6Packets(); 2670 2671 /* Reset Multicast v4 filtering state */ 2672 if (mFilteringMulticastV4Packets.get()) { 2673 mWifiNative.startFilteringMulticastV4Packets(); 2674 } else { 2675 mWifiNative.stopFilteringMulticastV4Packets(); 2676 } 2677 2678 mWifiNative.setPowerSave(mPowerSaveEnabled); 2679 2680 if (mIsScanMode) { 2681 mWifiNative.setScanResultHandling(SCAN_ONLY_MODE); 2682 mWifiNative.disconnect(); 2683 transitionTo(mScanModeState); 2684 } else { 2685 mWifiNative.setScanResultHandling(CONNECT_MODE); 2686 mWifiNative.reconnect(); 2687 // Status pulls in the current supplicant state and network connection state 2688 // events over the monitor connection. This helps framework sync up with 2689 // current supplicant state 2690 mWifiNative.status(); 2691 transitionTo(mDisconnectedState); 2692 } 2693 2694 if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); 2695 2696 mContext.registerReceiver(mScreenReceiver, mScreenFilter); 2697 } 2698 @Override 2699 public boolean processMessage(Message message) { 2700 if (DBG) log(getName() + message.toString() + "\n"); 2701 switch(message.what) { 2702 case CMD_SET_SCAN_TYPE: 2703 mSetScanActive = (message.arg1 == SCAN_ACTIVE); 2704 mWifiNative.setScanMode(mSetScanActive); 2705 break; 2706 case CMD_START_SCAN: 2707 boolean forceActive = (message.arg1 == SCAN_ACTIVE); 2708 if (forceActive && !mSetScanActive) { 2709 mWifiNative.setScanMode(forceActive); 2710 } 2711 mWifiNative.scan(); 2712 if (forceActive && !mSetScanActive) { 2713 mWifiNative.setScanMode(mSetScanActive); 2714 } 2715 mScanResultIsPending = true; 2716 break; 2717 case CMD_SET_COUNTRY_CODE: 2718 String country = (String) message.obj; 2719 if (DBG) log("set country code " + country); 2720 if (!mWifiNative.setCountryCode(country.toUpperCase())) { 2721 loge("Failed to set country code " + country); 2722 } 2723 break; 2724 case CMD_SET_FREQUENCY_BAND: 2725 int band = message.arg1; 2726 if (DBG) log("set frequency band " + band); 2727 if (mWifiNative.setBand(band)) { 2728 mFrequencyBand.set(band); 2729 //Fetch the latest scan results when frequency band is set 2730 startScan(true); 2731 } else { 2732 loge("Failed to set frequency band " + band); 2733 } 2734 break; 2735 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 2736 mBluetoothConnectionActive = (message.arg1 != 2737 BluetoothAdapter.STATE_DISCONNECTED); 2738 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 2739 break; 2740 case CMD_STOP_DRIVER: 2741 int mode = message.arg1; 2742 2743 /* Already doing a delayed stop && not in ecm state */ 2744 if (mInDelayedStop && mode != IN_ECM_STATE) { 2745 if (DBG) log("Already in delayed stop"); 2746 break; 2747 } 2748 mInDelayedStop = true; 2749 mDelayedStopCounter++; 2750 if (DBG) log("Delayed stop message " + mDelayedStopCounter); 2751 2752 if (mode == IN_ECM_STATE) { 2753 /* send a shut down immediately */ 2754 sendMessage(obtainMessage(CMD_DELAYED_STOP_DRIVER, mDelayedStopCounter, 0)); 2755 } else { 2756 /* send regular delayed shut down */ 2757 Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); 2758 driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); 2759 mDriverStopIntent = PendingIntent.getBroadcast(mContext, 2760 DRIVER_STOP_REQUEST, driverStopIntent, 2761 PendingIntent.FLAG_UPDATE_CURRENT); 2762 2763 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 2764 + mDriverStopDelayMs, mDriverStopIntent); 2765 } 2766 break; 2767 case CMD_START_DRIVER: 2768 if (mInDelayedStop) { 2769 mInDelayedStop = false; 2770 mDelayedStopCounter++; 2771 mAlarmManager.cancel(mDriverStopIntent); 2772 if (DBG) log("Delayed stop ignored due to start"); 2773 } 2774 break; 2775 case CMD_DELAYED_STOP_DRIVER: 2776 if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter); 2777 if (message.arg1 != mDelayedStopCounter) break; 2778 if (getCurrentState() != mDisconnectedState) { 2779 mWifiNative.disconnect(); 2780 handleNetworkDisconnect(); 2781 } 2782 mWakeLock.acquire(); 2783 mWifiNative.stopDriver(); 2784 transitionTo(mDriverStoppingState); 2785 mWakeLock.release(); 2786 break; 2787 case CMD_START_PACKET_FILTERING: 2788 if (message.arg1 == MULTICAST_V6) { 2789 mWifiNative.startFilteringMulticastV6Packets(); 2790 } else if (message.arg1 == MULTICAST_V4) { 2791 mWifiNative.startFilteringMulticastV4Packets(); 2792 } else { 2793 loge("Illegal arugments to CMD_START_PACKET_FILTERING"); 2794 } 2795 break; 2796 case CMD_STOP_PACKET_FILTERING: 2797 if (message.arg1 == MULTICAST_V6) { 2798 mWifiNative.stopFilteringMulticastV6Packets(); 2799 } else if (message.arg1 == MULTICAST_V4) { 2800 mWifiNative.stopFilteringMulticastV4Packets(); 2801 } else { 2802 loge("Illegal arugments to CMD_STOP_PACKET_FILTERING"); 2803 } 2804 break; 2805 case CMD_SET_SUSPEND_OPTIMIZATIONS: 2806 if (!mHighPerfMode) { 2807 mWifiNative.setSuspendOptimizations(true); 2808 } 2809 mSuspendWakeLock.release(); 2810 break; 2811 case CMD_CLEAR_SUSPEND_OPTIMIZATIONS: 2812 mWifiNative.setSuspendOptimizations(false); 2813 break; 2814 case CMD_SET_HIGH_PERF_MODE: 2815 mHighPerfMode = (message.arg1 == 1); 2816 if (mHighPerfMode) { 2817 //Disable any suspend optimizations 2818 mWifiNative.setSuspendOptimizations(false); 2819 } 2820 break; 2821 default: 2822 return NOT_HANDLED; 2823 } 2824 return HANDLED; 2825 } 2826 @Override 2827 public void exit() { 2828 if (DBG) log(getName() + "\n"); 2829 mIsRunning = false; 2830 updateBatteryWorkSource(null); 2831 mScanResults = null; 2832 2833 if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P); 2834 mContext.unregisterReceiver(mScreenReceiver); 2835 } 2836 } 2837 2838 class DriverStoppingState extends State { 2839 @Override 2840 public void enter() { 2841 if (DBG) log(getName() + "\n"); 2842 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2843 } 2844 @Override 2845 public boolean processMessage(Message message) { 2846 if (DBG) log(getName() + message.toString() + "\n"); 2847 switch(message.what) { 2848 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2849 SupplicantState state = handleSupplicantStateChange(message); 2850 if (state == SupplicantState.INTERFACE_DISABLED) { 2851 transitionTo(mDriverStoppedState); 2852 } 2853 break; 2854 /* Queue driver commands */ 2855 case CMD_START_DRIVER: 2856 case CMD_STOP_DRIVER: 2857 case CMD_SET_SCAN_TYPE: 2858 case CMD_SET_COUNTRY_CODE: 2859 case CMD_SET_FREQUENCY_BAND: 2860 case CMD_START_PACKET_FILTERING: 2861 case CMD_STOP_PACKET_FILTERING: 2862 case CMD_START_SCAN: 2863 case CMD_DISCONNECT: 2864 case CMD_REASSOCIATE: 2865 case CMD_RECONNECT: 2866 deferMessage(message); 2867 break; 2868 default: 2869 return NOT_HANDLED; 2870 } 2871 return HANDLED; 2872 } 2873 } 2874 2875 class DriverStoppedState extends State { 2876 @Override 2877 public void enter() { 2878 if (DBG) log(getName() + "\n"); 2879 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2880 } 2881 @Override 2882 public boolean processMessage(Message message) { 2883 if (DBG) log(getName() + message.toString() + "\n"); 2884 switch (message.what) { 2885 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2886 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 2887 SupplicantState state = stateChangeResult.state; 2888 // A WEXT bug means that we can be back to driver started state 2889 // unexpectedly 2890 if (SupplicantState.isDriverActive(state)) { 2891 transitionTo(mDriverStartedState); 2892 } 2893 break; 2894 case CMD_START_DRIVER: 2895 mWakeLock.acquire(); 2896 mWifiNative.startDriver(); 2897 mWakeLock.release(); 2898 transitionTo(mDriverStartingState); 2899 break; 2900 default: 2901 return NOT_HANDLED; 2902 } 2903 return HANDLED; 2904 } 2905 } 2906 2907 class ScanModeState extends State { 2908 @Override 2909 public void enter() { 2910 if (DBG) log(getName() + "\n"); 2911 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2912 } 2913 @Override 2914 public boolean processMessage(Message message) { 2915 if (DBG) log(getName() + message.toString() + "\n"); 2916 switch(message.what) { 2917 case CMD_SET_SCAN_MODE: 2918 if (message.arg1 == SCAN_ONLY_MODE) { 2919 /* Ignore */ 2920 return HANDLED; 2921 } else { 2922 mWifiNative.setScanResultHandling(message.arg1); 2923 mWifiNative.reconnect(); 2924 mIsScanMode = false; 2925 transitionTo(mDisconnectedState); 2926 } 2927 break; 2928 /* Ignore */ 2929 case CMD_DISCONNECT: 2930 case CMD_RECONNECT: 2931 case CMD_REASSOCIATE: 2932 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2933 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2934 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2935 break; 2936 default: 2937 return NOT_HANDLED; 2938 } 2939 return HANDLED; 2940 } 2941 } 2942 2943 class ConnectModeState extends State { 2944 @Override 2945 public void enter() { 2946 if (DBG) log(getName() + "\n"); 2947 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2948 } 2949 @Override 2950 public boolean processMessage(Message message) { 2951 if (DBG) log(getName() + message.toString() + "\n"); 2952 StateChangeResult stateChangeResult; 2953 switch(message.what) { 2954 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 2955 mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT); 2956 break; 2957 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2958 SupplicantState state = handleSupplicantStateChange(message); 2959 // A driver/firmware hang can now put the interface in a down state. 2960 // We detect the interface going down and recover from it 2961 if (!SupplicantState.isDriverActive(state)) { 2962 if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 2963 handleNetworkDisconnect(); 2964 } 2965 log("Detected an interface down, restart driver"); 2966 transitionTo(mDriverStoppedState); 2967 sendMessage(CMD_START_DRIVER); 2968 break; 2969 } 2970 2971 // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT 2972 // when authentication times out after a successful connection, 2973 // we can figure this from the supplicant state. If supplicant 2974 // state is DISCONNECTED, but the mNetworkInfo says we are not 2975 // disconnected, we need to handle a disconnection 2976 if (state == SupplicantState.DISCONNECTED && 2977 mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 2978 if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect"); 2979 handleNetworkDisconnect(); 2980 transitionTo(mDisconnectedState); 2981 } 2982 break; 2983 /* Do a redundant disconnect without transition */ 2984 case CMD_DISCONNECT: 2985 mWifiNative.disconnect(); 2986 break; 2987 case CMD_RECONNECT: 2988 mWifiNative.reconnect(); 2989 break; 2990 case CMD_REASSOCIATE: 2991 mWifiNative.reassociate(); 2992 break; 2993 case WifiManager.CONNECT_NETWORK: 2994 /* The connect message can contain a network id passed as arg1 on message or 2995 * or a config passed as obj on message. 2996 * For a new network, a config is passed to create and connect. 2997 * For an existing network, a network id is passed 2998 */ 2999 int netId = message.arg1; 3000 WifiConfiguration config = (WifiConfiguration) message.obj; 3001 3002 /* Save the network config */ 3003 if (config != null) { 3004 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 3005 netId = result.getNetworkId(); 3006 } 3007 3008 if (mWifiConfigStore.selectNetwork(netId) && 3009 mWifiNative.reconnect()) { 3010 /* The state tracker handles enabling networks upon completion/failure */ 3011 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 3012 replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 3013 /* Expect a disconnection from the old connection */ 3014 transitionTo(mDisconnectingState); 3015 } else { 3016 loge("Failed to connect config: " + config + " netId: " + netId); 3017 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 3018 WifiManager.ERROR); 3019 break; 3020 } 3021 break; 3022 case WifiManager.START_WPS: 3023 WpsInfo wpsInfo = (WpsInfo) message.obj; 3024 WpsResult result; 3025 switch (wpsInfo.setup) { 3026 case WpsInfo.PBC: 3027 result = mWifiConfigStore.startWpsPbc(wpsInfo); 3028 break; 3029 case WpsInfo.KEYPAD: 3030 result = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); 3031 break; 3032 case WpsInfo.DISPLAY: 3033 result = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); 3034 break; 3035 default: 3036 result = new WpsResult(Status.FAILURE); 3037 Log.e(TAG, "Invalid setup for WPS"); 3038 break; 3039 } 3040 if (result.status == Status.SUCCESS) { 3041 replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, result); 3042 transitionTo(mWpsRunningState); 3043 } else { 3044 Log.e(TAG, "Failed to start WPS with config " + wpsInfo.toString()); 3045 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR); 3046 } 3047 break; 3048 case WifiMonitor.SCAN_RESULTS_EVENT: 3049 /* Set the scan setting back to "connect" mode */ 3050 mWifiNative.setScanResultHandling(CONNECT_MODE); 3051 /* Handle scan results */ 3052 return NOT_HANDLED; 3053 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3054 if (DBG) log("Network connection established"); 3055 mLastNetworkId = message.arg1; 3056 mLastBssid = (String) message.obj; 3057 3058 mWifiInfo.setBSSID(mLastBssid); 3059 mWifiInfo.setNetworkId(mLastNetworkId); 3060 /* send event to CM & network change broadcast */ 3061 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 3062 sendNetworkStateChangeBroadcast(mLastBssid); 3063 transitionTo(mObtainingIpState); 3064 break; 3065 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 3066 if (DBG) log("Network connection lost"); 3067 handleNetworkDisconnect(); 3068 transitionTo(mDisconnectedState); 3069 break; 3070 default: 3071 return NOT_HANDLED; 3072 } 3073 return HANDLED; 3074 } 3075 } 3076 3077 class L2ConnectedState extends State { 3078 @Override 3079 public void enter() { 3080 if (DBG) log(getName() + "\n"); 3081 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 3082 mRssiPollToken++; 3083 if (mEnableRssiPolling) { 3084 sendMessage(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0)); 3085 } 3086 } 3087 3088 @Override 3089 public boolean processMessage(Message message) { 3090 if (DBG) log(getName() + message.toString() + "\n"); 3091 switch (message.what) { 3092 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 3093 handlePreDhcpSetup(); 3094 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE); 3095 break; 3096 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 3097 handlePostDhcpSetup(); 3098 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 3099 if (DBG) log("DHCP successful"); 3100 handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj); 3101 transitionTo(mVerifyingLinkState); 3102 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { 3103 if (DBG) log("DHCP failed"); 3104 handleFailedIpConfiguration(); 3105 transitionTo(mDisconnectingState); 3106 } 3107 break; 3108 case CMD_DISCONNECT: 3109 mWifiNative.disconnect(); 3110 transitionTo(mDisconnectingState); 3111 break; 3112 case CMD_SET_SCAN_MODE: 3113 if (message.arg1 == SCAN_ONLY_MODE) { 3114 sendMessage(CMD_DISCONNECT); 3115 deferMessage(message); 3116 } 3117 break; 3118 case CMD_START_SCAN: 3119 /* When the network is connected, re-scanning can trigger 3120 * a reconnection. Put it in scan-only mode during scan. 3121 * When scan results are received, the mode is switched 3122 * back to CONNECT_MODE. 3123 */ 3124 mWifiNative.setScanResultHandling(SCAN_ONLY_MODE); 3125 /* Have the parent state handle the rest */ 3126 return NOT_HANDLED; 3127 /* Ignore connection to same network */ 3128 case WifiManager.CONNECT_NETWORK: 3129 int netId = message.arg1; 3130 if (mWifiInfo.getNetworkId() == netId) { 3131 break; 3132 } 3133 return NOT_HANDLED; 3134 case WifiManager.SAVE_NETWORK: 3135 WifiConfiguration config = (WifiConfiguration) message.obj; 3136 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 3137 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 3138 if (result.hasIpChanged()) { 3139 log("Reconfiguring IP on connection"); 3140 transitionTo(mObtainingIpState); 3141 } 3142 if (result.hasProxyChanged()) { 3143 log("Reconfiguring proxy on connection"); 3144 configureLinkProperties(); 3145 sendLinkConfigurationChangedBroadcast(); 3146 } 3147 } 3148 3149 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 3150 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 3151 } else { 3152 loge("Failed to save network"); 3153 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 3154 WifiManager.ERROR); 3155 } 3156 break; 3157 /* Ignore */ 3158 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3159 break; 3160 case CMD_RSSI_POLL: 3161 if (message.arg1 == mRssiPollToken) { 3162 // Get Info and continue polling 3163 fetchRssiAndLinkSpeedNative(); 3164 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 3165 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 3166 } else { 3167 // Polling has completed 3168 } 3169 break; 3170 case CMD_ENABLE_RSSI_POLL: 3171 mEnableRssiPolling = (message.arg1 == 1); 3172 mRssiPollToken++; 3173 if (mEnableRssiPolling) { 3174 // first poll 3175 fetchRssiAndLinkSpeedNative(); 3176 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 3177 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 3178 } 3179 break; 3180 case WifiManager.RSSI_PKTCNT_FETCH: 3181 RssiPacketCountInfo info = new RssiPacketCountInfo(); 3182 fetchRssiAndLinkSpeedNative(); 3183 info.rssi = mWifiInfo.getRssi(); 3184 fetchPktcntNative(info); 3185 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info); 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