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