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