WifiStateMachine.java revision 81196b207a63bce1a430752db74a65e2a2be6d80
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(); 1115 mWifiConfigStore.dump(fd, pw, args); 1116 } 1117 1118 /********************************************************* 1119 * Internal private functions 1120 ********************************************************/ 1121 1122 private void handleScreenStateChanged(boolean screenOn) { 1123 if (DBG) log("handleScreenStateChanged: " + screenOn); 1124 enableRssiPolling(screenOn); 1125 if (mBackgroundScanSupported) { 1126 enableBackgroundScanCommand(screenOn == false); 1127 } 1128 1129 if (screenOn) enableAllNetworks(); 1130 if (mUserWantsSuspendOpt.get()) { 1131 if (screenOn) { 1132 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0); 1133 } else { 1134 //Allow 2s for suspend optimizations to be set 1135 mSuspendWakeLock.acquire(2000); 1136 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0); 1137 } 1138 } 1139 mScreenBroadcastReceived.set(true); 1140 } 1141 1142 private void checkAndSetConnectivityInstance() { 1143 if (mCm == null) { 1144 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 1145 } 1146 } 1147 1148 private boolean startTethering(ArrayList<String> available) { 1149 1150 boolean wifiAvailable = false; 1151 1152 checkAndSetConnectivityInstance(); 1153 1154 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 1155 1156 for (String intf : available) { 1157 for (String regex : wifiRegexs) { 1158 if (intf.matches(regex)) { 1159 1160 InterfaceConfiguration ifcg = null; 1161 try { 1162 ifcg = mNwService.getInterfaceConfig(intf); 1163 if (ifcg != null) { 1164 /* IP/netmask: 192.168.43.1/255.255.255.0 */ 1165 ifcg.setLinkAddress(new LinkAddress( 1166 NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); 1167 ifcg.setInterfaceUp(); 1168 1169 mNwService.setInterfaceConfig(intf, ifcg); 1170 } 1171 } catch (Exception e) { 1172 loge("Error configuring interface " + intf + ", :" + e); 1173 return false; 1174 } 1175 1176 if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 1177 loge("Error tethering on " + intf); 1178 return false; 1179 } 1180 mTetherInterfaceName = intf; 1181 return true; 1182 } 1183 } 1184 } 1185 // We found no interfaces to tether 1186 return false; 1187 } 1188 1189 private void stopTethering() { 1190 1191 checkAndSetConnectivityInstance(); 1192 1193 /* Clear the interface config to allow dhcp correctly configure new 1194 ip settings */ 1195 InterfaceConfiguration ifcg = null; 1196 try { 1197 ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName); 1198 if (ifcg != null) { 1199 ifcg.setLinkAddress( 1200 new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); 1201 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg); 1202 } 1203 } catch (Exception e) { 1204 loge("Error resetting interface " + mTetherInterfaceName + ", :" + e); 1205 } 1206 1207 if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 1208 loge("Untether initiate failed!"); 1209 } 1210 } 1211 1212 private boolean isWifiTethered(ArrayList<String> active) { 1213 1214 checkAndSetConnectivityInstance(); 1215 1216 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 1217 for (String intf : active) { 1218 for (String regex : wifiRegexs) { 1219 if (intf.matches(regex)) { 1220 return true; 1221 } 1222 } 1223 } 1224 // We found no interfaces that are tethered 1225 return false; 1226 } 1227 1228 /** 1229 * Set the country code from the system setting value, if any. 1230 */ 1231 private void setCountryCode() { 1232 String countryCode = Settings.Global.getString(mContext.getContentResolver(), 1233 Settings.Global.WIFI_COUNTRY_CODE); 1234 if (countryCode != null && !countryCode.isEmpty()) { 1235 setCountryCode(countryCode, false); 1236 } else { 1237 //use driver default 1238 } 1239 } 1240 1241 /** 1242 * Set the frequency band from the system setting value, if any. 1243 */ 1244 private void setFrequencyBand() { 1245 int band = Settings.Global.getInt(mContext.getContentResolver(), 1246 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO); 1247 setFrequencyBand(band, false); 1248 } 1249 1250 private void setSuspendOptimizationsNative(int reason, boolean enabled) { 1251 if (DBG) log("setSuspendOptimizationsNative: " + reason + " " + enabled); 1252 if (enabled) { 1253 mSuspendOptNeedsDisabled &= ~reason; 1254 /* None of dhcp, screen or highperf need it disabled and user wants it enabled */ 1255 if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) { 1256 mWifiNative.setSuspendOptimizations(true); 1257 } 1258 } else { 1259 mSuspendOptNeedsDisabled |= reason; 1260 mWifiNative.setSuspendOptimizations(false); 1261 } 1262 } 1263 1264 private void setSuspendOptimizations(int reason, boolean enabled) { 1265 if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled); 1266 if (enabled) { 1267 mSuspendOptNeedsDisabled &= ~reason; 1268 } else { 1269 mSuspendOptNeedsDisabled |= reason; 1270 } 1271 if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 1272 } 1273 1274 private void setWifiState(int wifiState) { 1275 final int previousWifiState = mWifiState.get(); 1276 1277 try { 1278 if (wifiState == WIFI_STATE_ENABLED) { 1279 mBatteryStats.noteWifiOn(); 1280 } else if (wifiState == WIFI_STATE_DISABLED) { 1281 mBatteryStats.noteWifiOff(); 1282 } 1283 } catch (RemoteException e) { 1284 loge("Failed to note battery stats in wifi"); 1285 } 1286 1287 mWifiState.set(wifiState); 1288 1289 if (DBG) log("setWifiState: " + syncGetWifiStateByName()); 1290 1291 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 1292 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1293 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 1294 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 1295 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1296 } 1297 1298 private void setWifiApState(int wifiApState) { 1299 final int previousWifiApState = mWifiApState.get(); 1300 1301 try { 1302 if (wifiApState == WIFI_AP_STATE_ENABLED) { 1303 mBatteryStats.noteWifiOn(); 1304 } else if (wifiApState == WIFI_AP_STATE_DISABLED) { 1305 mBatteryStats.noteWifiOff(); 1306 } 1307 } catch (RemoteException e) { 1308 loge("Failed to note battery stats in wifi"); 1309 } 1310 1311 // Update state 1312 mWifiApState.set(wifiApState); 1313 1314 if (DBG) log("setWifiApState: " + syncGetWifiApStateByName()); 1315 1316 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 1317 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1318 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); 1319 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); 1320 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1321 } 1322 1323 private static final String ID_STR = "id="; 1324 private static final String BSSID_STR = "bssid="; 1325 private static final String FREQ_STR = "freq="; 1326 private static final String LEVEL_STR = "level="; 1327 private static final String TSF_STR = "tsf="; 1328 private static final String FLAGS_STR = "flags="; 1329 private static final String SSID_STR = "ssid="; 1330 private static final String DELIMITER_STR = "===="; 1331 private static final String END_STR = "####"; 1332 1333 /** 1334 * Format: 1335 * 1336 * id=1 1337 * bssid=68:7f:76:d7:1a:6e 1338 * freq=2412 1339 * level=-44 1340 * tsf=1344626243700342 1341 * flags=[WPA2-PSK-CCMP][WPS][ESS] 1342 * ssid=zfdy 1343 * ==== 1344 * id=2 1345 * bssid=68:5f:74:d7:1a:6f 1346 * freq=5180 1347 * level=-73 1348 * tsf=1344626243700373 1349 * flags=[WPA2-PSK-CCMP][WPS][ESS] 1350 * ssid=zuby 1351 * ==== 1352 */ 1353 private void setScanResults() { 1354 String bssid = ""; 1355 int level = 0; 1356 int freq = 0; 1357 long tsf = 0; 1358 String flags = ""; 1359 WifiSsid wifiSsid = null; 1360 String scanResults; 1361 String tmpResults; 1362 StringBuffer scanResultsBuf = new StringBuffer(); 1363 int sid = 0; 1364 1365 while (true) { 1366 tmpResults = mWifiNative.scanResults(sid); 1367 if (TextUtils.isEmpty(tmpResults)) break; 1368 scanResultsBuf.append(tmpResults); 1369 scanResultsBuf.append("\n"); 1370 String[] lines = tmpResults.split("\n"); 1371 sid = -1; 1372 for (int i=lines.length - 1; i >= 0; i--) { 1373 if (lines[i].startsWith(END_STR)) { 1374 break; 1375 } else if (lines[i].startsWith(ID_STR)) { 1376 try { 1377 sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1; 1378 } catch (NumberFormatException e) { 1379 // Nothing to do 1380 } 1381 break; 1382 } 1383 } 1384 if (sid == -1) break; 1385 } 1386 1387 scanResults = scanResultsBuf.toString(); 1388 if (TextUtils.isEmpty(scanResults)) { 1389 return; 1390 } 1391 1392 synchronized(mScanResultCache) { 1393 mScanResults = new ArrayList<ScanResult>(); 1394 String[] lines = scanResults.split("\n"); 1395 1396 for (String line : lines) { 1397 if (line.startsWith(BSSID_STR)) { 1398 bssid = line.substring(BSSID_STR.length()); 1399 } else if (line.startsWith(FREQ_STR)) { 1400 try { 1401 freq = Integer.parseInt(line.substring(FREQ_STR.length())); 1402 } catch (NumberFormatException e) { 1403 freq = 0; 1404 } 1405 } else if (line.startsWith(LEVEL_STR)) { 1406 try { 1407 level = Integer.parseInt(line.substring(LEVEL_STR.length())); 1408 /* some implementations avoid negative values by adding 256 1409 * so we need to adjust for that here. 1410 */ 1411 if (level > 0) level -= 256; 1412 } catch(NumberFormatException e) { 1413 level = 0; 1414 } 1415 } else if (line.startsWith(TSF_STR)) { 1416 try { 1417 tsf = Long.parseLong(line.substring(TSF_STR.length())); 1418 } catch (NumberFormatException e) { 1419 tsf = 0; 1420 } 1421 } else if (line.startsWith(FLAGS_STR)) { 1422 flags = line.substring(FLAGS_STR.length()); 1423 } else if (line.startsWith(SSID_STR)) { 1424 wifiSsid = WifiSsid.createFromAsciiEncoded( 1425 line.substring(SSID_STR.length())); 1426 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) { 1427 if (bssid != null) { 1428 String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 1429 String key = bssid + ssid; 1430 ScanResult scanResult = mScanResultCache.get(key); 1431 if (scanResult != null) { 1432 scanResult.level = level; 1433 scanResult.wifiSsid = wifiSsid; 1434 // Keep existing API 1435 scanResult.SSID = (wifiSsid != null) ? wifiSsid.toString() : 1436 WifiSsid.NONE; 1437 scanResult.capabilities = flags; 1438 scanResult.frequency = freq; 1439 scanResult.timestamp = tsf; 1440 } else { 1441 scanResult = 1442 new ScanResult( 1443 wifiSsid, bssid, flags, level, freq, tsf); 1444 mScanResultCache.put(key, scanResult); 1445 } 1446 mScanResults.add(scanResult); 1447 } 1448 bssid = null; 1449 level = 0; 1450 freq = 0; 1451 tsf = 0; 1452 flags = ""; 1453 wifiSsid = null; 1454 } 1455 } 1456 } 1457 } 1458 1459 /* 1460 * Fetch RSSI and linkspeed on current connection 1461 */ 1462 private void fetchRssiAndLinkSpeedNative() { 1463 int newRssi = -1; 1464 int newLinkSpeed = -1; 1465 1466 String signalPoll = mWifiNative.signalPoll(); 1467 1468 if (signalPoll != null) { 1469 String[] lines = signalPoll.split("\n"); 1470 for (String line : lines) { 1471 String[] prop = line.split("="); 1472 if (prop.length < 2) continue; 1473 try { 1474 if (prop[0].equals("RSSI")) { 1475 newRssi = Integer.parseInt(prop[1]); 1476 } else if (prop[0].equals("LINKSPEED")) { 1477 newLinkSpeed = Integer.parseInt(prop[1]); 1478 } 1479 } catch (NumberFormatException e) { 1480 //Ignore, defaults on rssi and linkspeed are assigned 1481 } 1482 } 1483 } 1484 1485 if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values 1486 /* some implementations avoid negative values by adding 256 1487 * so we need to adjust for that here. 1488 */ 1489 if (newRssi > 0) newRssi -= 256; 1490 mWifiInfo.setRssi(newRssi); 1491 /* 1492 * Rather then sending the raw RSSI out every time it 1493 * changes, we precalculate the signal level that would 1494 * be displayed in the status bar, and only send the 1495 * broadcast if that much more coarse-grained number 1496 * changes. This cuts down greatly on the number of 1497 * broadcasts, at the cost of not informing others 1498 * interested in RSSI of all the changes in signal 1499 * level. 1500 */ 1501 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); 1502 if (newSignalLevel != mLastSignalLevel) { 1503 sendRssiChangeBroadcast(newRssi); 1504 } 1505 mLastSignalLevel = newSignalLevel; 1506 } else { 1507 mWifiInfo.setRssi(MIN_RSSI); 1508 } 1509 1510 if (newLinkSpeed != -1) { 1511 mWifiInfo.setLinkSpeed(newLinkSpeed); 1512 } 1513 } 1514 1515 /* 1516 * Fetch TX packet counters on current connection 1517 */ 1518 private void fetchPktcntNative(RssiPacketCountInfo info) { 1519 String pktcntPoll = mWifiNative.pktcntPoll(); 1520 1521 if (pktcntPoll != null) { 1522 String[] lines = pktcntPoll.split("\n"); 1523 for (String line : lines) { 1524 String[] prop = line.split("="); 1525 if (prop.length < 2) continue; 1526 try { 1527 if (prop[0].equals("TXGOOD")) { 1528 info.txgood = Integer.parseInt(prop[1]); 1529 } else if (prop[0].equals("TXBAD")) { 1530 info.txbad = Integer.parseInt(prop[1]); 1531 } 1532 } catch (NumberFormatException e) { 1533 //Ignore 1534 } 1535 } 1536 } 1537 } 1538 1539 private void configureLinkProperties() { 1540 if (mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 1541 mLinkProperties = mWifiConfigStore.getLinkProperties(mLastNetworkId); 1542 } else { 1543 synchronized (mDhcpResultsLock) { 1544 if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) { 1545 mLinkProperties = mDhcpResults.linkProperties; 1546 } 1547 } 1548 mLinkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); 1549 } 1550 mLinkProperties.setInterfaceName(mInterfaceName); 1551 if (DBG) log("netId=" + mLastNetworkId + " Link configured: " + mLinkProperties); 1552 } 1553 1554 private int getMaxDhcpRetries() { 1555 return Settings.Global.getInt(mContext.getContentResolver(), 1556 Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, 1557 DEFAULT_MAX_DHCP_RETRIES); 1558 } 1559 1560 private void sendScanResultsAvailableBroadcast() { 1561 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 1562 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1563 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1564 } 1565 1566 private void sendRssiChangeBroadcast(final int newRssi) { 1567 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); 1568 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1569 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); 1570 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1571 } 1572 1573 private void sendNetworkStateChangeBroadcast(String bssid) { 1574 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); 1575 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1576 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 1577 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties)); 1578 if (bssid != null) 1579 intent.putExtra(WifiManager.EXTRA_BSSID, bssid); 1580 if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK || 1581 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { 1582 intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo)); 1583 } 1584 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1585 } 1586 1587 private void sendLinkConfigurationChangedBroadcast() { 1588 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); 1589 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1590 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); 1591 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1592 } 1593 1594 private void sendSupplicantConnectionChangedBroadcast(boolean connected) { 1595 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 1596 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1597 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); 1598 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1599 } 1600 1601 /** 1602 * Record the detailed state of a network. 1603 * @param state the new {@code DetailedState} 1604 */ 1605 private void setNetworkDetailedState(NetworkInfo.DetailedState state) { 1606 if (DBG) { 1607 log("setDetailed state, old =" 1608 + mNetworkInfo.getDetailedState() + " and new state=" + state); 1609 } 1610 1611 if (state != mNetworkInfo.getDetailedState()) { 1612 mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); 1613 } 1614 } 1615 1616 private DetailedState getNetworkDetailedState() { 1617 return mNetworkInfo.getDetailedState(); 1618 } 1619 1620 1621 private SupplicantState handleSupplicantStateChange(Message message) { 1622 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 1623 SupplicantState state = stateChangeResult.state; 1624 // Supplicant state change 1625 // [31-13] Reserved for future use 1626 // [8 - 0] Supplicant state (as defined in SupplicantState.java) 1627 // 50023 supplicant_state_changed (custom|1|5) 1628 mWifiInfo.setSupplicantState(state); 1629 // Network id is only valid when we start connecting 1630 if (SupplicantState.isConnecting(state)) { 1631 mWifiInfo.setNetworkId(stateChangeResult.networkId); 1632 } else { 1633 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 1634 } 1635 1636 mWifiInfo.setBSSID(stateChangeResult.BSSID); 1637 mWifiInfo.setSSID(stateChangeResult.wifiSsid); 1638 1639 mSupplicantStateTracker.sendMessage(Message.obtain(message)); 1640 1641 return state; 1642 } 1643 1644 /** 1645 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 1646 * using the interface, stopping DHCP & disabling interface 1647 */ 1648 private void handleNetworkDisconnect() { 1649 if (DBG) log("Stopping DHCP and clearing IP"); 1650 1651 /* 1652 * stop DHCP 1653 */ 1654 if (mDhcpStateMachine != null) { 1655 /* In case we were in middle of DHCP operation 1656 restore back powermode */ 1657 handlePostDhcpSetup(); 1658 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); 1659 } 1660 1661 try { 1662 mNwService.clearInterfaceAddresses(mInterfaceName); 1663 mNwService.disableIpv6(mInterfaceName); 1664 } catch (Exception e) { 1665 loge("Failed to clear addresses or disable ipv6" + e); 1666 } 1667 1668 /* Reset data structures */ 1669 mWifiInfo.setInetAddress(null); 1670 mWifiInfo.setBSSID(null); 1671 mWifiInfo.setSSID(null); 1672 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 1673 mWifiInfo.setRssi(MIN_RSSI); 1674 mWifiInfo.setLinkSpeed(-1); 1675 mWifiInfo.setMeteredHint(false); 1676 1677 setNetworkDetailedState(DetailedState.DISCONNECTED); 1678 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 1679 1680 /* Clear network properties */ 1681 mLinkProperties.clear(); 1682 1683 /* send event to CM & network change broadcast */ 1684 sendNetworkStateChangeBroadcast(mLastBssid); 1685 1686 /* Clear IP settings if the network used DHCP */ 1687 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 1688 mWifiConfigStore.clearLinkProperties(mLastNetworkId); 1689 } 1690 1691 mLastBssid= null; 1692 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 1693 } 1694 1695 private void handleSupplicantConnectionLoss() { 1696 /* Socket connection can be lost when we do a graceful shutdown 1697 * or when the driver is hung. Ensure supplicant is stopped here. 1698 */ 1699 mWifiNative.killSupplicant(mP2pSupported); 1700 mWifiNative.closeSupplicantConnection(); 1701 sendSupplicantConnectionChangedBroadcast(false); 1702 setWifiState(WIFI_STATE_DISABLED); 1703 } 1704 1705 void handlePreDhcpSetup() { 1706 if (!mBluetoothConnectionActive) { 1707 /* 1708 * There are problems setting the Wi-Fi driver's power 1709 * mode to active when bluetooth coexistence mode is 1710 * enabled or sense. 1711 * <p> 1712 * We set Wi-Fi to active mode when 1713 * obtaining an IP address because we've found 1714 * compatibility issues with some routers with low power 1715 * mode. 1716 * <p> 1717 * In order for this active power mode to properly be set, 1718 * we disable coexistence mode until we're done with 1719 * obtaining an IP address. One exception is if we 1720 * are currently connected to a headset, since disabling 1721 * coexistence would interrupt that connection. 1722 */ 1723 // Disable the coexistence mode 1724 mWifiNative.setBluetoothCoexistenceMode( 1725 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); 1726 } 1727 1728 /* Disable power save and suspend optimizations during DHCP */ 1729 // Note: The order here is important for now. Brcm driver changes 1730 // power settings when we control suspend mode optimizations. 1731 // TODO: Remove this comment when the driver is fixed. 1732 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false); 1733 mWifiNative.setPowerSave(false); 1734 } 1735 1736 1737 void handlePostDhcpSetup() { 1738 /* Restore power save and suspend optimizations */ 1739 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true); 1740 mWifiNative.setPowerSave(true); 1741 1742 // Set the coexistence mode back to its default value 1743 mWifiNative.setBluetoothCoexistenceMode( 1744 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); 1745 } 1746 1747 private void handleSuccessfulIpConfiguration(DhcpResults dhcpResults) { 1748 mLastSignalLevel = -1; // force update of signal strength 1749 mReconnectCount = 0; //Reset IP failure tracking 1750 synchronized (mDhcpResultsLock) { 1751 mDhcpResults = dhcpResults; 1752 } 1753 LinkProperties linkProperties = dhcpResults.linkProperties; 1754 mWifiConfigStore.setLinkProperties(mLastNetworkId, linkProperties); 1755 InetAddress addr = null; 1756 Iterator<InetAddress> addrs = linkProperties.getAddresses().iterator(); 1757 if (addrs.hasNext()) { 1758 addr = addrs.next(); 1759 } 1760 mWifiInfo.setInetAddress(addr); 1761 mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint()); 1762 if (getNetworkDetailedState() == DetailedState.CONNECTED) { 1763 //DHCP renewal in connected state 1764 linkProperties.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); 1765 if (!linkProperties.equals(mLinkProperties)) { 1766 if (DBG) { 1767 log("Link configuration changed for netId: " + mLastNetworkId 1768 + " old: " + mLinkProperties + "new: " + linkProperties); 1769 } 1770 mLinkProperties = linkProperties; 1771 sendLinkConfigurationChangedBroadcast(); 1772 } 1773 } else { 1774 configureLinkProperties(); 1775 } 1776 } 1777 1778 private void handleFailedIpConfiguration() { 1779 loge("IP configuration failed"); 1780 1781 mWifiInfo.setInetAddress(null); 1782 mWifiInfo.setMeteredHint(false); 1783 /** 1784 * If we've exceeded the maximum number of retries for DHCP 1785 * to a given network, disable the network 1786 */ 1787 int maxRetries = getMaxDhcpRetries(); 1788 // maxRetries == 0 means keep trying forever 1789 if (maxRetries > 0 && ++mReconnectCount > maxRetries) { 1790 loge("Failed " + 1791 mReconnectCount + " times, Disabling " + mLastNetworkId); 1792 mWifiConfigStore.disableNetwork(mLastNetworkId, 1793 WifiConfiguration.DISABLED_DHCP_FAILURE); 1794 mReconnectCount = 0; 1795 } 1796 1797 /* DHCP times out after about 30 seconds, we do a 1798 * disconnect and an immediate reconnect to try again 1799 */ 1800 mWifiNative.disconnect(); 1801 mWifiNative.reconnect(); 1802 } 1803 1804 /* Current design is to not set the config on a running hostapd but instead 1805 * stop and start tethering when user changes config on a running access point 1806 * 1807 * TODO: Add control channel setup through hostapd that allows changing config 1808 * on a running daemon 1809 */ 1810 private void startSoftApWithConfig(final WifiConfiguration config) { 1811 // start hostapd on a seperate thread 1812 new Thread(new Runnable() { 1813 public void run() { 1814 try { 1815 mNwService.startAccessPoint(config, mInterfaceName); 1816 } catch (Exception e) { 1817 loge("Exception in softap start " + e); 1818 try { 1819 mNwService.stopAccessPoint(mInterfaceName); 1820 mNwService.startAccessPoint(config, mInterfaceName); 1821 } catch (Exception e1) { 1822 loge("Exception in softap re-start " + e1); 1823 sendMessage(CMD_START_AP_FAILURE); 1824 return; 1825 } 1826 } 1827 if (DBG) log("Soft AP start successful"); 1828 sendMessage(CMD_START_AP_SUCCESS); 1829 } 1830 }).start(); 1831 } 1832 1833 /******************************************************** 1834 * HSM states 1835 *******************************************************/ 1836 1837 class DefaultState extends State { 1838 @Override 1839 public boolean processMessage(Message message) { 1840 switch (message.what) { 1841 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 1842 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 1843 mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 1844 } else { 1845 loge("WifiP2pService connection failure, error=" + message.arg1); 1846 } 1847 break; 1848 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 1849 loge("WifiP2pService channel lost, message.arg1 =" + message.arg1); 1850 //TODO: Re-establish connection to state machine after a delay 1851 //mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger()); 1852 break; 1853 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 1854 mBluetoothConnectionActive = (message.arg1 != 1855 BluetoothAdapter.STATE_DISCONNECTED); 1856 break; 1857 /* Synchronous call returns */ 1858 case CMD_PING_SUPPLICANT: 1859 case CMD_ENABLE_NETWORK: 1860 case CMD_ADD_OR_UPDATE_NETWORK: 1861 case CMD_REMOVE_NETWORK: 1862 case CMD_SAVE_CONFIG: 1863 replyToMessage(message, message.what, FAILURE); 1864 break; 1865 case CMD_GET_CONFIGURED_NETWORKS: 1866 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 1867 break; 1868 case CMD_ENABLE_RSSI_POLL: 1869 mEnableRssiPolling = (message.arg1 == 1); 1870 break; 1871 case CMD_ENABLE_BACKGROUND_SCAN: 1872 mEnableBackgroundScan = (message.arg1 == 1); 1873 break; 1874 case CMD_SET_HIGH_PERF_MODE: 1875 if (message.arg1 == 1) { 1876 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false); 1877 } else { 1878 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true); 1879 } 1880 break; 1881 /* Discard */ 1882 case CMD_START_SUPPLICANT: 1883 case CMD_STOP_SUPPLICANT: 1884 case CMD_STOP_SUPPLICANT_FAILED: 1885 case CMD_START_DRIVER: 1886 case CMD_STOP_DRIVER: 1887 case CMD_DELAYED_STOP_DRIVER: 1888 case CMD_DRIVER_START_TIMED_OUT: 1889 case CMD_CAPTIVE_CHECK_COMPLETE: 1890 case CMD_START_AP: 1891 case CMD_START_AP_SUCCESS: 1892 case CMD_START_AP_FAILURE: 1893 case CMD_STOP_AP: 1894 case CMD_TETHER_STATE_CHANGE: 1895 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 1896 case CMD_START_SCAN: 1897 case CMD_DISCONNECT: 1898 case CMD_RECONNECT: 1899 case CMD_REASSOCIATE: 1900 case WifiMonitor.SUP_CONNECTION_EVENT: 1901 case WifiMonitor.SUP_DISCONNECTION_EVENT: 1902 case WifiMonitor.NETWORK_CONNECTION_EVENT: 1903 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 1904 case WifiMonitor.SCAN_RESULTS_EVENT: 1905 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 1906 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 1907 case WifiMonitor.WPS_OVERLAP_EVENT: 1908 case CMD_BLACKLIST_NETWORK: 1909 case CMD_CLEAR_BLACKLIST: 1910 case CMD_SET_OPERATIONAL_MODE: 1911 case CMD_SET_COUNTRY_CODE: 1912 case CMD_SET_FREQUENCY_BAND: 1913 case CMD_RSSI_POLL: 1914 case CMD_ENABLE_ALL_NETWORKS: 1915 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 1916 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 1917 /* Handled by WifiApConfigStore */ 1918 case CMD_SET_AP_CONFIG: 1919 case CMD_SET_AP_CONFIG_COMPLETED: 1920 case CMD_REQUEST_AP_CONFIG: 1921 case CMD_RESPONSE_AP_CONFIG: 1922 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 1923 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 1924 case CMD_NO_NETWORKS_PERIODIC_SCAN: 1925 case CMD_DISABLE_P2P_RSP: 1926 break; 1927 case DhcpStateMachine.CMD_ON_QUIT: 1928 mDhcpStateMachine = null; 1929 break; 1930 case CMD_SET_SUSPEND_OPT_ENABLED: 1931 if (message.arg1 == 1) { 1932 mSuspendWakeLock.release(); 1933 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true); 1934 } else { 1935 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false); 1936 } 1937 break; 1938 case WifiMonitor.DRIVER_HUNG_EVENT: 1939 setSupplicantRunning(false); 1940 setSupplicantRunning(true); 1941 break; 1942 case WifiManager.CONNECT_NETWORK: 1943 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 1944 WifiManager.BUSY); 1945 break; 1946 case WifiManager.FORGET_NETWORK: 1947 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 1948 WifiManager.BUSY); 1949 break; 1950 case WifiManager.SAVE_NETWORK: 1951 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 1952 WifiManager.BUSY); 1953 break; 1954 case WifiManager.START_WPS: 1955 replyToMessage(message, WifiManager.WPS_FAILED, 1956 WifiManager.BUSY); 1957 break; 1958 case WifiManager.CANCEL_WPS: 1959 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, 1960 WifiManager.BUSY); 1961 break; 1962 case WifiManager.DISABLE_NETWORK: 1963 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 1964 WifiManager.BUSY); 1965 break; 1966 case WifiManager.RSSI_PKTCNT_FETCH: 1967 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED, 1968 WifiManager.BUSY); 1969 break; 1970 case WifiP2pService.P2P_CONNECTION_CHANGED: 1971 NetworkInfo info = (NetworkInfo) message.obj; 1972 mP2pConnected.set(info.isConnected()); 1973 break; 1974 case WifiP2pService.DISCONNECT_WIFI_REQUEST: 1975 mTemporarilyDisconnectWifi = (message.arg1 == 1); 1976 replyToMessage(message, WifiP2pService.DISCONNECT_WIFI_RESPONSE); 1977 break; 1978 default: 1979 loge("Error! unhandled message" + message); 1980 break; 1981 } 1982 return HANDLED; 1983 } 1984 } 1985 1986 class InitialState extends State { 1987 @Override 1988 public void enter() { 1989 mWifiNative.unloadDriver(); 1990 1991 if (mWifiP2pChannel == null) { 1992 mWifiP2pChannel = new AsyncChannel(); 1993 mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger()); 1994 } 1995 1996 if (mWifiApConfigChannel == null) { 1997 mWifiApConfigChannel = new AsyncChannel(); 1998 WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore( 1999 mContext, getHandler()); 2000 wifiApConfigStore.loadApConfiguration(); 2001 mWifiApConfigChannel.connectSync(mContext, getHandler(), 2002 wifiApConfigStore.getMessenger()); 2003 } 2004 } 2005 @Override 2006 public boolean processMessage(Message message) { 2007 switch (message.what) { 2008 case CMD_START_SUPPLICANT: 2009 if (mWifiNative.loadDriver()) { 2010 try { 2011 mNwService.wifiFirmwareReload(mInterfaceName, "STA"); 2012 } catch (Exception e) { 2013 loge("Failed to reload STA firmware " + e); 2014 // continue 2015 } 2016 2017 try { 2018 // A runtime crash can leave the interface up and 2019 // this affects connectivity when supplicant starts up. 2020 // Ensure interface is down before a supplicant start. 2021 mNwService.setInterfaceDown(mInterfaceName); 2022 // Set privacy extensions 2023 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); 2024 2025 // IPv6 is enabled only as long as access point is connected since: 2026 // - IPv6 addresses and routes stick around after disconnection 2027 // - kernel is unaware when connected and fails to start IPv6 negotiation 2028 // - kernel can start autoconfiguration when 802.1x is not complete 2029 mNwService.disableIpv6(mInterfaceName); 2030 } catch (RemoteException re) { 2031 loge("Unable to change interface settings: " + re); 2032 } catch (IllegalStateException ie) { 2033 loge("Unable to change interface settings: " + ie); 2034 } 2035 2036 /* Stop a running supplicant after a runtime restart 2037 * Avoids issues with drivers that do not handle interface down 2038 * on a running supplicant properly. 2039 */ 2040 mWifiNative.killSupplicant(mP2pSupported); 2041 if(mWifiNative.startSupplicant(mP2pSupported)) { 2042 setWifiState(WIFI_STATE_ENABLING); 2043 if (DBG) log("Supplicant start successful"); 2044 mWifiMonitor.startMonitoring(); 2045 transitionTo(mSupplicantStartingState); 2046 } else { 2047 loge("Failed to start supplicant!"); 2048 } 2049 } else { 2050 loge("Failed to load driver"); 2051 } 2052 break; 2053 case CMD_START_AP: 2054 if (mWifiNative.loadDriver()) { 2055 setWifiApState(WIFI_AP_STATE_ENABLING); 2056 transitionTo(mSoftApStartingState); 2057 } else { 2058 loge("Failed to load driver for softap"); 2059 } 2060 default: 2061 return NOT_HANDLED; 2062 } 2063 return HANDLED; 2064 } 2065 } 2066 2067 class SupplicantStartingState extends State { 2068 private void initializeWpsDetails() { 2069 String detail; 2070 detail = SystemProperties.get("ro.product.name", ""); 2071 if (!mWifiNative.setDeviceName(detail)) { 2072 loge("Failed to set device name " + detail); 2073 } 2074 detail = SystemProperties.get("ro.product.manufacturer", ""); 2075 if (!mWifiNative.setManufacturer(detail)) { 2076 loge("Failed to set manufacturer " + detail); 2077 } 2078 detail = SystemProperties.get("ro.product.model", ""); 2079 if (!mWifiNative.setModelName(detail)) { 2080 loge("Failed to set model name " + detail); 2081 } 2082 detail = SystemProperties.get("ro.product.model", ""); 2083 if (!mWifiNative.setModelNumber(detail)) { 2084 loge("Failed to set model number " + detail); 2085 } 2086 detail = SystemProperties.get("ro.serialno", ""); 2087 if (!mWifiNative.setSerialNumber(detail)) { 2088 loge("Failed to set serial number " + detail); 2089 } 2090 if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) { 2091 loge("Failed to set WPS config methods"); 2092 } 2093 if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) { 2094 loge("Failed to set primary device type " + mPrimaryDeviceType); 2095 } 2096 } 2097 2098 @Override 2099 public boolean processMessage(Message message) { 2100 switch(message.what) { 2101 case WifiMonitor.SUP_CONNECTION_EVENT: 2102 if (DBG) log("Supplicant connection established"); 2103 setWifiState(WIFI_STATE_ENABLED); 2104 mSupplicantRestartCount = 0; 2105 /* Reset the supplicant state to indicate the supplicant 2106 * state is not known at this time */ 2107 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2108 /* Initialize data structures */ 2109 mLastBssid = null; 2110 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 2111 mLastSignalLevel = -1; 2112 2113 mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); 2114 mWifiConfigStore.initialize(); 2115 initializeWpsDetails(); 2116 2117 sendSupplicantConnectionChangedBroadcast(true); 2118 transitionTo(mDriverStartedState); 2119 break; 2120 case WifiMonitor.SUP_DISCONNECTION_EVENT: 2121 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { 2122 loge("Failed to setup control channel, restart supplicant"); 2123 mWifiNative.killSupplicant(mP2pSupported); 2124 transitionTo(mInitialState); 2125 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 2126 } else { 2127 loge("Failed " + mSupplicantRestartCount + 2128 " times to start supplicant, unload driver"); 2129 mSupplicantRestartCount = 0; 2130 setWifiState(WIFI_STATE_UNKNOWN); 2131 transitionTo(mInitialState); 2132 } 2133 break; 2134 case CMD_START_SUPPLICANT: 2135 case CMD_STOP_SUPPLICANT: 2136 case CMD_START_AP: 2137 case CMD_STOP_AP: 2138 case CMD_START_DRIVER: 2139 case CMD_STOP_DRIVER: 2140 case CMD_SET_OPERATIONAL_MODE: 2141 case CMD_SET_COUNTRY_CODE: 2142 case CMD_SET_FREQUENCY_BAND: 2143 case CMD_START_PACKET_FILTERING: 2144 case CMD_STOP_PACKET_FILTERING: 2145 deferMessage(message); 2146 break; 2147 default: 2148 return NOT_HANDLED; 2149 } 2150 return HANDLED; 2151 } 2152 } 2153 2154 class SupplicantStartedState extends State { 2155 @Override 2156 public void enter() { 2157 /* Wifi is available as long as we have a connection to supplicant */ 2158 mNetworkInfo.setIsAvailable(true); 2159 2160 int defaultInterval = mContext.getResources().getInteger( 2161 R.integer.config_wifi_supplicant_scan_interval); 2162 2163 mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 2164 Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, 2165 defaultInterval); 2166 2167 mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000); 2168 } 2169 @Override 2170 public boolean processMessage(Message message) { 2171 switch(message.what) { 2172 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ 2173 if (mP2pSupported) { 2174 transitionTo(mWaitForP2pDisableState); 2175 } else { 2176 transitionTo(mSupplicantStoppingState); 2177 } 2178 break; 2179 case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ 2180 loge("Connection lost, restart supplicant"); 2181 handleSupplicantConnectionLoss(); 2182 handleNetworkDisconnect(); 2183 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2184 if (mP2pSupported) { 2185 transitionTo(mWaitForP2pDisableState); 2186 } else { 2187 transitionTo(mInitialState); 2188 } 2189 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 2190 break; 2191 case WifiMonitor.SCAN_RESULTS_EVENT: 2192 setScanResults(); 2193 sendScanResultsAvailableBroadcast(); 2194 mScanResultIsPending = false; 2195 break; 2196 case CMD_PING_SUPPLICANT: 2197 boolean ok = mWifiNative.ping(); 2198 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 2199 break; 2200 /* Cannot start soft AP while in client mode */ 2201 case CMD_START_AP: 2202 loge("Failed to start soft AP with a running supplicant"); 2203 setWifiApState(WIFI_AP_STATE_FAILED); 2204 break; 2205 case CMD_SET_OPERATIONAL_MODE: 2206 mOperationalMode = message.arg1; 2207 break; 2208 default: 2209 return NOT_HANDLED; 2210 } 2211 return HANDLED; 2212 } 2213 2214 @Override 2215 public void exit() { 2216 mNetworkInfo.setIsAvailable(false); 2217 } 2218 } 2219 2220 class SupplicantStoppingState extends State { 2221 @Override 2222 public void enter() { 2223 /* Send any reset commands to supplicant before shutting it down */ 2224 handleNetworkDisconnect(); 2225 if (mDhcpStateMachine != null) { 2226 mDhcpStateMachine.doQuit(); 2227 } 2228 2229 if (DBG) log("stopping supplicant"); 2230 if (!mWifiNative.stopSupplicant()) { 2231 loge("Failed to stop supplicant"); 2232 } 2233 2234 /* Send ourselves a delayed message to indicate failure after a wait time */ 2235 sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED, 2236 ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS); 2237 setWifiState(WIFI_STATE_DISABLING); 2238 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 2239 } 2240 @Override 2241 public boolean processMessage(Message message) { 2242 switch(message.what) { 2243 case WifiMonitor.SUP_CONNECTION_EVENT: 2244 loge("Supplicant connection received while stopping"); 2245 break; 2246 case WifiMonitor.SUP_DISCONNECTION_EVENT: 2247 if (DBG) log("Supplicant connection lost"); 2248 handleSupplicantConnectionLoss(); 2249 transitionTo(mInitialState); 2250 break; 2251 case CMD_STOP_SUPPLICANT_FAILED: 2252 if (message.arg1 == mSupplicantStopFailureToken) { 2253 loge("Timed out on a supplicant stop, kill and proceed"); 2254 handleSupplicantConnectionLoss(); 2255 transitionTo(mInitialState); 2256 } 2257 break; 2258 case CMD_START_SUPPLICANT: 2259 case CMD_STOP_SUPPLICANT: 2260 case CMD_START_AP: 2261 case CMD_STOP_AP: 2262 case CMD_START_DRIVER: 2263 case CMD_STOP_DRIVER: 2264 case CMD_SET_OPERATIONAL_MODE: 2265 case CMD_SET_COUNTRY_CODE: 2266 case CMD_SET_FREQUENCY_BAND: 2267 case CMD_START_PACKET_FILTERING: 2268 case CMD_STOP_PACKET_FILTERING: 2269 deferMessage(message); 2270 break; 2271 default: 2272 return NOT_HANDLED; 2273 } 2274 return HANDLED; 2275 } 2276 } 2277 2278 class DriverStartingState extends State { 2279 private int mTries; 2280 @Override 2281 public void enter() { 2282 mTries = 1; 2283 /* Send ourselves a delayed message to start driver a second time */ 2284 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 2285 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 2286 } 2287 @Override 2288 public boolean processMessage(Message message) { 2289 switch(message.what) { 2290 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2291 SupplicantState state = handleSupplicantStateChange(message); 2292 /* If suplicant is exiting out of INTERFACE_DISABLED state into 2293 * a state that indicates driver has started, it is ready to 2294 * receive driver commands 2295 */ 2296 if (SupplicantState.isDriverActive(state)) { 2297 transitionTo(mDriverStartedState); 2298 } 2299 break; 2300 case CMD_DRIVER_START_TIMED_OUT: 2301 if (message.arg1 == mDriverStartToken) { 2302 if (mTries >= 2) { 2303 loge("Failed to start driver after " + mTries); 2304 transitionTo(mDriverStoppedState); 2305 } else { 2306 loge("Driver start failed, retrying"); 2307 mWakeLock.acquire(); 2308 mWifiNative.startDriver(); 2309 mWakeLock.release(); 2310 2311 ++mTries; 2312 /* Send ourselves a delayed message to start driver again */ 2313 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 2314 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 2315 } 2316 } 2317 break; 2318 /* Queue driver commands & connection events */ 2319 case CMD_START_DRIVER: 2320 case CMD_STOP_DRIVER: 2321 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2322 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2323 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 2324 case WifiMonitor.WPS_OVERLAP_EVENT: 2325 case CMD_SET_COUNTRY_CODE: 2326 case CMD_SET_FREQUENCY_BAND: 2327 case CMD_START_PACKET_FILTERING: 2328 case CMD_STOP_PACKET_FILTERING: 2329 case CMD_START_SCAN: 2330 case CMD_DISCONNECT: 2331 case CMD_REASSOCIATE: 2332 case CMD_RECONNECT: 2333 deferMessage(message); 2334 break; 2335 default: 2336 return NOT_HANDLED; 2337 } 2338 return HANDLED; 2339 } 2340 } 2341 2342 class DriverStartedState extends State { 2343 @Override 2344 public void enter() { 2345 mIsRunning = true; 2346 mInDelayedStop = false; 2347 updateBatteryWorkSource(null); 2348 2349 /** 2350 * Enable bluetooth coexistence scan mode when bluetooth connection is active. 2351 * When this mode is on, some of the low-level scan parameters used by the 2352 * driver are changed to reduce interference with bluetooth 2353 */ 2354 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 2355 /* set country code */ 2356 setCountryCode(); 2357 /* set frequency band of operation */ 2358 setFrequencyBand(); 2359 /* initialize network state */ 2360 setNetworkDetailedState(DetailedState.DISCONNECTED); 2361 2362 /* Remove any filtering on Multicast v6 at start */ 2363 mWifiNative.stopFilteringMulticastV6Packets(); 2364 2365 /* Reset Multicast v4 filtering state */ 2366 if (mFilteringMulticastV4Packets.get()) { 2367 mWifiNative.startFilteringMulticastV4Packets(); 2368 } else { 2369 mWifiNative.stopFilteringMulticastV4Packets(); 2370 } 2371 2372 if (mOperationalMode != CONNECT_MODE) { 2373 mWifiNative.disconnect(); 2374 transitionTo(mScanModeState); 2375 } else { 2376 mWifiNative.reconnect(); 2377 // Status pulls in the current supplicant state and network connection state 2378 // events over the monitor connection. This helps framework sync up with 2379 // current supplicant state 2380 mWifiNative.status(); 2381 transitionTo(mDisconnectedState); 2382 } 2383 2384 // We may have missed screen update at boot 2385 if (mScreenBroadcastReceived.get() == false) { 2386 PowerManager powerManager = (PowerManager)mContext.getSystemService( 2387 Context.POWER_SERVICE); 2388 handleScreenStateChanged(powerManager.isScreenOn()); 2389 } else { 2390 // Set the right suspend mode settings 2391 mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0 2392 && mUserWantsSuspendOpt.get()); 2393 } 2394 mWifiNative.setPowerSave(true); 2395 2396 if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); 2397 } 2398 @Override 2399 public boolean processMessage(Message message) { 2400 switch(message.what) { 2401 case CMD_START_SCAN: 2402 startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP); 2403 break; 2404 case CMD_SET_COUNTRY_CODE: 2405 String country = (String) message.obj; 2406 if (DBG) log("set country code " + country); 2407 if (!mWifiNative.setCountryCode(country.toUpperCase())) { 2408 loge("Failed to set country code " + country); 2409 } 2410 break; 2411 case CMD_SET_FREQUENCY_BAND: 2412 int band = message.arg1; 2413 if (DBG) log("set frequency band " + band); 2414 if (mWifiNative.setBand(band)) { 2415 mFrequencyBand.set(band); 2416 //Fetch the latest scan results when frequency band is set 2417 startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP); 2418 } else { 2419 loge("Failed to set frequency band " + band); 2420 } 2421 break; 2422 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 2423 mBluetoothConnectionActive = (message.arg1 != 2424 BluetoothAdapter.STATE_DISCONNECTED); 2425 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 2426 break; 2427 case CMD_STOP_DRIVER: 2428 int mode = message.arg1; 2429 2430 /* Already doing a delayed stop */ 2431 if (mInDelayedStop) { 2432 if (DBG) log("Already in delayed stop"); 2433 break; 2434 } 2435 mInDelayedStop = true; 2436 mDelayedStopCounter++; 2437 if (DBG) log("Delayed stop message " + mDelayedStopCounter); 2438 2439 /* send regular delayed shut down */ 2440 Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); 2441 driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); 2442 mDriverStopIntent = PendingIntent.getBroadcast(mContext, 2443 DRIVER_STOP_REQUEST, driverStopIntent, 2444 PendingIntent.FLAG_UPDATE_CURRENT); 2445 2446 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 2447 + mDriverStopDelayMs, mDriverStopIntent); 2448 break; 2449 case CMD_START_DRIVER: 2450 if (mInDelayedStop) { 2451 mInDelayedStop = false; 2452 mDelayedStopCounter++; 2453 mAlarmManager.cancel(mDriverStopIntent); 2454 if (DBG) log("Delayed stop ignored due to start"); 2455 } 2456 break; 2457 case CMD_DELAYED_STOP_DRIVER: 2458 if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter); 2459 if (message.arg1 != mDelayedStopCounter) break; 2460 if (getCurrentState() != mDisconnectedState) { 2461 mWifiNative.disconnect(); 2462 handleNetworkDisconnect(); 2463 } 2464 mWakeLock.acquire(); 2465 mWifiNative.stopDriver(); 2466 mWakeLock.release(); 2467 if (mP2pSupported) { 2468 transitionTo(mWaitForP2pDisableState); 2469 } else { 2470 transitionTo(mDriverStoppingState); 2471 } 2472 break; 2473 case CMD_START_PACKET_FILTERING: 2474 if (message.arg1 == MULTICAST_V6) { 2475 mWifiNative.startFilteringMulticastV6Packets(); 2476 } else if (message.arg1 == MULTICAST_V4) { 2477 mWifiNative.startFilteringMulticastV4Packets(); 2478 } else { 2479 loge("Illegal arugments to CMD_START_PACKET_FILTERING"); 2480 } 2481 break; 2482 case CMD_STOP_PACKET_FILTERING: 2483 if (message.arg1 == MULTICAST_V6) { 2484 mWifiNative.stopFilteringMulticastV6Packets(); 2485 } else if (message.arg1 == MULTICAST_V4) { 2486 mWifiNative.stopFilteringMulticastV4Packets(); 2487 } else { 2488 loge("Illegal arugments to CMD_STOP_PACKET_FILTERING"); 2489 } 2490 break; 2491 case CMD_SET_SUSPEND_OPT_ENABLED: 2492 if (message.arg1 == 1) { 2493 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true); 2494 mSuspendWakeLock.release(); 2495 } else { 2496 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false); 2497 } 2498 break; 2499 case CMD_SET_HIGH_PERF_MODE: 2500 if (message.arg1 == 1) { 2501 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false); 2502 } else { 2503 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true); 2504 } 2505 break; 2506 default: 2507 return NOT_HANDLED; 2508 } 2509 return HANDLED; 2510 } 2511 @Override 2512 public void exit() { 2513 mIsRunning = false; 2514 updateBatteryWorkSource(null); 2515 mScanResults = new ArrayList<ScanResult>(); 2516 } 2517 } 2518 2519 class WaitForP2pDisableState extends State { 2520 private State mTransitionToState; 2521 @Override 2522 public void enter() { 2523 switch (getCurrentMessage().what) { 2524 case WifiMonitor.SUP_DISCONNECTION_EVENT: 2525 mTransitionToState = mInitialState; 2526 break; 2527 case CMD_DELAYED_STOP_DRIVER: 2528 mTransitionToState = mDriverStoppingState; 2529 break; 2530 case CMD_STOP_SUPPLICANT: 2531 mTransitionToState = mSupplicantStoppingState; 2532 break; 2533 default: 2534 mTransitionToState = mDriverStoppingState; 2535 break; 2536 } 2537 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ); 2538 } 2539 @Override 2540 public boolean processMessage(Message message) { 2541 switch(message.what) { 2542 case WifiStateMachine.CMD_DISABLE_P2P_RSP: 2543 transitionTo(mTransitionToState); 2544 break; 2545 /* Defer wifi start/shut and driver commands */ 2546 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2547 case CMD_START_SUPPLICANT: 2548 case CMD_STOP_SUPPLICANT: 2549 case CMD_START_AP: 2550 case CMD_STOP_AP: 2551 case CMD_START_DRIVER: 2552 case CMD_STOP_DRIVER: 2553 case CMD_SET_OPERATIONAL_MODE: 2554 case CMD_SET_COUNTRY_CODE: 2555 case CMD_SET_FREQUENCY_BAND: 2556 case CMD_START_PACKET_FILTERING: 2557 case CMD_STOP_PACKET_FILTERING: 2558 case CMD_START_SCAN: 2559 case CMD_DISCONNECT: 2560 case CMD_REASSOCIATE: 2561 case CMD_RECONNECT: 2562 deferMessage(message); 2563 break; 2564 default: 2565 return NOT_HANDLED; 2566 } 2567 return HANDLED; 2568 } 2569 } 2570 2571 class DriverStoppingState extends State { 2572 @Override 2573 public boolean processMessage(Message message) { 2574 switch(message.what) { 2575 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2576 SupplicantState state = handleSupplicantStateChange(message); 2577 if (state == SupplicantState.INTERFACE_DISABLED) { 2578 transitionTo(mDriverStoppedState); 2579 } 2580 break; 2581 /* Queue driver commands */ 2582 case CMD_START_DRIVER: 2583 case CMD_STOP_DRIVER: 2584 case CMD_SET_COUNTRY_CODE: 2585 case CMD_SET_FREQUENCY_BAND: 2586 case CMD_START_PACKET_FILTERING: 2587 case CMD_STOP_PACKET_FILTERING: 2588 case CMD_START_SCAN: 2589 case CMD_DISCONNECT: 2590 case CMD_REASSOCIATE: 2591 case CMD_RECONNECT: 2592 deferMessage(message); 2593 break; 2594 default: 2595 return NOT_HANDLED; 2596 } 2597 return HANDLED; 2598 } 2599 } 2600 2601 class DriverStoppedState extends State { 2602 @Override 2603 public boolean processMessage(Message message) { 2604 switch (message.what) { 2605 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2606 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 2607 SupplicantState state = stateChangeResult.state; 2608 // A WEXT bug means that we can be back to driver started state 2609 // unexpectedly 2610 if (SupplicantState.isDriverActive(state)) { 2611 transitionTo(mDriverStartedState); 2612 } 2613 break; 2614 case CMD_START_DRIVER: 2615 mWakeLock.acquire(); 2616 mWifiNative.startDriver(); 2617 mWakeLock.release(); 2618 transitionTo(mDriverStartingState); 2619 break; 2620 default: 2621 return NOT_HANDLED; 2622 } 2623 return HANDLED; 2624 } 2625 } 2626 2627 class ScanModeState extends State { 2628 private int mLastOperationMode; 2629 @Override 2630 public void enter() { 2631 mWifiConfigStore.disableAllNetworks(); 2632 mLastOperationMode = mOperationalMode; 2633 if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 2634 mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); 2635 setWifiState(WIFI_STATE_DISABLED); 2636 } 2637 } 2638 @Override 2639 public void exit() { 2640 if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 2641 setWifiState(WIFI_STATE_ENABLED); 2642 mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P); 2643 } 2644 mWifiConfigStore.enableAllNetworks(); 2645 mWifiNative.reconnect(); 2646 } 2647 @Override 2648 public boolean processMessage(Message message) { 2649 switch(message.what) { 2650 case CMD_SET_OPERATIONAL_MODE: 2651 if (message.arg1 == CONNECT_MODE) { 2652 mOperationalMode = CONNECT_MODE; 2653 transitionTo(mDisconnectedState); 2654 } else { 2655 // Nothing to do 2656 return HANDLED; 2657 } 2658 break; 2659 // Handle scan. All the connection related commands are 2660 // handled only in ConnectModeState 2661 case CMD_START_SCAN: 2662 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP); 2663 break; 2664 default: 2665 return NOT_HANDLED; 2666 } 2667 return HANDLED; 2668 } 2669 } 2670 2671 class ConnectModeState extends State { 2672 @Override 2673 public boolean processMessage(Message message) { 2674 WifiConfiguration config; 2675 boolean ok; 2676 switch(message.what) { 2677 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 2678 mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT); 2679 break; 2680 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2681 SupplicantState state = handleSupplicantStateChange(message); 2682 // A driver/firmware hang can now put the interface in a down state. 2683 // We detect the interface going down and recover from it 2684 if (!SupplicantState.isDriverActive(state)) { 2685 if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 2686 handleNetworkDisconnect(); 2687 } 2688 log("Detected an interface down, restart driver"); 2689 transitionTo(mDriverStoppedState); 2690 sendMessage(CMD_START_DRIVER); 2691 break; 2692 } 2693 2694 // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT 2695 // when authentication times out after a successful connection, 2696 // we can figure this from the supplicant state. If supplicant 2697 // state is DISCONNECTED, but the mNetworkInfo says we are not 2698 // disconnected, we need to handle a disconnection 2699 if (state == SupplicantState.DISCONNECTED && 2700 mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 2701 if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect"); 2702 handleNetworkDisconnect(); 2703 transitionTo(mDisconnectedState); 2704 } 2705 break; 2706 case WifiP2pService.DISCONNECT_WIFI_REQUEST: 2707 if (message.arg1 == 1) { 2708 mWifiNative.disconnect(); 2709 mTemporarilyDisconnectWifi = true; 2710 } else { 2711 mWifiNative.reconnect(); 2712 mTemporarilyDisconnectWifi = false; 2713 } 2714 break; 2715 case CMD_ADD_OR_UPDATE_NETWORK: 2716 config = (WifiConfiguration) message.obj; 2717 replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, 2718 mWifiConfigStore.addOrUpdateNetwork(config)); 2719 break; 2720 case CMD_REMOVE_NETWORK: 2721 ok = mWifiConfigStore.removeNetwork(message.arg1); 2722 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 2723 break; 2724 case CMD_ENABLE_NETWORK: 2725 ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); 2726 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 2727 break; 2728 case CMD_ENABLE_ALL_NETWORKS: 2729 long time = android.os.SystemClock.elapsedRealtime(); 2730 if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { 2731 mWifiConfigStore.enableAllNetworks(); 2732 mLastEnableAllNetworksTime = time; 2733 } 2734 break; 2735 case WifiManager.DISABLE_NETWORK: 2736 if (mWifiConfigStore.disableNetwork(message.arg1, 2737 WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) { 2738 replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); 2739 } else { 2740 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 2741 WifiManager.ERROR); 2742 } 2743 break; 2744 case CMD_BLACKLIST_NETWORK: 2745 mWifiNative.addToBlacklist((String)message.obj); 2746 break; 2747 case CMD_CLEAR_BLACKLIST: 2748 mWifiNative.clearBlacklist(); 2749 break; 2750 case CMD_SAVE_CONFIG: 2751 ok = mWifiConfigStore.saveConfig(); 2752 replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); 2753 2754 // Inform the backup manager about a data change 2755 IBackupManager ibm = IBackupManager.Stub.asInterface( 2756 ServiceManager.getService(Context.BACKUP_SERVICE)); 2757 if (ibm != null) { 2758 try { 2759 ibm.dataChanged("com.android.providers.settings"); 2760 } catch (Exception e) { 2761 // Try again later 2762 } 2763 } 2764 break; 2765 case CMD_GET_CONFIGURED_NETWORKS: 2766 replyToMessage(message, message.what, 2767 mWifiConfigStore.getConfiguredNetworks()); 2768 break; 2769 /* Do a redundant disconnect without transition */ 2770 case CMD_DISCONNECT: 2771 mWifiNative.disconnect(); 2772 break; 2773 case CMD_RECONNECT: 2774 mWifiNative.reconnect(); 2775 break; 2776 case CMD_REASSOCIATE: 2777 mWifiNative.reassociate(); 2778 break; 2779 case WifiManager.CONNECT_NETWORK: 2780 /* The connect message can contain a network id passed as arg1 on message or 2781 * or a config passed as obj on message. 2782 * For a new network, a config is passed to create and connect. 2783 * For an existing network, a network id is passed 2784 */ 2785 int netId = message.arg1; 2786 config = (WifiConfiguration) message.obj; 2787 2788 /* Save the network config */ 2789 if (config != null) { 2790 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 2791 netId = result.getNetworkId(); 2792 } 2793 2794 if (mWifiConfigStore.selectNetwork(netId) && 2795 mWifiNative.reconnect()) { 2796 /* The state tracker handles enabling networks upon completion/failure */ 2797 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 2798 replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 2799 /* Expect a disconnection from the old connection */ 2800 transitionTo(mDisconnectingState); 2801 } else { 2802 loge("Failed to connect config: " + config + " netId: " + netId); 2803 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 2804 WifiManager.ERROR); 2805 break; 2806 } 2807 break; 2808 case WifiManager.SAVE_NETWORK: 2809 config = (WifiConfiguration) message.obj; 2810 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 2811 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 2812 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 2813 } else { 2814 loge("Failed to save network"); 2815 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 2816 WifiManager.ERROR); 2817 } 2818 break; 2819 case WifiManager.FORGET_NETWORK: 2820 if (mWifiConfigStore.forgetNetwork(message.arg1)) { 2821 replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); 2822 } else { 2823 loge("Failed to forget network"); 2824 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 2825 WifiManager.ERROR); 2826 } 2827 break; 2828 case WifiManager.START_WPS: 2829 WpsInfo wpsInfo = (WpsInfo) message.obj; 2830 WpsResult wpsResult; 2831 switch (wpsInfo.setup) { 2832 case WpsInfo.PBC: 2833 wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo); 2834 break; 2835 case WpsInfo.KEYPAD: 2836 wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); 2837 break; 2838 case WpsInfo.DISPLAY: 2839 wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); 2840 break; 2841 default: 2842 wpsResult = new WpsResult(Status.FAILURE); 2843 loge("Invalid setup for WPS"); 2844 break; 2845 } 2846 if (wpsResult.status == Status.SUCCESS) { 2847 replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult); 2848 transitionTo(mWpsRunningState); 2849 } else { 2850 loge("Failed to start WPS with config " + wpsInfo.toString()); 2851 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR); 2852 } 2853 break; 2854 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2855 if (DBG) log("Network connection established"); 2856 mLastNetworkId = message.arg1; 2857 mLastBssid = (String) message.obj; 2858 2859 mWifiInfo.setBSSID(mLastBssid); 2860 mWifiInfo.setNetworkId(mLastNetworkId); 2861 /* send event to CM & network change broadcast */ 2862 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 2863 sendNetworkStateChangeBroadcast(mLastBssid); 2864 transitionTo(mObtainingIpState); 2865 break; 2866 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2867 if (DBG) log("Network connection lost"); 2868 handleNetworkDisconnect(); 2869 transitionTo(mDisconnectedState); 2870 break; 2871 default: 2872 return NOT_HANDLED; 2873 } 2874 return HANDLED; 2875 } 2876 } 2877 2878 class L2ConnectedState extends State { 2879 @Override 2880 public void enter() { 2881 mRssiPollToken++; 2882 if (mEnableRssiPolling) { 2883 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0); 2884 } 2885 } 2886 2887 @Override 2888 public boolean processMessage(Message message) { 2889 switch (message.what) { 2890 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 2891 handlePreDhcpSetup(); 2892 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE); 2893 break; 2894 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 2895 handlePostDhcpSetup(); 2896 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 2897 if (DBG) log("DHCP successful"); 2898 handleSuccessfulIpConfiguration((DhcpResults) message.obj); 2899 transitionTo(mVerifyingLinkState); 2900 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { 2901 if (DBG) log("DHCP failed"); 2902 handleFailedIpConfiguration(); 2903 transitionTo(mDisconnectingState); 2904 } 2905 break; 2906 case CMD_DISCONNECT: 2907 mWifiNative.disconnect(); 2908 transitionTo(mDisconnectingState); 2909 break; 2910 case WifiP2pService.DISCONNECT_WIFI_REQUEST: 2911 if (message.arg1 == 1) { 2912 mWifiNative.disconnect(); 2913 mTemporarilyDisconnectWifi = true; 2914 transitionTo(mDisconnectingState); 2915 } 2916 break; 2917 case CMD_SET_OPERATIONAL_MODE: 2918 if (message.arg1 != CONNECT_MODE) { 2919 sendMessage(CMD_DISCONNECT); 2920 deferMessage(message); 2921 } 2922 break; 2923 case CMD_START_SCAN: 2924 /* Do not attempt to connect when we are already connected */ 2925 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP); 2926 break; 2927 /* Ignore connection to same network */ 2928 case WifiManager.CONNECT_NETWORK: 2929 int netId = message.arg1; 2930 if (mWifiInfo.getNetworkId() == netId) { 2931 break; 2932 } 2933 return NOT_HANDLED; 2934 case WifiManager.SAVE_NETWORK: 2935 WifiConfiguration config = (WifiConfiguration) message.obj; 2936 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 2937 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 2938 if (result.hasIpChanged()) { 2939 log("Reconfiguring IP on connection"); 2940 transitionTo(mObtainingIpState); 2941 } 2942 if (result.hasProxyChanged()) { 2943 log("Reconfiguring proxy on connection"); 2944 configureLinkProperties(); 2945 sendLinkConfigurationChangedBroadcast(); 2946 } 2947 } 2948 2949 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 2950 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 2951 } else { 2952 loge("Failed to save network"); 2953 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 2954 WifiManager.ERROR); 2955 } 2956 break; 2957 /* Ignore */ 2958 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2959 break; 2960 case CMD_RSSI_POLL: 2961 if (message.arg1 == mRssiPollToken) { 2962 // Get Info and continue polling 2963 fetchRssiAndLinkSpeedNative(); 2964 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 2965 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 2966 } else { 2967 // Polling has completed 2968 } 2969 break; 2970 case CMD_ENABLE_RSSI_POLL: 2971 mEnableRssiPolling = (message.arg1 == 1); 2972 mRssiPollToken++; 2973 if (mEnableRssiPolling) { 2974 // first poll 2975 fetchRssiAndLinkSpeedNative(); 2976 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 2977 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 2978 } 2979 break; 2980 case WifiManager.RSSI_PKTCNT_FETCH: 2981 RssiPacketCountInfo info = new RssiPacketCountInfo(); 2982 fetchRssiAndLinkSpeedNative(); 2983 info.rssi = mWifiInfo.getRssi(); 2984 fetchPktcntNative(info); 2985 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info); 2986 break; 2987 default: 2988 return NOT_HANDLED; 2989 } 2990 2991 return HANDLED; 2992 } 2993 } 2994 2995 class ObtainingIpState extends State { 2996 @Override 2997 public void enter() { 2998 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 2999 //start DHCP 3000 if (mDhcpStateMachine == null) { 3001 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 3002 mContext, WifiStateMachine.this, mInterfaceName); 3003 3004 } 3005 mDhcpStateMachine.registerForPreDhcpNotification(); 3006 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); 3007 } else { 3008 DhcpResults dhcpResults = new DhcpResults( 3009 mWifiConfigStore.getLinkProperties(mLastNetworkId)); 3010 dhcpResults.linkProperties.setInterfaceName(mInterfaceName); 3011 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 3012 Iterator<LinkAddress> addrs = 3013 dhcpResults.linkProperties.getLinkAddresses().iterator(); 3014 if (!addrs.hasNext()) { 3015 loge("Static IP lacks address"); 3016 sendMessage(CMD_STATIC_IP_FAILURE); 3017 } else { 3018 ifcg.setLinkAddress(addrs.next()); 3019 ifcg.setInterfaceUp(); 3020 try { 3021 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 3022 if (DBG) log("Static IP configuration succeeded"); 3023 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults); 3024 } catch (RemoteException re) { 3025 loge("Static IP configuration failed: " + re); 3026 sendMessage(CMD_STATIC_IP_FAILURE); 3027 } catch (IllegalStateException e) { 3028 loge("Static IP configuration failed: " + e); 3029 sendMessage(CMD_STATIC_IP_FAILURE); 3030 } 3031 } 3032 } 3033 } 3034 @Override 3035 public boolean processMessage(Message message) { 3036 if (DBG) log(getName() + message.toString() + "\n"); 3037 switch(message.what) { 3038 case CMD_STATIC_IP_SUCCESS: 3039 handleSuccessfulIpConfiguration((DhcpResults) message.obj); 3040 transitionTo(mVerifyingLinkState); 3041 break; 3042 case CMD_STATIC_IP_FAILURE: 3043 handleFailedIpConfiguration(); 3044 transitionTo(mDisconnectingState); 3045 break; 3046 case WifiManager.SAVE_NETWORK: 3047 deferMessage(message); 3048 break; 3049 /* Defer any power mode changes since we must keep active power mode at DHCP */ 3050 case CMD_SET_HIGH_PERF_MODE: 3051 deferMessage(message); 3052 break; 3053 /* Defer scan request since we should not switch to other channels at DHCP */ 3054 case CMD_START_SCAN: 3055 deferMessage(message); 3056 break; 3057 default: 3058 return NOT_HANDLED; 3059 } 3060 return HANDLED; 3061 } 3062 } 3063 3064 class VerifyingLinkState extends State { 3065 @Override 3066 public void enter() { 3067 setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); 3068 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); 3069 sendNetworkStateChangeBroadcast(mLastBssid); 3070 } 3071 @Override 3072 public boolean processMessage(Message message) { 3073 switch (message.what) { 3074 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 3075 //stay here 3076 break; 3077 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 3078 transitionTo(mCaptivePortalCheckState); 3079 break; 3080 default: 3081 return NOT_HANDLED; 3082 } 3083 return HANDLED; 3084 } 3085 } 3086 3087 class CaptivePortalCheckState extends State { 3088 @Override 3089 public void enter() { 3090 setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); 3091 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CAPTIVE_PORTAL_CHECK); 3092 sendNetworkStateChangeBroadcast(mLastBssid); 3093 } 3094 @Override 3095 public boolean processMessage(Message message) { 3096 switch (message.what) { 3097 case CMD_CAPTIVE_CHECK_COMPLETE: 3098 try { 3099 mNwService.enableIpv6(mInterfaceName); 3100 } catch (RemoteException re) { 3101 loge("Failed to enable IPv6: " + re); 3102 } catch (IllegalStateException e) { 3103 loge("Failed to enable IPv6: " + e); 3104 } 3105 setNetworkDetailedState(DetailedState.CONNECTED); 3106 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); 3107 sendNetworkStateChangeBroadcast(mLastBssid); 3108 transitionTo(mConnectedState); 3109 break; 3110 default: 3111 return NOT_HANDLED; 3112 } 3113 return HANDLED; 3114 } 3115 } 3116 3117 class ConnectedState extends State { 3118 @Override 3119 public boolean processMessage(Message message) { 3120 switch (message.what) { 3121 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 3122 if (DBG) log("Watchdog reports poor link"); 3123 try { 3124 mNwService.disableIpv6(mInterfaceName); 3125 } catch (RemoteException re) { 3126 loge("Failed to disable IPv6: " + re); 3127 } catch (IllegalStateException e) { 3128 loge("Failed to disable IPv6: " + e); 3129 } 3130 /* Report a disconnect */ 3131 setNetworkDetailedState(DetailedState.DISCONNECTED); 3132 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 3133 sendNetworkStateChangeBroadcast(mLastBssid); 3134 3135 transitionTo(mVerifyingLinkState); 3136 break; 3137 default: 3138 return NOT_HANDLED; 3139 } 3140 return HANDLED; 3141 } 3142 @Override 3143 public void exit() { 3144 /* Request a CS wakelock during transition to mobile */ 3145 checkAndSetConnectivityInstance(); 3146 mCm.requestNetworkTransitionWakelock(getName()); 3147 } 3148 } 3149 3150 class DisconnectingState extends State { 3151 @Override 3152 public boolean processMessage(Message message) { 3153 switch (message.what) { 3154 case CMD_SET_OPERATIONAL_MODE: 3155 if (message.arg1 != CONNECT_MODE) { 3156 deferMessage(message); 3157 } 3158 break; 3159 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3160 /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT 3161 * we have missed the network disconnection, transition to mDisconnectedState 3162 * and handle the rest of the events there 3163 */ 3164 deferMessage(message); 3165 handleNetworkDisconnect(); 3166 transitionTo(mDisconnectedState); 3167 break; 3168 default: 3169 return NOT_HANDLED; 3170 } 3171 return HANDLED; 3172 } 3173 } 3174 3175 class DisconnectedState extends State { 3176 private boolean mAlarmEnabled = false; 3177 /* This is set from the overlay config file or from a secure setting. 3178 * A value of 0 disables scanning in the framework. 3179 */ 3180 private long mFrameworkScanIntervalMs; 3181 3182 private void setScanAlarm(boolean enabled) { 3183 if (enabled == mAlarmEnabled) return; 3184 if (enabled) { 3185 if (mFrameworkScanIntervalMs > 0) { 3186 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 3187 System.currentTimeMillis() + mFrameworkScanIntervalMs, 3188 mFrameworkScanIntervalMs, 3189 mScanIntent); 3190 mAlarmEnabled = true; 3191 } 3192 } else { 3193 mAlarmManager.cancel(mScanIntent); 3194 mAlarmEnabled = false; 3195 } 3196 } 3197 3198 @Override 3199 public void enter() { 3200 // We dont scan frequently if this is a temporary disconnect 3201 // due to p2p 3202 if (mTemporarilyDisconnectWifi) { 3203 mWifiP2pChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_RESPONSE); 3204 return; 3205 } 3206 3207 mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 3208 Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS, 3209 mDefaultFrameworkScanIntervalMs); 3210 /* 3211 * We initiate background scanning if it is enabled, otherwise we 3212 * initiate an infrequent scan that wakes up the device to ensure 3213 * a user connects to an access point on the move 3214 */ 3215 if (mEnableBackgroundScan) { 3216 /* If a regular scan result is pending, do not initiate background 3217 * scan until the scan results are returned. This is needed because 3218 * initiating a background scan will cancel the regular scan and 3219 * scan results will not be returned until background scanning is 3220 * cleared 3221 */ 3222 if (!mScanResultIsPending) { 3223 mWifiNative.enableBackgroundScan(true); 3224 } 3225 } else { 3226 setScanAlarm(true); 3227 } 3228 3229 /** 3230 * If we have no networks saved, the supplicant stops doing the periodic scan. 3231 * The scans are useful to notify the user of the presence of an open network. 3232 * Note that these are not wake up scans. 3233 */ 3234 if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) { 3235 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 3236 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 3237 } 3238 } 3239 @Override 3240 public boolean processMessage(Message message) { 3241 boolean ret = HANDLED; 3242 switch (message.what) { 3243 case CMD_NO_NETWORKS_PERIODIC_SCAN: 3244 if (mP2pConnected.get()) break; 3245 if (message.arg1 == mPeriodicScanToken && 3246 mWifiConfigStore.getConfiguredNetworks().size() == 0) { 3247 sendMessage(CMD_START_SCAN); 3248 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 3249 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 3250 } 3251 break; 3252 case WifiManager.FORGET_NETWORK: 3253 case CMD_REMOVE_NETWORK: 3254 // Set up a delayed message here. After the forget/remove is handled 3255 // the handled delayed message will determine if there is a need to 3256 // scan and continue 3257 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 3258 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 3259 ret = NOT_HANDLED; 3260 break; 3261 case CMD_SET_OPERATIONAL_MODE: 3262 if (message.arg1 != CONNECT_MODE) { 3263 mOperationalMode = message.arg1; 3264 transitionTo(mScanModeState); 3265 } 3266 break; 3267 case CMD_ENABLE_BACKGROUND_SCAN: 3268 mEnableBackgroundScan = (message.arg1 == 1); 3269 if (mEnableBackgroundScan) { 3270 mWifiNative.enableBackgroundScan(true); 3271 setScanAlarm(false); 3272 } else { 3273 mWifiNative.enableBackgroundScan(false); 3274 setScanAlarm(true); 3275 } 3276 break; 3277 /* Ignore network disconnect */ 3278 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 3279 break; 3280 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3281 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 3282 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 3283 /* ConnectModeState does the rest of the handling */ 3284 ret = NOT_HANDLED; 3285 break; 3286 case CMD_START_SCAN: 3287 /* Disable background scan temporarily during a regular scan */ 3288 if (mEnableBackgroundScan) { 3289 mWifiNative.enableBackgroundScan(false); 3290 } 3291 /* Handled in parent state */ 3292 ret = NOT_HANDLED; 3293 break; 3294 case WifiMonitor.SCAN_RESULTS_EVENT: 3295 /* Re-enable background scan when a pending scan result is received */ 3296 if (mEnableBackgroundScan && mScanResultIsPending) { 3297 mWifiNative.enableBackgroundScan(true); 3298 } 3299 /* Handled in parent state */ 3300 ret = NOT_HANDLED; 3301 break; 3302 case WifiP2pService.P2P_CONNECTION_CHANGED: 3303 NetworkInfo info = (NetworkInfo) message.obj; 3304 mP2pConnected.set(info.isConnected()); 3305 if (mP2pConnected.get()) { 3306 int defaultInterval = mContext.getResources().getInteger( 3307 R.integer.config_wifi_scan_interval_p2p_connected); 3308 long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 3309 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 3310 defaultInterval); 3311 mWifiNative.setScanInterval((int) scanIntervalMs/1000); 3312 } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { 3313 if (DBG) log("Turn on scanning after p2p disconnected"); 3314 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 3315 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 3316 } 3317 case CMD_RECONNECT: 3318 case CMD_REASSOCIATE: 3319 if (mTemporarilyDisconnectWifi) { 3320 // Drop a third party reconnect/reassociate if STA is 3321 // temporarily disconnected for p2p 3322 break; 3323 } else { 3324 // ConnectModeState handles it 3325 ret = NOT_HANDLED; 3326 } 3327 break; 3328 default: 3329 ret = NOT_HANDLED; 3330 } 3331 return ret; 3332 } 3333 3334 @Override 3335 public void exit() { 3336 /* No need for a background scan upon exit from a disconnected state */ 3337 if (mEnableBackgroundScan) { 3338 mWifiNative.enableBackgroundScan(false); 3339 } 3340 setScanAlarm(false); 3341 } 3342 } 3343 3344 class WpsRunningState extends State { 3345 //Tracks the source to provide a reply 3346 private Message mSourceMessage; 3347 @Override 3348 public void enter() { 3349 mSourceMessage = Message.obtain(getCurrentMessage()); 3350 } 3351 @Override 3352 public boolean processMessage(Message message) { 3353 switch (message.what) { 3354 case WifiMonitor.WPS_SUCCESS_EVENT: 3355 replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED); 3356 mSourceMessage.recycle(); 3357 mSourceMessage = null; 3358 transitionTo(mDisconnectedState); 3359 break; 3360 case WifiMonitor.WPS_OVERLAP_EVENT: 3361 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 3362 WifiManager.WPS_OVERLAP_ERROR); 3363 mSourceMessage.recycle(); 3364 mSourceMessage = null; 3365 transitionTo(mDisconnectedState); 3366 break; 3367 case WifiMonitor.WPS_FAIL_EVENT: 3368 //arg1 has the reason for the failure 3369 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1); 3370 mSourceMessage.recycle(); 3371 mSourceMessage = null; 3372 transitionTo(mDisconnectedState); 3373 break; 3374 case WifiMonitor.WPS_TIMEOUT_EVENT: 3375 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 3376 WifiManager.WPS_TIMED_OUT); 3377 mSourceMessage.recycle(); 3378 mSourceMessage = null; 3379 transitionTo(mDisconnectedState); 3380 break; 3381 case WifiManager.START_WPS: 3382 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS); 3383 break; 3384 case WifiManager.CANCEL_WPS: 3385 if (mWifiNative.cancelWps()) { 3386 replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED); 3387 } else { 3388 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR); 3389 } 3390 transitionTo(mDisconnectedState); 3391 break; 3392 /* Defer all commands that can cause connections to a different network 3393 * or put the state machine out of connect mode 3394 */ 3395 case CMD_STOP_DRIVER: 3396 case CMD_SET_OPERATIONAL_MODE: 3397 case WifiManager.CONNECT_NETWORK: 3398 case CMD_ENABLE_NETWORK: 3399 case CMD_RECONNECT: 3400 case CMD_REASSOCIATE: 3401 case WifiMonitor.NETWORK_CONNECTION_EVENT: /* Handled after exiting WPS state */ 3402 deferMessage(message); 3403 break; 3404 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 3405 if (DBG) log("Network connection lost"); 3406 handleNetworkDisconnect(); 3407 break; 3408 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 3409 // Disregard auth failure events during WPS connection. The 3410 // EAP sequence is retried several times, and there might be 3411 // failures (especially for wps pin). We will get a WPS_XXX 3412 // event at the end of the sequence anyway. 3413 if (DBG) log("Ignore auth failure during WPS connection"); 3414 break; 3415 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3416 //Throw away supplicant state changes when WPS is running. 3417 //We will start getting supplicant state changes once we get 3418 //a WPS success or failure 3419 break; 3420 default: 3421 return NOT_HANDLED; 3422 } 3423 return HANDLED; 3424 } 3425 3426 @Override 3427 public void exit() { 3428 mWifiConfigStore.enableAllNetworks(); 3429 mWifiConfigStore.loadConfiguredNetworks(); 3430 } 3431 } 3432 3433 class SoftApStartingState extends State { 3434 @Override 3435 public void enter() { 3436 final Message message = getCurrentMessage(); 3437 if (message.what == CMD_START_AP) { 3438 final WifiConfiguration config = (WifiConfiguration) message.obj; 3439 3440 if (config == null) { 3441 mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); 3442 } else { 3443 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 3444 startSoftApWithConfig(config); 3445 } 3446 } else { 3447 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); 3448 } 3449 } 3450 @Override 3451 public boolean processMessage(Message message) { 3452 switch(message.what) { 3453 case CMD_START_SUPPLICANT: 3454 case CMD_STOP_SUPPLICANT: 3455 case CMD_START_AP: 3456 case CMD_STOP_AP: 3457 case CMD_START_DRIVER: 3458 case CMD_STOP_DRIVER: 3459 case CMD_SET_OPERATIONAL_MODE: 3460 case CMD_SET_COUNTRY_CODE: 3461 case CMD_SET_FREQUENCY_BAND: 3462 case CMD_START_PACKET_FILTERING: 3463 case CMD_STOP_PACKET_FILTERING: 3464 case CMD_TETHER_STATE_CHANGE: 3465 deferMessage(message); 3466 break; 3467 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: 3468 WifiConfiguration config = (WifiConfiguration) message.obj; 3469 if (config != null) { 3470 startSoftApWithConfig(config); 3471 } else { 3472 loge("Softap config is null!"); 3473 sendMessage(CMD_START_AP_FAILURE); 3474 } 3475 break; 3476 case CMD_START_AP_SUCCESS: 3477 setWifiApState(WIFI_AP_STATE_ENABLED); 3478 transitionTo(mSoftApStartedState); 3479 break; 3480 case CMD_START_AP_FAILURE: 3481 setWifiApState(WIFI_AP_STATE_FAILED); 3482 transitionTo(mInitialState); 3483 break; 3484 default: 3485 return NOT_HANDLED; 3486 } 3487 return HANDLED; 3488 } 3489 } 3490 3491 class SoftApStartedState extends State { 3492 @Override 3493 public boolean processMessage(Message message) { 3494 switch(message.what) { 3495 case CMD_STOP_AP: 3496 if (DBG) log("Stopping Soft AP"); 3497 /* We have not tethered at this point, so we just shutdown soft Ap */ 3498 try { 3499 mNwService.stopAccessPoint(mInterfaceName); 3500 } catch(Exception e) { 3501 loge("Exception in stopAccessPoint()"); 3502 } 3503 setWifiApState(WIFI_AP_STATE_DISABLED); 3504 transitionTo(mInitialState); 3505 break; 3506 case CMD_START_AP: 3507 // Ignore a start on a running access point 3508 break; 3509 /* Fail client mode operation when soft AP is enabled */ 3510 case CMD_START_SUPPLICANT: 3511 loge("Cannot start supplicant with a running soft AP"); 3512 setWifiState(WIFI_STATE_UNKNOWN); 3513 break; 3514 case CMD_TETHER_STATE_CHANGE: 3515 TetherStateChange stateChange = (TetherStateChange) message.obj; 3516 if (startTethering(stateChange.available)) { 3517 transitionTo(mTetheringState); 3518 } 3519 break; 3520 default: 3521 return NOT_HANDLED; 3522 } 3523 return HANDLED; 3524 } 3525 } 3526 3527 class TetheringState extends State { 3528 @Override 3529 public void enter() { 3530 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 3531 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 3532 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 3533 } 3534 @Override 3535 public boolean processMessage(Message message) { 3536 switch(message.what) { 3537 case CMD_TETHER_STATE_CHANGE: 3538 TetherStateChange stateChange = (TetherStateChange) message.obj; 3539 if (isWifiTethered(stateChange.active)) { 3540 transitionTo(mTetheredState); 3541 } 3542 return HANDLED; 3543 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 3544 if (message.arg1 == mTetherToken) { 3545 loge("Failed to get tether update, shutdown soft access point"); 3546 transitionTo(mSoftApStartedState); 3547 // Needs to be first thing handled 3548 sendMessageAtFrontOfQueue(CMD_STOP_AP); 3549 } 3550 break; 3551 case CMD_START_SUPPLICANT: 3552 case CMD_STOP_SUPPLICANT: 3553 case CMD_START_AP: 3554 case CMD_STOP_AP: 3555 case CMD_START_DRIVER: 3556 case CMD_STOP_DRIVER: 3557 case CMD_SET_OPERATIONAL_MODE: 3558 case CMD_SET_COUNTRY_CODE: 3559 case CMD_SET_FREQUENCY_BAND: 3560 case CMD_START_PACKET_FILTERING: 3561 case CMD_STOP_PACKET_FILTERING: 3562 deferMessage(message); 3563 break; 3564 default: 3565 return NOT_HANDLED; 3566 } 3567 return HANDLED; 3568 } 3569 } 3570 3571 class TetheredState extends State { 3572 @Override 3573 public boolean processMessage(Message message) { 3574 switch(message.what) { 3575 case CMD_TETHER_STATE_CHANGE: 3576 TetherStateChange stateChange = (TetherStateChange) message.obj; 3577 if (!isWifiTethered(stateChange.active)) { 3578 loge("Tethering reports wifi as untethered!, shut down soft Ap"); 3579 setHostApRunning(null, false); 3580 } 3581 return HANDLED; 3582 case CMD_STOP_AP: 3583 if (DBG) log("Untethering before stopping AP"); 3584 setWifiApState(WIFI_AP_STATE_DISABLING); 3585 stopTethering(); 3586 transitionTo(mUntetheringState); 3587 // More work to do after untethering 3588 deferMessage(message); 3589 break; 3590 default: 3591 return NOT_HANDLED; 3592 } 3593 return HANDLED; 3594 } 3595 } 3596 3597 class UntetheringState extends State { 3598 @Override 3599 public void enter() { 3600 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 3601 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 3602 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 3603 3604 } 3605 @Override 3606 public boolean processMessage(Message message) { 3607 switch(message.what) { 3608 case CMD_TETHER_STATE_CHANGE: 3609 TetherStateChange stateChange = (TetherStateChange) message.obj; 3610 3611 /* Wait till wifi is untethered */ 3612 if (isWifiTethered(stateChange.active)) break; 3613 3614 transitionTo(mSoftApStartedState); 3615 break; 3616 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 3617 if (message.arg1 == mTetherToken) { 3618 loge("Failed to get tether update, force stop access point"); 3619 transitionTo(mSoftApStartedState); 3620 } 3621 break; 3622 case CMD_START_SUPPLICANT: 3623 case CMD_STOP_SUPPLICANT: 3624 case CMD_START_AP: 3625 case CMD_STOP_AP: 3626 case CMD_START_DRIVER: 3627 case CMD_STOP_DRIVER: 3628 case CMD_SET_OPERATIONAL_MODE: 3629 case CMD_SET_COUNTRY_CODE: 3630 case CMD_SET_FREQUENCY_BAND: 3631 case CMD_START_PACKET_FILTERING: 3632 case CMD_STOP_PACKET_FILTERING: 3633 deferMessage(message); 3634 break; 3635 default: 3636 return NOT_HANDLED; 3637 } 3638 return HANDLED; 3639 } 3640 } 3641 3642 //State machine initiated requests can have replyTo set to null indicating 3643 //there are no recepients, we ignore those reply actions 3644 private void replyToMessage(Message msg, int what) { 3645 if (msg.replyTo == null) return; 3646 Message dstMsg = obtainMessageWithArg2(msg); 3647 dstMsg.what = what; 3648 mReplyChannel.replyToMessage(msg, dstMsg); 3649 } 3650 3651 private void replyToMessage(Message msg, int what, int arg1) { 3652 if (msg.replyTo == null) return; 3653 Message dstMsg = obtainMessageWithArg2(msg); 3654 dstMsg.what = what; 3655 dstMsg.arg1 = arg1; 3656 mReplyChannel.replyToMessage(msg, dstMsg); 3657 } 3658 3659 private void replyToMessage(Message msg, int what, Object obj) { 3660 if (msg.replyTo == null) return; 3661 Message dstMsg = obtainMessageWithArg2(msg); 3662 dstMsg.what = what; 3663 dstMsg.obj = obj; 3664 mReplyChannel.replyToMessage(msg, dstMsg); 3665 } 3666 3667 /** 3668 * arg2 on the source message has a unique id that needs to be retained in replies 3669 * to match the request 3670 * 3671 * see WifiManager for details 3672 */ 3673 private Message obtainMessageWithArg2(Message srcMsg) { 3674 Message msg = Message.obtain(); 3675 msg.arg2 = srcMsg.arg2; 3676 return msg; 3677 } 3678} 3679