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