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