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