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