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