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