WifiStateMachine.java revision 31b62322bfa9470d648fbfd69510e03da29b29af
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.net.wifi; 18 19import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; 20import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; 21import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; 22import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; 23import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; 24 25/** 26 * TODO: Add soft AP states as part of WIFI_STATE_XXX 27 * Retain WIFI_STATE_ENABLING that indicates driver is loading 28 * Add WIFI_STATE_AP_ENABLED to indicate soft AP has started 29 * and WIFI_STATE_FAILED for failure 30 * Deprecate WIFI_STATE_UNKNOWN 31 * 32 * Doing this will simplify the logic for sending broadcasts 33 */ 34import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; 35import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; 36import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; 37import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; 38import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; 39 40import android.app.ActivityManagerNative; 41import android.net.NetworkInfo; 42import android.net.DhcpInfo; 43import android.net.NetworkUtils; 44import android.net.ConnectivityManager; 45import android.net.NetworkInfo.DetailedState; 46import android.net.LinkProperties; 47import android.net.wifi.WifiConfiguration.Status; 48import android.os.Binder; 49import android.os.Message; 50import android.os.Parcelable; 51import android.os.Handler; 52import android.os.IBinder; 53import android.os.INetworkManagementService; 54import android.os.PowerManager; 55import android.os.SystemProperties; 56import android.os.RemoteException; 57import android.os.ServiceManager; 58import android.os.Process; 59import android.provider.Settings; 60import android.text.TextUtils; 61import android.util.EventLog; 62import android.util.Log; 63import android.util.Slog; 64import android.app.backup.IBackupManager; 65import android.bluetooth.BluetoothDevice; 66import android.bluetooth.BluetoothHeadset; 67import android.bluetooth.BluetoothA2dp; 68import android.content.ContentResolver; 69import android.content.Intent; 70import android.content.Context; 71import android.database.ContentObserver; 72import com.android.internal.app.IBatteryStats; 73import com.android.internal.util.HierarchicalState; 74import com.android.internal.util.HierarchicalStateMachine; 75 76import java.net.InetAddress; 77import java.net.NetworkInterface; 78import java.net.SocketException; 79import java.net.UnknownHostException; 80import java.util.ArrayList; 81import java.util.BitSet; 82import java.util.Iterator; 83import java.util.LinkedHashMap; 84import java.util.List; 85import java.util.Map; 86import java.util.Set; 87import java.util.concurrent.atomic.AtomicBoolean; 88import java.util.concurrent.atomic.AtomicInteger; 89import java.util.regex.Pattern; 90 91/** 92 * Track the state of Wifi connectivity. All event handling is done here, 93 * and all changes in connectivity state are initiated here. 94 * 95 * @hide 96 */ 97//TODO: we still need frequent scanning for the case when 98// we issue disconnect but need scan results for open network notification 99public class WifiStateMachine extends HierarchicalStateMachine { 100 101 private static final String TAG = "WifiStateMachine"; 102 private static final String NETWORKTYPE = "WIFI"; 103 private static final boolean DBG = false; 104 105 /* TODO: fetch a configurable interface */ 106 private static final String SOFTAP_IFACE = "wl0.1"; 107 108 private WifiMonitor mWifiMonitor; 109 private INetworkManagementService nwService; 110 private ConnectivityManager mCm; 111 112 /* Scan results handling */ 113 private List<ScanResult> mScanResults; 114 private static final Pattern scanResultPattern = Pattern.compile("\t+"); 115 private static final int SCAN_RESULT_CACHE_SIZE = 80; 116 private final LinkedHashMap<String, ScanResult> mScanResultCache; 117 118 private String mInterfaceName; 119 120 private int mNumAllowedChannels = 0; 121 private int mLastSignalLevel = -1; 122 private String mLastBssid; 123 private int mLastNetworkId; 124 private boolean mEnableRssiPolling = false; 125 private boolean mPasswordKeyMayBeIncorrect = false; 126 private int mReconnectCount = 0; 127 private boolean mIsScanMode = false; 128 129 /** 130 * Instance of the bluetooth headset helper. This needs to be created 131 * early because there is a delay before it actually 'connects', as 132 * noted by its javadoc. If we check before it is connected, it will be 133 * in an error state and we will not disable coexistence. 134 */ 135 private BluetoothHeadset mBluetoothHeadset; 136 137 private BluetoothA2dp mBluetoothA2dp; 138 139 private LinkProperties mLinkProperties; 140 141 // Held during driver load and unload 142 private static PowerManager.WakeLock sWakeLock; 143 144 private Context mContext; 145 146 private DhcpInfo mDhcpInfo; 147 private WifiInfo mWifiInfo; 148 private NetworkInfo mNetworkInfo; 149 private SupplicantStateTracker mSupplicantStateTracker; 150 /* Connection to a specific network involves disabling all networks, 151 * this flag tracks if networks need to be re-enabled */ 152 private boolean mEnableAllNetworks = false; 153 154 155 // Event log tags (must be in sync with event-log-tags) 156 private static final int EVENTLOG_WIFI_STATE_CHANGED = 50021; 157 private static final int EVENTLOG_WIFI_EVENT_HANDLED = 50022; 158 private static final int EVENTLOG_SUPPLICANT_STATE_CHANGED = 50023; 159 160 /* Load the driver */ 161 private static final int CMD_LOAD_DRIVER = 1; 162 /* Unload the driver */ 163 private static final int CMD_UNLOAD_DRIVER = 2; 164 /* Indicates driver load succeeded */ 165 private static final int CMD_LOAD_DRIVER_SUCCESS = 3; 166 /* Indicates driver load failed */ 167 private static final int CMD_LOAD_DRIVER_FAILURE = 4; 168 /* Indicates driver unload succeeded */ 169 private static final int CMD_UNLOAD_DRIVER_SUCCESS = 5; 170 /* Indicates driver unload failed */ 171 private static final int CMD_UNLOAD_DRIVER_FAILURE = 6; 172 173 /* Start the supplicant */ 174 private static final int CMD_START_SUPPLICANT = 11; 175 /* Stop the supplicant */ 176 private static final int CMD_STOP_SUPPLICANT = 12; 177 /* Start the driver */ 178 private static final int CMD_START_DRIVER = 13; 179 /* Start the driver */ 180 private static final int CMD_STOP_DRIVER = 14; 181 /* Indicates DHCP succeded */ 182 private static final int CMD_IP_CONFIG_SUCCESS = 15; 183 /* Indicates DHCP failed */ 184 private static final int CMD_IP_CONFIG_FAILURE = 16; 185 /* Re-configure interface */ 186 private static final int CMD_RECONFIGURE_IP = 17; 187 188 189 /* Start the soft access point */ 190 private static final int CMD_START_AP = 21; 191 /* Stop the soft access point */ 192 private static final int CMD_STOP_AP = 22; 193 194 195 /* Supplicant events */ 196 /* Connection to supplicant established */ 197 private static final int SUP_CONNECTION_EVENT = 31; 198 /* Connection to supplicant lost */ 199 private static final int SUP_DISCONNECTION_EVENT = 32; 200 /* Driver start completed */ 201 private static final int DRIVER_START_EVENT = 33; 202 /* Driver stop completed */ 203 private static final int DRIVER_STOP_EVENT = 34; 204 /* Network connection completed */ 205 private static final int NETWORK_CONNECTION_EVENT = 36; 206 /* Network disconnection completed */ 207 private static final int NETWORK_DISCONNECTION_EVENT = 37; 208 /* Scan results are available */ 209 private static final int SCAN_RESULTS_EVENT = 38; 210 /* Supplicate state changed */ 211 private static final int SUPPLICANT_STATE_CHANGE_EVENT = 39; 212 /* Password may be incorrect */ 213 private static final int PASSWORD_MAY_BE_INCORRECT_EVENT = 40; 214 215 /* Supplicant commands */ 216 /* Is supplicant alive ? */ 217 private static final int CMD_PING_SUPPLICANT = 51; 218 /* Add/update a network configuration */ 219 private static final int CMD_ADD_OR_UPDATE_NETWORK = 52; 220 /* Delete a network */ 221 private static final int CMD_REMOVE_NETWORK = 53; 222 /* Enable a network. The device will attempt a connection to the given network. */ 223 private static final int CMD_ENABLE_NETWORK = 54; 224 /* Disable a network. The device does not attempt a connection to the given network. */ 225 private static final int CMD_DISABLE_NETWORK = 55; 226 /* Blacklist network. De-prioritizes the given BSSID for connection. */ 227 private static final int CMD_BLACKLIST_NETWORK = 56; 228 /* Clear the blacklist network list */ 229 private static final int CMD_CLEAR_BLACKLIST = 57; 230 /* Save configuration */ 231 private static final int CMD_SAVE_CONFIG = 58; 232 233 /* Supplicant commands after driver start*/ 234 /* Initiate a scan */ 235 private static final int CMD_START_SCAN = 71; 236 /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */ 237 private static final int CMD_SET_SCAN_MODE = 72; 238 /* Set scan type. SCAN_ACTIVE or SCAN_PASSIVE */ 239 private static final int CMD_SET_SCAN_TYPE = 73; 240 /* Disconnect from a network */ 241 private static final int CMD_DISCONNECT = 74; 242 /* Reconnect to a network */ 243 private static final int CMD_RECONNECT = 75; 244 /* Reassociate to a network */ 245 private static final int CMD_REASSOCIATE = 76; 246 /* Set power mode 247 * POWER_MODE_ACTIVE 248 * POWER_MODE_AUTO 249 */ 250 private static final int CMD_SET_POWER_MODE = 77; 251 /* Set bluetooth co-existence 252 * BLUETOOTH_COEXISTENCE_MODE_ENABLED 253 * BLUETOOTH_COEXISTENCE_MODE_DISABLED 254 * BLUETOOTH_COEXISTENCE_MODE_SENSE 255 */ 256 private static final int CMD_SET_BLUETOOTH_COEXISTENCE = 78; 257 /* Enable/disable bluetooth scan mode 258 * true(1) 259 * false(0) 260 */ 261 private static final int CMD_SET_BLUETOOTH_SCAN_MODE = 79; 262 /* Set number of allowed channels */ 263 private static final int CMD_SET_NUM_ALLOWED_CHANNELS = 80; 264 /* Request connectivity manager wake lock before driver stop */ 265 private static final int CMD_REQUEST_CM_WAKELOCK = 81; 266 /* Enables RSSI poll */ 267 private static final int CMD_ENABLE_RSSI_POLL = 82; 268 /* RSSI poll */ 269 private static final int CMD_RSSI_POLL = 83; 270 /* Get current RSSI */ 271 private static final int CMD_GET_RSSI = 84; 272 /* Get approx current RSSI */ 273 private static final int CMD_GET_RSSI_APPROX = 85; 274 /* Get link speed on connection */ 275 private static final int CMD_GET_LINK_SPEED = 86; 276 /* Radio mac address */ 277 private static final int CMD_GET_MAC_ADDR = 87; 278 /* Set up packet filtering */ 279 private static final int CMD_START_PACKET_FILTERING = 88; 280 /* Clear packet filter */ 281 private static final int CMD_STOP_PACKET_FILTERING = 89; 282 /* Connect to a specified network (network id 283 * or WifiConfiguration) This involves increasing 284 * the priority of the network, enabling the network 285 * (while disabling others) and issuing a reconnect. 286 * Note that CMD_RECONNECT just does a reconnect to 287 * an existing network. All the networks get enabled 288 * upon a successful connection or a failure. 289 */ 290 private static final int CMD_CONNECT_NETWORK = 90; 291 /* Save the specified network. This involves adding 292 * an enabled network (if new) and updating the 293 * config and issuing a save on supplicant config. 294 */ 295 private static final int CMD_SAVE_NETWORK = 91; 296 /* Delete the specified network. This involves 297 * removing the network and issuing a save on 298 * supplicant config. 299 */ 300 private static final int CMD_FORGET_NETWORK = 92; 301 302 303 304 /** 305 * Interval in milliseconds between polling for connection 306 * status items that are not sent via asynchronous events. 307 * An example is RSSI (signal strength). 308 */ 309 private static final int POLL_RSSI_INTERVAL_MSECS = 3000; 310 311 private static final int CONNECT_MODE = 1; 312 private static final int SCAN_ONLY_MODE = 2; 313 314 private static final int SCAN_ACTIVE = 1; 315 private static final int SCAN_PASSIVE = 2; 316 317 /* Auto allows 802.11A/B/G operation */ 318 private static final int BAND_AUTO = 0; 319 /* 5GHz allows 802.11A operation */ 320 private static final int BAND_5G = 1; 321 /* 2.4GHz allows 802.11B/G operation */ 322 private static final int BAND_2G = 2; 323 324 /** 325 * The maximum number of times we will retry a connection to an access point 326 * for which we have failed in acquiring an IP address from DHCP. A value of 327 * N means that we will make N+1 connection attempts in all. 328 * <p> 329 * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default 330 * value if a Settings value is not present. 331 */ 332 private static final int DEFAULT_MAX_DHCP_RETRIES = 9; 333 334 private static final int DRIVER_POWER_MODE_ACTIVE = 1; 335 private static final int DRIVER_POWER_MODE_AUTO = 0; 336 337 /* Default parent state */ 338 private HierarchicalState mDefaultState = new DefaultState(); 339 /* Temporary initial state */ 340 private HierarchicalState mInitialState = new InitialState(); 341 /* Unloading the driver */ 342 private HierarchicalState mDriverUnloadingState = new DriverUnloadingState(); 343 /* Loading the driver */ 344 private HierarchicalState mDriverUnloadedState = new DriverUnloadedState(); 345 /* Driver load/unload failed */ 346 private HierarchicalState mDriverFailedState = new DriverFailedState(); 347 /* Driver loading */ 348 private HierarchicalState mDriverLoadingState = new DriverLoadingState(); 349 /* Driver loaded */ 350 private HierarchicalState mDriverLoadedState = new DriverLoadedState(); 351 /* Driver loaded, waiting for supplicant to start */ 352 private HierarchicalState mWaitForSupState = new WaitForSupState(); 353 354 /* Driver loaded and supplicant ready */ 355 private HierarchicalState mDriverSupReadyState = new DriverSupReadyState(); 356 /* Driver start issued, waiting for completed event */ 357 private HierarchicalState mDriverStartingState = new DriverStartingState(); 358 /* Driver started */ 359 private HierarchicalState mDriverStartedState = new DriverStartedState(); 360 /* Driver stopping */ 361 private HierarchicalState mDriverStoppingState = new DriverStoppingState(); 362 /* Driver stopped */ 363 private HierarchicalState mDriverStoppedState = new DriverStoppedState(); 364 /* Scan for networks, no connection will be established */ 365 private HierarchicalState mScanModeState = new ScanModeState(); 366 /* Connecting to an access point */ 367 private HierarchicalState mConnectModeState = new ConnectModeState(); 368 /* Fetching IP after network connection (assoc+auth complete) */ 369 private HierarchicalState mConnectingState = new ConnectingState(); 370 /* Connected with IP addr */ 371 private HierarchicalState mConnectedState = new ConnectedState(); 372 /* disconnect issued, waiting for network disconnect confirmation */ 373 private HierarchicalState mDisconnectingState = new DisconnectingState(); 374 /* Network is not connected, supplicant assoc+auth is not complete */ 375 private HierarchicalState mDisconnectedState = new DisconnectedState(); 376 377 /* Soft Ap is running */ 378 private HierarchicalState mSoftApStartedState = new SoftApStartedState(); 379 380 381 /** 382 * One of {@link WifiManager#WIFI_STATE_DISABLED}, 383 * {@link WifiManager#WIFI_STATE_DISABLING}, 384 * {@link WifiManager#WIFI_STATE_ENABLED}, 385 * {@link WifiManager#WIFI_STATE_ENABLING}, 386 * {@link WifiManager#WIFI_STATE_UNKNOWN} 387 * 388 */ 389 private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED); 390 391 /** 392 * One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 393 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 394 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 395 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 396 * {@link WifiManager#WIFI_AP_STATE_FAILED} 397 * 398 */ 399 private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED); 400 401 private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid()); 402 private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid()); 403 404 private final IBatteryStats mBatteryStats; 405 406 public WifiStateMachine(Context context) { 407 super(TAG); 408 409 mContext = context; 410 411 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); 412 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); 413 414 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 415 nwService = INetworkManagementService.Stub.asInterface(b); 416 417 mWifiMonitor = new WifiMonitor(this); 418 mDhcpInfo = new DhcpInfo(); 419 mWifiInfo = new WifiInfo(); 420 mInterfaceName = SystemProperties.get("wifi.interface", "tiwlan0"); 421 mSupplicantStateTracker = new SupplicantStateTracker(context, getHandler()); 422 423 mBluetoothHeadset = new BluetoothHeadset(mContext, null); 424 mLinkProperties = new LinkProperties(); 425 426 mNetworkInfo.setIsAvailable(false); 427 mLinkProperties.clear(); 428 mLastBssid = null; 429 mLastNetworkId = -1; 430 mLastSignalLevel = -1; 431 432 mScanResultCache = new LinkedHashMap<String, ScanResult>( 433 SCAN_RESULT_CACHE_SIZE, 0.75f, true) { 434 /* 435 * Limit the cache size by SCAN_RESULT_CACHE_SIZE 436 * elements 437 */ 438 @Override 439 public boolean removeEldestEntry(Map.Entry eldest) { 440 return SCAN_RESULT_CACHE_SIZE < this.size(); 441 } 442 }; 443 444 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 445 sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 446 447 addState(mDefaultState); 448 addState(mInitialState, mDefaultState); 449 addState(mDriverUnloadingState, mDefaultState); 450 addState(mDriverUnloadedState, mDefaultState); 451 addState(mDriverFailedState, mDriverUnloadedState); 452 addState(mDriverLoadingState, mDefaultState); 453 addState(mDriverLoadedState, mDefaultState); 454 addState(mWaitForSupState, mDriverLoadedState); 455 addState(mDriverSupReadyState, mDefaultState); 456 addState(mDriverStartingState, mDriverSupReadyState); 457 addState(mDriverStartedState, mDriverSupReadyState); 458 addState(mScanModeState, mDriverStartedState); 459 addState(mConnectModeState, mDriverStartedState); 460 addState(mConnectingState, mConnectModeState); 461 addState(mConnectedState, mConnectModeState); 462 addState(mDisconnectingState, mConnectModeState); 463 addState(mDisconnectedState, mConnectModeState); 464 addState(mDriverStoppingState, mDriverSupReadyState); 465 addState(mDriverStoppedState, mDriverSupReadyState); 466 addState(mSoftApStartedState, mDefaultState); 467 468 setInitialState(mInitialState); 469 470 if (DBG) setDbg(true); 471 472 //start the state machine 473 start(); 474 } 475 476 /********************************************************* 477 * Methods exposed for public use 478 ********************************************************/ 479 480 /** 481 * TODO: doc 482 */ 483 public boolean syncPingSupplicant() { 484 return sendSyncMessage(CMD_PING_SUPPLICANT).boolValue; 485 } 486 487 /** 488 * TODO: doc 489 */ 490 public void startScan(boolean forceActive) { 491 sendMessage(obtainMessage(CMD_START_SCAN, forceActive ? 492 SCAN_ACTIVE : SCAN_PASSIVE, 0)); 493 } 494 495 /** 496 * TODO: doc 497 */ 498 public void setWifiEnabled(boolean enable) { 499 mLastEnableUid.set(Binder.getCallingUid()); 500 if (enable) { 501 /* Argument is the state that is entered prior to load */ 502 sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0)); 503 sendMessage(CMD_START_SUPPLICANT); 504 } else { 505 sendMessage(CMD_STOP_SUPPLICANT); 506 /* Argument is the state that is entered upon success */ 507 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0)); 508 } 509 } 510 511 /** 512 * TODO: doc 513 */ 514 public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) { 515 mLastApEnableUid.set(Binder.getCallingUid()); 516 if (enable) { 517 /* Argument is the state that is entered prior to load */ 518 sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0)); 519 sendMessage(obtainMessage(CMD_START_AP, wifiConfig)); 520 } else { 521 sendMessage(CMD_STOP_AP); 522 /* Argument is the state that is entered upon success */ 523 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0)); 524 } 525 } 526 527 /** 528 * TODO: doc 529 */ 530 public int syncGetWifiState() { 531 return mWifiState.get(); 532 } 533 534 /** 535 * TODO: doc 536 */ 537 public String syncGetWifiStateByName() { 538 switch (mWifiState.get()) { 539 case WIFI_STATE_DISABLING: 540 return "disabling"; 541 case WIFI_STATE_DISABLED: 542 return "disabled"; 543 case WIFI_STATE_ENABLING: 544 return "enabling"; 545 case WIFI_STATE_ENABLED: 546 return "enabled"; 547 case WIFI_STATE_UNKNOWN: 548 return "unknown state"; 549 default: 550 return "[invalid state]"; 551 } 552 } 553 554 /** 555 * TODO: doc 556 */ 557 public int syncGetWifiApState() { 558 return mWifiApState.get(); 559 } 560 561 /** 562 * TODO: doc 563 */ 564 public String syncGetWifiApStateByName() { 565 switch (mWifiApState.get()) { 566 case WIFI_AP_STATE_DISABLING: 567 return "disabling"; 568 case WIFI_AP_STATE_DISABLED: 569 return "disabled"; 570 case WIFI_AP_STATE_ENABLING: 571 return "enabling"; 572 case WIFI_AP_STATE_ENABLED: 573 return "enabled"; 574 case WIFI_AP_STATE_FAILED: 575 return "failed"; 576 default: 577 return "[invalid state]"; 578 } 579 } 580 581 /** 582 * Get status information for the current connection, if any. 583 * @return a {@link WifiInfo} object containing information about the current connection 584 * 585 */ 586 public WifiInfo syncRequestConnectionInfo() { 587 return mWifiInfo; 588 } 589 590 public DhcpInfo syncGetDhcpInfo() { 591 synchronized (mDhcpInfo) { 592 return new DhcpInfo(mDhcpInfo); 593 } 594 } 595 596 /** 597 * TODO: doc 598 */ 599 public void setDriverStart(boolean enable) { 600 if (enable) { 601 sendMessage(CMD_START_DRIVER); 602 } else { 603 sendMessage(CMD_STOP_DRIVER); 604 } 605 } 606 607 /** 608 * TODO: doc 609 */ 610 public void setScanOnlyMode(boolean enable) { 611 if (enable) { 612 sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0)); 613 } else { 614 sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0)); 615 } 616 } 617 618 /** 619 * TODO: doc 620 */ 621 public void setScanType(boolean active) { 622 if (active) { 623 sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_ACTIVE, 0)); 624 } else { 625 sendMessage(obtainMessage(CMD_SET_SCAN_TYPE, SCAN_PASSIVE, 0)); 626 } 627 } 628 629 /** 630 * TODO: doc 631 */ 632 public List<ScanResult> syncGetScanResultsList() { 633 return mScanResults; 634 } 635 636 /** 637 * Disconnect from Access Point 638 */ 639 public void disconnectCommand() { 640 sendMessage(CMD_DISCONNECT); 641 } 642 643 /** 644 * Initiate a reconnection to AP 645 */ 646 public void reconnectCommand() { 647 sendMessage(CMD_RECONNECT); 648 } 649 650 /** 651 * Initiate a re-association to AP 652 */ 653 public void reassociateCommand() { 654 sendMessage(CMD_REASSOCIATE); 655 } 656 657 /** 658 * Add a network synchronously 659 * 660 * @return network id of the new network 661 */ 662 public int syncAddOrUpdateNetwork(WifiConfiguration config) { 663 return sendSyncMessage(CMD_ADD_OR_UPDATE_NETWORK, config).intValue; 664 } 665 666 public List<WifiConfiguration> syncGetConfiguredNetworks() { 667 return WifiConfigStore.getConfiguredNetworks(); 668 } 669 670 /** 671 * Delete a network 672 * 673 * @param networkId id of the network to be removed 674 */ 675 public boolean syncRemoveNetwork(int networkId) { 676 return sendSyncMessage(obtainMessage(CMD_REMOVE_NETWORK, networkId, 0)).boolValue; 677 } 678 679 private class EnableNetParams { 680 private int netId; 681 private boolean disableOthers; 682 EnableNetParams(int n, boolean b) { 683 netId = n; 684 disableOthers = b; 685 } 686 } 687 /** 688 * Enable a network 689 * 690 * @param netId network id of the network 691 * @param disableOthers true, if all other networks have to be disabled 692 * @return {@code true} if the operation succeeds, {@code false} otherwise 693 */ 694 public boolean syncEnableNetwork(int netId, boolean disableOthers) { 695 return sendSyncMessage(CMD_ENABLE_NETWORK, 696 new EnableNetParams(netId, disableOthers)).boolValue; 697 } 698 699 /** 700 * Disable a network 701 * 702 * @param netId network id of the network 703 * @return {@code true} if the operation succeeds, {@code false} otherwise 704 */ 705 public boolean syncDisableNetwork(int netId) { 706 return sendSyncMessage(obtainMessage(CMD_DISABLE_NETWORK, netId, 0)).boolValue; 707 } 708 709 /** 710 * Blacklist a BSSID. This will avoid the AP if there are 711 * alternate APs to connect 712 * 713 * @param bssid BSSID of the network 714 */ 715 public void addToBlacklist(String bssid) { 716 sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid)); 717 } 718 719 /** 720 * Clear the blacklist list 721 * 722 */ 723 public void clearBlacklist() { 724 sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST)); 725 } 726 727 public void connectNetwork(int netId) { 728 sendMessage(obtainMessage(CMD_CONNECT_NETWORK, netId, 0)); 729 } 730 731 public void connectNetwork(WifiConfiguration wifiConfig) { 732 /* arg1 is used to indicate netId, force a netId value of -1 when 733 * we are passing a configuration since the default value of 734 * 0 is a valid netId 735 */ 736 sendMessage(obtainMessage(CMD_CONNECT_NETWORK, -1, 0, wifiConfig)); 737 } 738 739 public void saveNetwork(WifiConfiguration wifiConfig) { 740 sendMessage(obtainMessage(CMD_SAVE_NETWORK, wifiConfig)); 741 } 742 743 public void forgetNetwork(int netId) { 744 sendMessage(obtainMessage(CMD_FORGET_NETWORK, netId, 0)); 745 } 746 747 public void enableRssiPolling(boolean enabled) { 748 sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0)); 749 } 750 /** 751 * Get RSSI to currently connected network 752 * 753 * @return RSSI value, -1 on failure 754 */ 755 public int syncGetRssi() { 756 return sendSyncMessage(CMD_GET_RSSI).intValue; 757 } 758 759 /** 760 * Get approx RSSI to currently connected network 761 * 762 * @return RSSI value, -1 on failure 763 */ 764 public int syncGetRssiApprox() { 765 return sendSyncMessage(CMD_GET_RSSI_APPROX).intValue; 766 } 767 768 /** 769 * Get link speed to currently connected network 770 * 771 * @return link speed, -1 on failure 772 */ 773 public int syncGetLinkSpeed() { 774 return sendSyncMessage(CMD_GET_LINK_SPEED).intValue; 775 } 776 777 /** 778 * Get MAC address of radio 779 * 780 * @return MAC address, null on failure 781 */ 782 public String syncGetMacAddress() { 783 return sendSyncMessage(CMD_GET_MAC_ADDR).stringValue; 784 } 785 786 /** 787 * Start packet filtering 788 */ 789 public void startPacketFiltering() { 790 sendMessage(CMD_START_PACKET_FILTERING); 791 } 792 793 /** 794 * Stop packet filtering 795 */ 796 public void stopPacketFiltering() { 797 sendMessage(CMD_STOP_PACKET_FILTERING); 798 } 799 800 /** 801 * Set power mode 802 * @param mode 803 * DRIVER_POWER_MODE_AUTO 804 * DRIVER_POWER_MODE_ACTIVE 805 */ 806 public void setPowerMode(int mode) { 807 sendMessage(obtainMessage(CMD_SET_POWER_MODE, mode, 0)); 808 } 809 810 /** 811 * Set the number of allowed radio frequency channels from the system 812 * setting value, if any. 813 */ 814 public void setNumAllowedChannels() { 815 try { 816 setNumAllowedChannels( 817 Settings.Secure.getInt(mContext.getContentResolver(), 818 Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS)); 819 } catch (Settings.SettingNotFoundException e) { 820 if (mNumAllowedChannels != 0) { 821 setNumAllowedChannels(mNumAllowedChannels); 822 } 823 // otherwise, use the driver default 824 } 825 } 826 827 /** 828 * Set the number of radio frequency channels that are allowed to be used 829 * in the current regulatory domain. 830 * @param numChannels the number of allowed channels. Must be greater than 0 831 * and less than or equal to 16. 832 */ 833 public void setNumAllowedChannels(int numChannels) { 834 sendMessage(obtainMessage(CMD_SET_NUM_ALLOWED_CHANNELS, numChannels, 0)); 835 } 836 837 /** 838 * Get number of allowed channels 839 * 840 * @return channel count, -1 on failure 841 * 842 * TODO: this is not a public API and needs to be removed in favor 843 * of asynchronous reporting. unused for now. 844 */ 845 public int getNumAllowedChannels() { 846 return -1; 847 } 848 849 /** 850 * Set bluetooth coex mode: 851 * 852 * @param mode 853 * BLUETOOTH_COEXISTENCE_MODE_ENABLED 854 * BLUETOOTH_COEXISTENCE_MODE_DISABLED 855 * BLUETOOTH_COEXISTENCE_MODE_SENSE 856 */ 857 public void setBluetoothCoexistenceMode(int mode) { 858 sendMessage(obtainMessage(CMD_SET_BLUETOOTH_COEXISTENCE, mode, 0)); 859 } 860 861 /** 862 * Enable or disable Bluetooth coexistence scan mode. When this mode is on, 863 * some of the low-level scan parameters used by the driver are changed to 864 * reduce interference with A2DP streaming. 865 * 866 * @param isBluetoothPlaying whether to enable or disable this mode 867 */ 868 public void setBluetoothScanMode(boolean isBluetoothPlaying) { 869 sendMessage(obtainMessage(CMD_SET_BLUETOOTH_SCAN_MODE, isBluetoothPlaying ? 1 : 0, 0)); 870 } 871 872 /** 873 * Save configuration on supplicant 874 * 875 * @return {@code true} if the operation succeeds, {@code false} otherwise 876 * 877 * TODO: deprecate this 878 */ 879 public boolean syncSaveConfig() { 880 return sendSyncMessage(CMD_SAVE_CONFIG).boolValue; 881 } 882 883 /** 884 * TODO: doc 885 */ 886 public void requestCmWakeLock() { 887 sendMessage(CMD_REQUEST_CM_WAKELOCK); 888 } 889 890 @Override 891 public String toString() { 892 StringBuffer sb = new StringBuffer(); 893 String LS = System.getProperty("line.separator"); 894 sb.append("current HSM state: ").append(getCurrentState().getName()).append(LS); 895 sb.append("mLinkProperties ").append(mLinkProperties).append(LS); 896 sb.append("mWifiInfo ").append(mWifiInfo).append(LS); 897 sb.append("mDhcpInfo ").append(mDhcpInfo).append(LS); 898 sb.append("mNetworkInfo ").append(mNetworkInfo).append(LS); 899 sb.append("mNumAllowedChannels ").append(mNumAllowedChannels).append(LS); 900 sb.append("mLastSignalLevel ").append(mLastSignalLevel).append(LS); 901 sb.append("mLastBssid ").append(mLastBssid).append(LS); 902 sb.append("mLastNetworkId ").append(mLastNetworkId).append(LS); 903 sb.append("mEnableAllNetworks ").append(mEnableAllNetworks).append(LS); 904 sb.append("mEnableRssiPolling ").append(mEnableRssiPolling).append(LS); 905 sb.append("mPasswordKeyMayBeIncorrect ").append(mPasswordKeyMayBeIncorrect).append(LS); 906 sb.append("mReconnectCount ").append(mReconnectCount).append(LS); 907 sb.append("mIsScanMode ").append(mIsScanMode).append(LS); 908 sb.append("Supplicant status").append(LS) 909 .append(WifiNative.statusCommand()).append(LS).append(LS); 910 911 sb.append(WifiConfigStore.dump()); 912 return sb.toString(); 913 } 914 915 /********************************************************* 916 * Internal private functions 917 ********************************************************/ 918 919 class SyncReturn { 920 boolean boolValue; 921 int intValue; 922 String stringValue; 923 Object objValue; 924 } 925 926 class SyncParams { 927 Object mParameter; 928 SyncReturn mSyncReturn; 929 SyncParams() { 930 mSyncReturn = new SyncReturn(); 931 } 932 SyncParams(Object p) { 933 mParameter = p; 934 mSyncReturn = new SyncReturn(); 935 } 936 } 937 938 /** 939 * message.obj is used to store SyncParams 940 */ 941 private SyncReturn syncedSend(Message msg) { 942 SyncParams syncParams = (SyncParams) msg.obj; 943 synchronized(syncParams) { 944 if (DBG) Log.d(TAG, "syncedSend " + msg); 945 sendMessage(msg); 946 try { 947 syncParams.wait(); 948 } catch (InterruptedException e) { 949 Log.e(TAG, "sendSyncMessage: unexpected interruption of wait()"); 950 return null; 951 } 952 } 953 return syncParams.mSyncReturn; 954 } 955 956 private SyncReturn sendSyncMessage(Message msg) { 957 SyncParams syncParams = new SyncParams(); 958 msg.obj = syncParams; 959 return syncedSend(msg); 960 } 961 962 private SyncReturn sendSyncMessage(int what, Object param) { 963 SyncParams syncParams = new SyncParams(param); 964 Message msg = obtainMessage(what, syncParams); 965 return syncedSend(msg); 966 } 967 968 969 private SyncReturn sendSyncMessage(int what) { 970 return sendSyncMessage(obtainMessage(what)); 971 } 972 973 private void notifyOnMsgObject(Message msg) { 974 SyncParams syncParams = (SyncParams) msg.obj; 975 if (syncParams != null) { 976 synchronized(syncParams) { 977 if (DBG) Log.d(TAG, "notifyOnMsgObject " + msg); 978 syncParams.notify(); 979 } 980 } 981 else { 982 Log.e(TAG, "Error! syncParams in notifyOnMsgObject is null"); 983 } 984 } 985 986 private void setWifiState(int wifiState) { 987 final int previousWifiState = mWifiState.get(); 988 989 try { 990 if (wifiState == WIFI_STATE_ENABLED) { 991 mBatteryStats.noteWifiOn(mLastEnableUid.get()); 992 } else if (wifiState == WIFI_STATE_DISABLED) { 993 mBatteryStats.noteWifiOff(mLastEnableUid.get()); 994 } 995 } catch (RemoteException e) { 996 Log.e(TAG, "Failed to note battery stats in wifi"); 997 } 998 999 mWifiState.set(wifiState); 1000 1001 if (DBG) Log.d(TAG, "setWifiState: " + syncGetWifiStateByName()); 1002 1003 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 1004 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1005 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 1006 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 1007 mContext.sendStickyBroadcast(intent); 1008 } 1009 1010 private void setWifiApState(int wifiApState) { 1011 final int previousWifiApState = mWifiApState.get(); 1012 1013 try { 1014 if (wifiApState == WIFI_AP_STATE_ENABLED) { 1015 mBatteryStats.noteWifiOn(mLastApEnableUid.get()); 1016 } else if (wifiApState == WIFI_AP_STATE_DISABLED) { 1017 mBatteryStats.noteWifiOff(mLastApEnableUid.get()); 1018 } 1019 } catch (RemoteException e) { 1020 Log.d(TAG, "Failed to note battery stats in wifi"); 1021 } 1022 1023 // Update state 1024 mWifiApState.set(wifiApState); 1025 1026 if (DBG) Log.d(TAG, "setWifiApState: " + syncGetWifiApStateByName()); 1027 1028 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 1029 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1030 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); 1031 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); 1032 mContext.sendStickyBroadcast(intent); 1033 } 1034 1035 /** 1036 * Parse the scan result line passed to us by wpa_supplicant (helper). 1037 * @param line the line to parse 1038 * @return the {@link ScanResult} object 1039 */ 1040 private ScanResult parseScanResult(String line) { 1041 ScanResult scanResult = null; 1042 if (line != null) { 1043 /* 1044 * Cache implementation (LinkedHashMap) is not synchronized, thus, 1045 * must synchronized here! 1046 */ 1047 synchronized (mScanResultCache) { 1048 String[] result = scanResultPattern.split(line); 1049 if (3 <= result.length && result.length <= 5) { 1050 String bssid = result[0]; 1051 // bssid | frequency | level | flags | ssid 1052 int frequency; 1053 int level; 1054 try { 1055 frequency = Integer.parseInt(result[1]); 1056 level = Integer.parseInt(result[2]); 1057 /* some implementations avoid negative values by adding 256 1058 * so we need to adjust for that here. 1059 */ 1060 if (level > 0) level -= 256; 1061 } catch (NumberFormatException e) { 1062 frequency = 0; 1063 level = 0; 1064 } 1065 1066 /* 1067 * The formatting of the results returned by 1068 * wpa_supplicant is intended to make the fields 1069 * line up nicely when printed, 1070 * not to make them easy to parse. So we have to 1071 * apply some heuristics to figure out which field 1072 * is the SSID and which field is the flags. 1073 */ 1074 String ssid; 1075 String flags; 1076 if (result.length == 4) { 1077 if (result[3].charAt(0) == '[') { 1078 flags = result[3]; 1079 ssid = ""; 1080 } else { 1081 flags = ""; 1082 ssid = result[3]; 1083 } 1084 } else if (result.length == 5) { 1085 flags = result[3]; 1086 ssid = result[4]; 1087 } else { 1088 // Here, we must have 3 fields: no flags and ssid 1089 // set 1090 flags = ""; 1091 ssid = ""; 1092 } 1093 1094 // bssid + ssid is the hash key 1095 String key = bssid + ssid; 1096 scanResult = mScanResultCache.get(key); 1097 if (scanResult != null) { 1098 scanResult.level = level; 1099 scanResult.SSID = ssid; 1100 scanResult.capabilities = flags; 1101 scanResult.frequency = frequency; 1102 } else { 1103 // Do not add scan results that have no SSID set 1104 if (0 < ssid.trim().length()) { 1105 scanResult = 1106 new ScanResult( 1107 ssid, bssid, flags, level, frequency); 1108 mScanResultCache.put(key, scanResult); 1109 } 1110 } 1111 } else { 1112 Log.w(TAG, "Misformatted scan result text with " + 1113 result.length + " fields: " + line); 1114 } 1115 } 1116 } 1117 1118 return scanResult; 1119 } 1120 1121 /** 1122 * scanResults input format 1123 * 00:bb:cc:dd:cc:ee 2427 166 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net1 1124 * 00:bb:cc:dd:cc:ff 2412 165 [WPA-EAP-TKIP][WPA2-EAP-CCMP] Net2 1125 */ 1126 private void setScanResults(String scanResults) { 1127 if (scanResults == null) { 1128 return; 1129 } 1130 1131 List<ScanResult> scanList = new ArrayList<ScanResult>(); 1132 1133 int lineCount = 0; 1134 1135 int scanResultsLen = scanResults.length(); 1136 // Parse the result string, keeping in mind that the last line does 1137 // not end with a newline. 1138 for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) { 1139 if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') { 1140 ++lineCount; 1141 1142 if (lineCount == 1) { 1143 lineBeg = lineEnd + 1; 1144 continue; 1145 } 1146 if (lineEnd > lineBeg) { 1147 String line = scanResults.substring(lineBeg, lineEnd); 1148 ScanResult scanResult = parseScanResult(line); 1149 if (scanResult != null) { 1150 scanList.add(scanResult); 1151 } else { 1152 Log.w(TAG, "misformatted scan result for: " + line); 1153 } 1154 } 1155 lineBeg = lineEnd + 1; 1156 } 1157 } 1158 1159 mScanResults = scanList; 1160 } 1161 1162 private String fetchSSID() { 1163 String status = WifiNative.statusCommand(); 1164 if (status == null) { 1165 return null; 1166 } 1167 // extract ssid from a series of "name=value" 1168 String[] lines = status.split("\n"); 1169 for (String line : lines) { 1170 String[] prop = line.split(" *= *"); 1171 if (prop.length < 2) continue; 1172 String name = prop[0]; 1173 String value = prop[1]; 1174 if (name.equalsIgnoreCase("ssid")) return value; 1175 } 1176 return null; 1177 } 1178 1179 private void configureLinkProperties() { 1180 try { 1181 mLinkProperties.setInterface(NetworkInterface.getByName(mInterfaceName)); 1182 } catch (SocketException e) { 1183 Log.e(TAG, "SocketException creating NetworkInterface from " + mInterfaceName + 1184 ". e=" + e); 1185 return; 1186 } catch (NullPointerException e) { 1187 Log.e(TAG, "NPE creating NetworkInterface. e=" + e); 1188 return; 1189 } 1190 // TODO - fix this for v6 1191 synchronized (mDhcpInfo) { 1192 mLinkProperties.addAddress(NetworkUtils.intToInetAddress(mDhcpInfo.ipAddress)); 1193 mLinkProperties.setGateway(NetworkUtils.intToInetAddress(mDhcpInfo.gateway)); 1194 mLinkProperties.addDns(NetworkUtils.intToInetAddress(mDhcpInfo.dns1)); 1195 mLinkProperties.addDns(NetworkUtils.intToInetAddress(mDhcpInfo.dns2)); 1196 } 1197 // TODO - add proxy info 1198 } 1199 1200 private int getMaxDhcpRetries() { 1201 return Settings.Secure.getInt(mContext.getContentResolver(), 1202 Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT, 1203 DEFAULT_MAX_DHCP_RETRIES); 1204 } 1205 1206 /** 1207 * Whether to disable coexistence mode while obtaining IP address. This 1208 * logic will return true only if the current bluetooth 1209 * headset/handsfree state is disconnected. This means if it is in an 1210 * error state, we will NOT disable coexistence mode to err on the side 1211 * of safety. 1212 * 1213 * @return Whether to disable coexistence mode. 1214 */ 1215 private boolean shouldDisableCoexistenceMode() { 1216 int state = mBluetoothHeadset.getState(mBluetoothHeadset.getCurrentHeadset()); 1217 return state == BluetoothHeadset.STATE_DISCONNECTED; 1218 } 1219 1220 private void checkIsBluetoothPlaying() { 1221 boolean isBluetoothPlaying = false; 1222 Set<BluetoothDevice> connected = mBluetoothA2dp.getConnectedSinks(); 1223 1224 for (BluetoothDevice device : connected) { 1225 if (mBluetoothA2dp.getSinkState(device) == BluetoothA2dp.STATE_PLAYING) { 1226 isBluetoothPlaying = true; 1227 break; 1228 } 1229 } 1230 setBluetoothScanMode(isBluetoothPlaying); 1231 } 1232 1233 private void sendScanResultsAvailableBroadcast() { 1234 if (!ActivityManagerNative.isSystemReady()) return; 1235 1236 mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); 1237 } 1238 1239 private void sendRssiChangeBroadcast(final int newRssi) { 1240 if (!ActivityManagerNative.isSystemReady()) return; 1241 1242 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); 1243 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); 1244 mContext.sendBroadcast(intent); 1245 } 1246 1247 private void sendNetworkStateChangeBroadcast(String bssid) { 1248 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); 1249 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 1250 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 1251 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo); 1252 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, mLinkProperties); 1253 if (bssid != null) 1254 intent.putExtra(WifiManager.EXTRA_BSSID, bssid); 1255 mContext.sendStickyBroadcast(intent); 1256 } 1257 1258 /* TODO: Unused for now, will be used when ip change on connected network is handled */ 1259 private void sendConfigChangeBroadcast() { 1260 if (!ActivityManagerNative.isSystemReady()) return; 1261 Intent intent = new Intent(WifiManager.CONFIG_CHANGED_ACTION); 1262 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, mLinkProperties); 1263 mContext.sendBroadcast(intent); 1264 } 1265 1266 private void sendSupplicantStateChangedBroadcast(StateChangeResult sc, boolean failedAuth) { 1267 Intent intent = new Intent(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); 1268 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 1269 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 1270 intent.putExtra(WifiManager.EXTRA_NEW_STATE, (Parcelable)sc.state); 1271 if (failedAuth) { 1272 intent.putExtra( 1273 WifiManager.EXTRA_SUPPLICANT_ERROR, 1274 WifiManager.ERROR_AUTHENTICATING); 1275 } 1276 mContext.sendStickyBroadcast(intent); 1277 } 1278 1279 private void sendSupplicantConnectionChangedBroadcast(boolean connected) { 1280 if (!ActivityManagerNative.isSystemReady()) return; 1281 1282 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 1283 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); 1284 mContext.sendBroadcast(intent); 1285 } 1286 1287 /** 1288 * Record the detailed state of a network. 1289 * @param state the new @{code DetailedState} 1290 */ 1291 private void setDetailedState(NetworkInfo.DetailedState state) { 1292 Log.d(TAG, "setDetailed state, old =" 1293 + mNetworkInfo.getDetailedState() + " and new state=" + state); 1294 if (state != mNetworkInfo.getDetailedState()) { 1295 mNetworkInfo.setDetailedState(state, null, null); 1296 } 1297 } 1298 1299 /** 1300 * Poll for info not reported via events 1301 * RSSI & Linkspeed 1302 */ 1303 private void requestPolledInfo() { 1304 int newRssi = WifiNative.getRssiCommand(); 1305 if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values 1306 /* some implementations avoid negative values by adding 256 1307 * so we need to adjust for that here. 1308 */ 1309 if (newRssi > 0) newRssi -= 256; 1310 mWifiInfo.setRssi(newRssi); 1311 /* 1312 * Rather then sending the raw RSSI out every time it 1313 * changes, we precalculate the signal level that would 1314 * be displayed in the status bar, and only send the 1315 * broadcast if that much more coarse-grained number 1316 * changes. This cuts down greatly on the number of 1317 * broadcasts, at the cost of not mWifiInforming others 1318 * interested in RSSI of all the changes in signal 1319 * level. 1320 */ 1321 // TODO: The second arg to the call below needs to be a symbol somewhere, but 1322 // it's actually the size of an array of icons that's private 1323 // to StatusBar Policy. 1324 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, 4); 1325 if (newSignalLevel != mLastSignalLevel) { 1326 sendRssiChangeBroadcast(newRssi); 1327 } 1328 mLastSignalLevel = newSignalLevel; 1329 } else { 1330 mWifiInfo.setRssi(-200); 1331 } 1332 int newLinkSpeed = WifiNative.getLinkSpeedCommand(); 1333 if (newLinkSpeed != -1) { 1334 mWifiInfo.setLinkSpeed(newLinkSpeed); 1335 } 1336 } 1337 1338 /** 1339 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 1340 * using the interface, stopping DHCP & disabling interface 1341 */ 1342 private void handleNetworkDisconnect() { 1343 Log.d(TAG, "Reset connections and stopping DHCP"); 1344 1345 /* 1346 * Reset connections & stop DHCP 1347 */ 1348 NetworkUtils.resetConnections(mInterfaceName); 1349 1350 if (!NetworkUtils.stopDhcp(mInterfaceName)) { 1351 Log.e(TAG, "Could not stop DHCP"); 1352 } 1353 1354 /* Disable interface */ 1355 NetworkUtils.disableInterface(mInterfaceName); 1356 1357 /* send event to CM & network change broadcast */ 1358 setDetailedState(DetailedState.DISCONNECTED); 1359 sendNetworkStateChangeBroadcast(mLastBssid); 1360 1361 /* Reset data structures */ 1362 mWifiInfo.setIpAddress(0); 1363 mWifiInfo.setBSSID(null); 1364 mWifiInfo.setSSID(null); 1365 mWifiInfo.setNetworkId(-1); 1366 1367 /* Clear network properties */ 1368 mLinkProperties.clear(); 1369 1370 mLastBssid= null; 1371 mLastNetworkId = -1; 1372 1373 } 1374 1375 1376 /********************************************************* 1377 * Notifications from WifiMonitor 1378 ********************************************************/ 1379 1380 /** 1381 * A structure for supplying information about a supplicant state 1382 * change in the STATE_CHANGE event message that comes from the 1383 * WifiMonitor 1384 * thread. 1385 */ 1386 private static class StateChangeResult { 1387 StateChangeResult(int networkId, String BSSID, Object state) { 1388 this.state = state; 1389 this.BSSID = BSSID; 1390 this.networkId = networkId; 1391 } 1392 int networkId; 1393 String BSSID; 1394 Object state; 1395 } 1396 1397 /** 1398 * Send the tracker a notification that a user-entered password key 1399 * may be incorrect (i.e., caused authentication to fail). 1400 */ 1401 void notifyPasswordKeyMayBeIncorrect() { 1402 sendMessage(PASSWORD_MAY_BE_INCORRECT_EVENT); 1403 } 1404 1405 /** 1406 * Send the tracker a notification that a connection to the supplicant 1407 * daemon has been established. 1408 */ 1409 void notifySupplicantConnection() { 1410 sendMessage(SUP_CONNECTION_EVENT); 1411 } 1412 1413 /** 1414 * Send the tracker a notification that a connection to the supplicant 1415 * daemon has been established. 1416 */ 1417 void notifySupplicantLost() { 1418 sendMessage(SUP_DISCONNECTION_EVENT); 1419 } 1420 1421 /** 1422 * Send the tracker a notification that the state of Wifi connectivity 1423 * has changed. 1424 * @param networkId the configured network on which the state change occurred 1425 * @param newState the new network state 1426 * @param BSSID when the new state is {@link DetailedState#CONNECTED 1427 * NetworkInfo.DetailedState.CONNECTED}, 1428 * this is the MAC address of the access point. Otherwise, it 1429 * is {@code null}. 1430 */ 1431 void notifyNetworkStateChange(DetailedState newState, String BSSID, int networkId) { 1432 if (newState == NetworkInfo.DetailedState.CONNECTED) { 1433 sendMessage(obtainMessage(NETWORK_CONNECTION_EVENT, 1434 new StateChangeResult(networkId, BSSID, newState))); 1435 } else { 1436 sendMessage(obtainMessage(NETWORK_DISCONNECTION_EVENT, 1437 new StateChangeResult(networkId, BSSID, newState))); 1438 } 1439 } 1440 1441 /** 1442 * Send the tracker a notification that the state of the supplicant 1443 * has changed. 1444 * @param networkId the configured network on which the state change occurred 1445 * @param newState the new {@code SupplicantState} 1446 */ 1447 void notifySupplicantStateChange(int networkId, String BSSID, SupplicantState newState) { 1448 sendMessage(obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT, 1449 new StateChangeResult(networkId, BSSID, newState))); 1450 } 1451 1452 /** 1453 * Send the tracker a notification that a scan has completed, and results 1454 * are available. 1455 */ 1456 void notifyScanResultsAvailable() { 1457 /** 1458 * Switch scan mode over to passive. 1459 * Turning off scan-only mode happens only in "Connect" mode 1460 */ 1461 setScanType(false); 1462 sendMessage(SCAN_RESULTS_EVENT); 1463 } 1464 1465 void notifyDriverStarted() { 1466 sendMessage(DRIVER_START_EVENT); 1467 } 1468 1469 void notifyDriverStopped() { 1470 sendMessage(DRIVER_STOP_EVENT); 1471 } 1472 1473 void notifyDriverHung() { 1474 setWifiEnabled(false); 1475 setWifiEnabled(true); 1476 } 1477 1478 1479 /******************************************************** 1480 * HSM states 1481 *******************************************************/ 1482 1483 class DefaultState extends HierarchicalState { 1484 @Override 1485 public boolean processMessage(Message message) { 1486 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1487 SyncParams syncParams; 1488 switch (message.what) { 1489 /* Synchronous call returns */ 1490 case CMD_PING_SUPPLICANT: 1491 case CMD_REMOVE_NETWORK: 1492 case CMD_ENABLE_NETWORK: 1493 case CMD_DISABLE_NETWORK: 1494 case CMD_ADD_OR_UPDATE_NETWORK: 1495 case CMD_GET_RSSI: 1496 case CMD_GET_RSSI_APPROX: 1497 case CMD_GET_LINK_SPEED: 1498 case CMD_GET_MAC_ADDR: 1499 case CMD_SAVE_CONFIG: 1500 syncParams = (SyncParams) message.obj; 1501 syncParams.mSyncReturn.boolValue = false; 1502 syncParams.mSyncReturn.intValue = -1; 1503 syncParams.mSyncReturn.stringValue = null; 1504 notifyOnMsgObject(message); 1505 break; 1506 case CMD_ENABLE_RSSI_POLL: 1507 mEnableRssiPolling = (message.arg1 == 1); 1508 mSupplicantStateTracker.sendMessage(CMD_ENABLE_RSSI_POLL); 1509 break; 1510 /* Discard */ 1511 case CMD_LOAD_DRIVER: 1512 case CMD_UNLOAD_DRIVER: 1513 case CMD_START_SUPPLICANT: 1514 case CMD_STOP_SUPPLICANT: 1515 case CMD_START_DRIVER: 1516 case CMD_STOP_DRIVER: 1517 case CMD_START_AP: 1518 case CMD_STOP_AP: 1519 case CMD_START_SCAN: 1520 case CMD_DISCONNECT: 1521 case CMD_RECONNECT: 1522 case CMD_REASSOCIATE: 1523 case CMD_RECONFIGURE_IP: 1524 case SUP_CONNECTION_EVENT: 1525 case SUP_DISCONNECTION_EVENT: 1526 case DRIVER_START_EVENT: 1527 case DRIVER_STOP_EVENT: 1528 case NETWORK_CONNECTION_EVENT: 1529 case NETWORK_DISCONNECTION_EVENT: 1530 case SCAN_RESULTS_EVENT: 1531 case SUPPLICANT_STATE_CHANGE_EVENT: 1532 case PASSWORD_MAY_BE_INCORRECT_EVENT: 1533 case CMD_BLACKLIST_NETWORK: 1534 case CMD_CLEAR_BLACKLIST: 1535 case CMD_SET_SCAN_MODE: 1536 case CMD_SET_SCAN_TYPE: 1537 case CMD_SET_POWER_MODE: 1538 case CMD_SET_BLUETOOTH_COEXISTENCE: 1539 case CMD_SET_BLUETOOTH_SCAN_MODE: 1540 case CMD_SET_NUM_ALLOWED_CHANNELS: 1541 case CMD_REQUEST_CM_WAKELOCK: 1542 case CMD_CONNECT_NETWORK: 1543 case CMD_SAVE_NETWORK: 1544 case CMD_FORGET_NETWORK: 1545 break; 1546 default: 1547 Log.e(TAG, "Error! unhandled message" + message); 1548 break; 1549 } 1550 return HANDLED; 1551 } 1552 } 1553 1554 class InitialState extends HierarchicalState { 1555 @Override 1556 //TODO: could move logging into a common class 1557 public void enter() { 1558 if (DBG) Log.d(TAG, getName() + "\n"); 1559 // [31-8] Reserved for future use 1560 // [7 - 0] HSM state change 1561 // 50021 wifi_state_changed (custom|1|5) 1562 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1563 1564 if (WifiNative.isDriverLoaded()) { 1565 transitionTo(mDriverLoadedState); 1566 } 1567 else { 1568 transitionTo(mDriverUnloadedState); 1569 } 1570 } 1571 } 1572 1573 class DriverLoadingState extends HierarchicalState { 1574 @Override 1575 public void enter() { 1576 if (DBG) Log.d(TAG, getName() + "\n"); 1577 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1578 1579 final Message message = new Message(); 1580 message.copyFrom(getCurrentMessage()); 1581 /* TODO: add a timeout to fail when driver load is hung. 1582 * Similarly for driver unload. 1583 */ 1584 new Thread(new Runnable() { 1585 public void run() { 1586 sWakeLock.acquire(); 1587 //enabling state 1588 switch(message.arg1) { 1589 case WIFI_STATE_ENABLING: 1590 setWifiState(WIFI_STATE_ENABLING); 1591 break; 1592 case WIFI_AP_STATE_ENABLING: 1593 setWifiApState(WIFI_AP_STATE_ENABLING); 1594 break; 1595 } 1596 1597 if(WifiNative.loadDriver()) { 1598 Log.d(TAG, "Driver load successful"); 1599 sendMessage(CMD_LOAD_DRIVER_SUCCESS); 1600 } else { 1601 Log.e(TAG, "Failed to load driver!"); 1602 switch(message.arg1) { 1603 case WIFI_STATE_ENABLING: 1604 setWifiState(WIFI_STATE_UNKNOWN); 1605 break; 1606 case WIFI_AP_STATE_ENABLING: 1607 setWifiApState(WIFI_AP_STATE_FAILED); 1608 break; 1609 } 1610 sendMessage(CMD_LOAD_DRIVER_FAILURE); 1611 } 1612 sWakeLock.release(); 1613 } 1614 }).start(); 1615 } 1616 1617 @Override 1618 public boolean processMessage(Message message) { 1619 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1620 switch (message.what) { 1621 case CMD_LOAD_DRIVER_SUCCESS: 1622 transitionTo(mDriverLoadedState); 1623 break; 1624 case CMD_LOAD_DRIVER_FAILURE: 1625 transitionTo(mDriverFailedState); 1626 break; 1627 case CMD_LOAD_DRIVER: 1628 case CMD_UNLOAD_DRIVER: 1629 case CMD_START_SUPPLICANT: 1630 case CMD_STOP_SUPPLICANT: 1631 case CMD_START_AP: 1632 case CMD_STOP_AP: 1633 case CMD_START_DRIVER: 1634 case CMD_STOP_DRIVER: 1635 case CMD_SET_SCAN_MODE: 1636 case CMD_SET_SCAN_TYPE: 1637 case CMD_SET_POWER_MODE: 1638 case CMD_SET_BLUETOOTH_COEXISTENCE: 1639 case CMD_SET_BLUETOOTH_SCAN_MODE: 1640 case CMD_SET_NUM_ALLOWED_CHANNELS: 1641 case CMD_START_PACKET_FILTERING: 1642 case CMD_STOP_PACKET_FILTERING: 1643 deferMessage(message); 1644 break; 1645 default: 1646 return NOT_HANDLED; 1647 } 1648 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1649 return HANDLED; 1650 } 1651 } 1652 1653 class DriverLoadedState extends HierarchicalState { 1654 @Override 1655 public void enter() { 1656 if (DBG) Log.d(TAG, getName() + "\n"); 1657 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1658 } 1659 @Override 1660 public boolean processMessage(Message message) { 1661 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1662 switch(message.what) { 1663 case CMD_UNLOAD_DRIVER: 1664 transitionTo(mDriverUnloadingState); 1665 break; 1666 case CMD_START_SUPPLICANT: 1667 if(WifiNative.startSupplicant()) { 1668 Log.d(TAG, "Supplicant start successful"); 1669 mWifiMonitor.startMonitoring(); 1670 setWifiState(WIFI_STATE_ENABLED); 1671 transitionTo(mWaitForSupState); 1672 } else { 1673 Log.e(TAG, "Failed to start supplicant!"); 1674 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0)); 1675 } 1676 break; 1677 case CMD_START_AP: 1678 try { 1679 nwService.startAccessPoint((WifiConfiguration) message.obj, 1680 mInterfaceName, 1681 SOFTAP_IFACE); 1682 } catch(Exception e) { 1683 Log.e(TAG, "Exception in startAccessPoint()"); 1684 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0)); 1685 break; 1686 } 1687 Log.d(TAG, "Soft AP start successful"); 1688 setWifiApState(WIFI_AP_STATE_ENABLED); 1689 transitionTo(mSoftApStartedState); 1690 break; 1691 default: 1692 return NOT_HANDLED; 1693 } 1694 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1695 return HANDLED; 1696 } 1697 } 1698 1699 class DriverUnloadingState extends HierarchicalState { 1700 @Override 1701 public void enter() { 1702 if (DBG) Log.d(TAG, getName() + "\n"); 1703 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1704 1705 final Message message = new Message(); 1706 message.copyFrom(getCurrentMessage()); 1707 new Thread(new Runnable() { 1708 public void run() { 1709 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1710 sWakeLock.acquire(); 1711 if(WifiNative.unloadDriver()) { 1712 Log.d(TAG, "Driver unload successful"); 1713 sendMessage(CMD_UNLOAD_DRIVER_SUCCESS); 1714 1715 switch(message.arg1) { 1716 case WIFI_STATE_DISABLED: 1717 case WIFI_STATE_UNKNOWN: 1718 setWifiState(message.arg1); 1719 break; 1720 case WIFI_AP_STATE_DISABLED: 1721 case WIFI_AP_STATE_FAILED: 1722 setWifiApState(message.arg1); 1723 break; 1724 } 1725 } else { 1726 Log.e(TAG, "Failed to unload driver!"); 1727 sendMessage(CMD_UNLOAD_DRIVER_FAILURE); 1728 1729 switch(message.arg1) { 1730 case WIFI_STATE_DISABLED: 1731 case WIFI_STATE_UNKNOWN: 1732 setWifiState(WIFI_STATE_UNKNOWN); 1733 break; 1734 case WIFI_AP_STATE_DISABLED: 1735 case WIFI_AP_STATE_FAILED: 1736 setWifiApState(WIFI_AP_STATE_FAILED); 1737 break; 1738 } 1739 } 1740 sWakeLock.release(); 1741 } 1742 }).start(); 1743 } 1744 1745 @Override 1746 public boolean processMessage(Message message) { 1747 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1748 switch (message.what) { 1749 case CMD_UNLOAD_DRIVER_SUCCESS: 1750 transitionTo(mDriverUnloadedState); 1751 break; 1752 case CMD_UNLOAD_DRIVER_FAILURE: 1753 transitionTo(mDriverFailedState); 1754 break; 1755 case CMD_LOAD_DRIVER: 1756 case CMD_UNLOAD_DRIVER: 1757 case CMD_START_SUPPLICANT: 1758 case CMD_STOP_SUPPLICANT: 1759 case CMD_START_AP: 1760 case CMD_STOP_AP: 1761 case CMD_START_DRIVER: 1762 case CMD_STOP_DRIVER: 1763 case CMD_SET_SCAN_MODE: 1764 case CMD_SET_SCAN_TYPE: 1765 case CMD_SET_POWER_MODE: 1766 case CMD_SET_BLUETOOTH_COEXISTENCE: 1767 case CMD_SET_BLUETOOTH_SCAN_MODE: 1768 case CMD_SET_NUM_ALLOWED_CHANNELS: 1769 case CMD_START_PACKET_FILTERING: 1770 case CMD_STOP_PACKET_FILTERING: 1771 deferMessage(message); 1772 break; 1773 default: 1774 return NOT_HANDLED; 1775 } 1776 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1777 return HANDLED; 1778 } 1779 } 1780 1781 class DriverUnloadedState extends HierarchicalState { 1782 @Override 1783 public void enter() { 1784 if (DBG) Log.d(TAG, getName() + "\n"); 1785 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1786 } 1787 @Override 1788 public boolean processMessage(Message message) { 1789 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1790 switch (message.what) { 1791 case CMD_LOAD_DRIVER: 1792 transitionTo(mDriverLoadingState); 1793 break; 1794 default: 1795 return NOT_HANDLED; 1796 } 1797 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1798 return HANDLED; 1799 } 1800 } 1801 1802 class DriverFailedState extends HierarchicalState { 1803 @Override 1804 public void enter() { 1805 Log.e(TAG, getName() + "\n"); 1806 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1807 } 1808 @Override 1809 public boolean processMessage(Message message) { 1810 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1811 return NOT_HANDLED; 1812 } 1813 } 1814 1815 1816 class WaitForSupState extends HierarchicalState { 1817 @Override 1818 public void enter() { 1819 if (DBG) Log.d(TAG, getName() + "\n"); 1820 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1821 } 1822 @Override 1823 public boolean processMessage(Message message) { 1824 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1825 switch(message.what) { 1826 case SUP_CONNECTION_EVENT: 1827 Log.d(TAG, "Supplicant connection established"); 1828 mSupplicantStateTracker.resetSupplicantState(); 1829 /* Initialize data structures */ 1830 mLastBssid = null; 1831 mLastNetworkId = -1; 1832 mLastSignalLevel = -1; 1833 1834 mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand()); 1835 1836 WifiConfigStore.initialize(mContext); 1837 1838 //TODO: initialize and fix multicast filtering 1839 //mWM.initializeMulticastFiltering(); 1840 1841 if (mBluetoothA2dp == null) { 1842 mBluetoothA2dp = new BluetoothA2dp(mContext); 1843 } 1844 checkIsBluetoothPlaying(); 1845 1846 sendSupplicantConnectionChangedBroadcast(true); 1847 transitionTo(mDriverSupReadyState); 1848 break; 1849 case CMD_STOP_SUPPLICANT: 1850 Log.d(TAG, "Stop supplicant received"); 1851 WifiNative.stopSupplicant(); 1852 transitionTo(mDriverLoadedState); 1853 break; 1854 /* Fail soft ap when waiting for supplicant start */ 1855 case CMD_START_AP: 1856 Log.d(TAG, "Failed to start soft AP with a running supplicant"); 1857 setWifiApState(WIFI_AP_STATE_FAILED); 1858 break; 1859 case CMD_START_DRIVER: 1860 case CMD_STOP_DRIVER: 1861 case CMD_SET_SCAN_MODE: 1862 case CMD_SET_SCAN_TYPE: 1863 case CMD_SET_POWER_MODE: 1864 case CMD_SET_BLUETOOTH_COEXISTENCE: 1865 case CMD_SET_BLUETOOTH_SCAN_MODE: 1866 case CMD_SET_NUM_ALLOWED_CHANNELS: 1867 case CMD_START_PACKET_FILTERING: 1868 case CMD_STOP_PACKET_FILTERING: 1869 deferMessage(message); 1870 break; 1871 case CMD_STOP_AP: 1872 case CMD_START_SUPPLICANT: 1873 case CMD_UNLOAD_DRIVER: 1874 break; 1875 default: 1876 return NOT_HANDLED; 1877 } 1878 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1879 return HANDLED; 1880 } 1881 } 1882 1883 class DriverSupReadyState extends HierarchicalState { 1884 @Override 1885 public void enter() { 1886 if (DBG) Log.d(TAG, getName() + "\n"); 1887 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 1888 /* Initialize for connect mode operation at start */ 1889 mIsScanMode = false; 1890 } 1891 @Override 1892 public boolean processMessage(Message message) { 1893 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 1894 SyncParams syncParams; 1895 WifiConfiguration config; 1896 switch(message.what) { 1897 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ 1898 Log.d(TAG, "Stop supplicant received"); 1899 WifiNative.stopSupplicant(); 1900 //$FALL-THROUGH$ 1901 case SUP_DISCONNECTION_EVENT: /* Supplicant died */ 1902 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1903 WifiNative.closeSupplicantConnection(); 1904 handleNetworkDisconnect(); 1905 sendSupplicantConnectionChangedBroadcast(false); 1906 mSupplicantStateTracker.resetSupplicantState(); 1907 transitionTo(mDriverLoadedState); 1908 1909 /* When supplicant dies, unload driver and enter failed state */ 1910 //TODO: consider bringing up supplicant again 1911 if (message.what == SUP_DISCONNECTION_EVENT) { 1912 Log.d(TAG, "Supplicant died, unloading driver"); 1913 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0)); 1914 } 1915 break; 1916 case CMD_START_DRIVER: 1917 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1918 WifiNative.startDriverCommand(); 1919 transitionTo(mDriverStartingState); 1920 break; 1921 case SCAN_RESULTS_EVENT: 1922 setScanResults(WifiNative.scanResultsCommand()); 1923 sendScanResultsAvailableBroadcast(); 1924 break; 1925 case CMD_PING_SUPPLICANT: 1926 syncParams = (SyncParams) message.obj; 1927 syncParams.mSyncReturn.boolValue = WifiNative.pingCommand(); 1928 notifyOnMsgObject(message); 1929 break; 1930 case CMD_ADD_OR_UPDATE_NETWORK: 1931 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1932 syncParams = (SyncParams) message.obj; 1933 config = (WifiConfiguration) syncParams.mParameter; 1934 syncParams.mSyncReturn.intValue = WifiConfigStore.addOrUpdateNetwork(config); 1935 notifyOnMsgObject(message); 1936 break; 1937 case CMD_REMOVE_NETWORK: 1938 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1939 syncParams = (SyncParams) message.obj; 1940 syncParams.mSyncReturn.boolValue = WifiConfigStore.removeNetwork( 1941 message.arg1); 1942 notifyOnMsgObject(message); 1943 break; 1944 case CMD_ENABLE_NETWORK: 1945 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1946 syncParams = (SyncParams) message.obj; 1947 EnableNetParams enableNetParams = (EnableNetParams) syncParams.mParameter; 1948 syncParams.mSyncReturn.boolValue = WifiConfigStore.enableNetwork( 1949 enableNetParams.netId, enableNetParams.disableOthers); 1950 notifyOnMsgObject(message); 1951 break; 1952 case CMD_DISABLE_NETWORK: 1953 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1954 syncParams = (SyncParams) message.obj; 1955 syncParams.mSyncReturn.boolValue = WifiConfigStore.disableNetwork( 1956 message.arg1); 1957 notifyOnMsgObject(message); 1958 break; 1959 case CMD_BLACKLIST_NETWORK: 1960 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1961 WifiNative.addToBlacklistCommand((String)message.obj); 1962 break; 1963 case CMD_CLEAR_BLACKLIST: 1964 WifiNative.clearBlacklistCommand(); 1965 break; 1966 case CMD_SAVE_CONFIG: 1967 syncParams = (SyncParams) message.obj; 1968 syncParams.mSyncReturn.boolValue = WifiConfigStore.saveConfig(); 1969 notifyOnMsgObject(message); 1970 // Inform the backup manager about a data change 1971 IBackupManager ibm = IBackupManager.Stub.asInterface( 1972 ServiceManager.getService(Context.BACKUP_SERVICE)); 1973 if (ibm != null) { 1974 try { 1975 ibm.dataChanged("com.android.providers.settings"); 1976 } catch (Exception e) { 1977 // Try again later 1978 } 1979 } 1980 break; 1981 case CMD_GET_MAC_ADDR: 1982 syncParams = (SyncParams) message.obj; 1983 syncParams.mSyncReturn.stringValue = WifiNative.getMacAddressCommand(); 1984 notifyOnMsgObject(message); 1985 break; 1986 /* Cannot start soft AP while in client mode */ 1987 case CMD_START_AP: 1988 Log.d(TAG, "Failed to start soft AP with a running supplicant"); 1989 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 1990 setWifiApState(WIFI_AP_STATE_FAILED); 1991 break; 1992 case CMD_SET_SCAN_MODE: 1993 mIsScanMode = (message.arg1 == SCAN_ONLY_MODE); 1994 break; 1995 case CMD_SAVE_NETWORK: 1996 config = (WifiConfiguration) message.obj; 1997 WifiConfigStore.saveNetwork(config); 1998 break; 1999 case CMD_FORGET_NETWORK: 2000 WifiConfigStore.forgetNetwork(message.arg1); 2001 break; 2002 default: 2003 return NOT_HANDLED; 2004 } 2005 return HANDLED; 2006 } 2007 } 2008 2009 class DriverStartingState extends HierarchicalState { 2010 @Override 2011 public void enter() { 2012 if (DBG) Log.d(TAG, getName() + "\n"); 2013 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2014 } 2015 @Override 2016 public boolean processMessage(Message message) { 2017 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2018 switch(message.what) { 2019 case DRIVER_START_EVENT: 2020 transitionTo(mDriverStartedState); 2021 break; 2022 /* Queue driver commands & connection events */ 2023 case CMD_START_DRIVER: 2024 case CMD_STOP_DRIVER: 2025 case SUPPLICANT_STATE_CHANGE_EVENT: 2026 case NETWORK_CONNECTION_EVENT: 2027 case NETWORK_DISCONNECTION_EVENT: 2028 case PASSWORD_MAY_BE_INCORRECT_EVENT: 2029 case CMD_SET_SCAN_TYPE: 2030 case CMD_SET_POWER_MODE: 2031 case CMD_SET_BLUETOOTH_COEXISTENCE: 2032 case CMD_SET_BLUETOOTH_SCAN_MODE: 2033 case CMD_SET_NUM_ALLOWED_CHANNELS: 2034 case CMD_START_PACKET_FILTERING: 2035 case CMD_STOP_PACKET_FILTERING: 2036 case CMD_START_SCAN: 2037 case CMD_DISCONNECT: 2038 case CMD_REASSOCIATE: 2039 case CMD_RECONNECT: 2040 deferMessage(message); 2041 break; 2042 default: 2043 return NOT_HANDLED; 2044 } 2045 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2046 return HANDLED; 2047 } 2048 } 2049 2050 class DriverStartedState extends HierarchicalState { 2051 @Override 2052 public void enter() { 2053 if (DBG) Log.d(TAG, getName() + "\n"); 2054 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2055 2056 try { 2057 mBatteryStats.noteWifiRunning(); 2058 } catch (RemoteException ignore) {} 2059 2060 /* Initialize channel count */ 2061 setNumAllowedChannels(); 2062 /* 2063 * STOPSHIP 2064 * TODO: We are having 11A issues that Broadcom is looking 2065 * to resolve, this is a temporary fix to allow only 11B/G 2066 * and help improve GoogleGuest connectivity 2067 * We also need to add the UI for band control 2068 */ 2069 WifiNative.setBandCommand(BAND_2G); 2070 2071 if (mIsScanMode) { 2072 WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE); 2073 WifiNative.disconnectCommand(); 2074 transitionTo(mScanModeState); 2075 } else { 2076 WifiNative.setScanResultHandlingCommand(CONNECT_MODE); 2077 /* If supplicant has already connected, before we could finish establishing 2078 * the control channel connection, we miss all the supplicant events. 2079 * Disconnect and reconnect when driver has started to ensure we receive 2080 * all supplicant events. 2081 * 2082 * TODO: This is a bit unclean, ideally the supplicant should never 2083 * connect until told to do so by the framework 2084 */ 2085 WifiNative.disconnectCommand(); 2086 WifiNative.reconnectCommand(); 2087 transitionTo(mConnectModeState); 2088 } 2089 } 2090 @Override 2091 public boolean processMessage(Message message) { 2092 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2093 SyncParams syncParams; 2094 switch(message.what) { 2095 case CMD_SET_SCAN_TYPE: 2096 if (message.arg1 == SCAN_ACTIVE) { 2097 WifiNative.setScanModeCommand(true); 2098 } else { 2099 WifiNative.setScanModeCommand(false); 2100 } 2101 break; 2102 case CMD_SET_POWER_MODE: 2103 WifiNative.setPowerModeCommand(message.arg1); 2104 break; 2105 case CMD_SET_BLUETOOTH_COEXISTENCE: 2106 WifiNative.setBluetoothCoexistenceModeCommand(message.arg1); 2107 break; 2108 case CMD_SET_BLUETOOTH_SCAN_MODE: 2109 WifiNative.setBluetoothCoexistenceScanModeCommand(message.arg1 == 1); 2110 break; 2111 case CMD_SET_NUM_ALLOWED_CHANNELS: 2112 mNumAllowedChannels = message.arg1; 2113 WifiNative.setNumAllowedChannelsCommand(message.arg1); 2114 break; 2115 case CMD_START_DRIVER: 2116 /* Ignore another driver start */ 2117 break; 2118 case CMD_STOP_DRIVER: 2119 WifiNative.stopDriverCommand(); 2120 transitionTo(mDriverStoppingState); 2121 break; 2122 case CMD_REQUEST_CM_WAKELOCK: 2123 if (mCm == null) { 2124 mCm = (ConnectivityManager)mContext.getSystemService( 2125 Context.CONNECTIVITY_SERVICE); 2126 } 2127 mCm.requestNetworkTransitionWakelock(TAG); 2128 break; 2129 case CMD_START_PACKET_FILTERING: 2130 WifiNative.startPacketFiltering(); 2131 break; 2132 case CMD_STOP_PACKET_FILTERING: 2133 WifiNative.stopPacketFiltering(); 2134 break; 2135 default: 2136 return NOT_HANDLED; 2137 } 2138 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2139 return HANDLED; 2140 } 2141 @Override 2142 public void exit() { 2143 if (DBG) Log.d(TAG, getName() + "\n"); 2144 try { 2145 mBatteryStats.noteWifiStopped(); 2146 } catch (RemoteException ignore) { } 2147 mScanResults = null; 2148 } 2149 } 2150 2151 class DriverStoppingState extends HierarchicalState { 2152 @Override 2153 public void enter() { 2154 if (DBG) Log.d(TAG, getName() + "\n"); 2155 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2156 } 2157 @Override 2158 public boolean processMessage(Message message) { 2159 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2160 switch(message.what) { 2161 case DRIVER_STOP_EVENT: 2162 transitionTo(mDriverStoppedState); 2163 break; 2164 /* Queue driver commands */ 2165 case CMD_START_DRIVER: 2166 case CMD_STOP_DRIVER: 2167 case CMD_SET_SCAN_TYPE: 2168 case CMD_SET_POWER_MODE: 2169 case CMD_SET_BLUETOOTH_COEXISTENCE: 2170 case CMD_SET_BLUETOOTH_SCAN_MODE: 2171 case CMD_SET_NUM_ALLOWED_CHANNELS: 2172 case CMD_START_PACKET_FILTERING: 2173 case CMD_STOP_PACKET_FILTERING: 2174 case CMD_START_SCAN: 2175 case CMD_DISCONNECT: 2176 case CMD_REASSOCIATE: 2177 case CMD_RECONNECT: 2178 deferMessage(message); 2179 break; 2180 default: 2181 return NOT_HANDLED; 2182 } 2183 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2184 return HANDLED; 2185 } 2186 } 2187 2188 class DriverStoppedState extends HierarchicalState { 2189 @Override 2190 public void enter() { 2191 if (DBG) Log.d(TAG, getName() + "\n"); 2192 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2193 } 2194 @Override 2195 public boolean processMessage(Message message) { 2196 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2197 return NOT_HANDLED; 2198 } 2199 } 2200 2201 class ScanModeState extends HierarchicalState { 2202 @Override 2203 public void enter() { 2204 if (DBG) Log.d(TAG, getName() + "\n"); 2205 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2206 } 2207 @Override 2208 public boolean processMessage(Message message) { 2209 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2210 SyncParams syncParams; 2211 switch(message.what) { 2212 case CMD_SET_SCAN_MODE: 2213 if (message.arg1 == SCAN_ONLY_MODE) { 2214 /* Ignore */ 2215 return HANDLED; 2216 } else { 2217 WifiNative.setScanResultHandlingCommand(message.arg1); 2218 WifiNative.reconnectCommand(); 2219 mIsScanMode = false; 2220 transitionTo(mDisconnectedState); 2221 } 2222 break; 2223 case CMD_START_SCAN: 2224 WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE); 2225 break; 2226 /* Ignore */ 2227 case CMD_DISCONNECT: 2228 case CMD_RECONNECT: 2229 case CMD_REASSOCIATE: 2230 case SUPPLICANT_STATE_CHANGE_EVENT: 2231 case NETWORK_CONNECTION_EVENT: 2232 case NETWORK_DISCONNECTION_EVENT: 2233 break; 2234 default: 2235 return NOT_HANDLED; 2236 } 2237 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2238 return HANDLED; 2239 } 2240 } 2241 2242 class ConnectModeState extends HierarchicalState { 2243 @Override 2244 public void enter() { 2245 if (DBG) Log.d(TAG, getName() + "\n"); 2246 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2247 } 2248 @Override 2249 public boolean processMessage(Message message) { 2250 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2251 SyncParams syncParams; 2252 StateChangeResult stateChangeResult; 2253 switch(message.what) { 2254 case PASSWORD_MAY_BE_INCORRECT_EVENT: 2255 mPasswordKeyMayBeIncorrect = true; 2256 break; 2257 case SUPPLICANT_STATE_CHANGE_EVENT: 2258 stateChangeResult = (StateChangeResult) message.obj; 2259 mSupplicantStateTracker.handleEvent(stateChangeResult); 2260 break; 2261 case CMD_START_SCAN: 2262 /* We need to set scan type in completed state */ 2263 Message newMsg = obtainMessage(); 2264 newMsg.copyFrom(message); 2265 mSupplicantStateTracker.sendMessage(newMsg); 2266 break; 2267 /* Do a redundant disconnect without transition */ 2268 case CMD_DISCONNECT: 2269 WifiNative.disconnectCommand(); 2270 break; 2271 case CMD_RECONNECT: 2272 WifiNative.reconnectCommand(); 2273 break; 2274 case CMD_REASSOCIATE: 2275 WifiNative.reassociateCommand(); 2276 break; 2277 case CMD_CONNECT_NETWORK: 2278 int netId = message.arg1; 2279 WifiConfiguration config = (WifiConfiguration) message.obj; 2280 2281 /* We connect to a specific network by issuing a select 2282 * to the WifiConfigStore. This enables the network, 2283 * while disabling all other networks in the supplicant. 2284 * Disabling a connected network will cause a disconnection 2285 * from the network. A reconnectCommand() will then initiate 2286 * a connection to the enabled network. 2287 */ 2288 if (config != null) { 2289 WifiConfigStore.selectNetwork(config); 2290 } else { 2291 WifiConfigStore.selectNetwork(netId); 2292 } 2293 2294 /* Save a flag to indicate that we need to enable all 2295 * networks after supplicant indicates a network 2296 * state change event 2297 */ 2298 mEnableAllNetworks = true; 2299 2300 WifiNative.reconnectCommand(); 2301 2302 /* Expect a disconnection from the old connection */ 2303 transitionTo(mDisconnectingState); 2304 break; 2305 case SCAN_RESULTS_EVENT: 2306 /* Set the scan setting back to "connect" mode */ 2307 WifiNative.setScanResultHandlingCommand(CONNECT_MODE); 2308 /* Handle scan results */ 2309 return NOT_HANDLED; 2310 case NETWORK_CONNECTION_EVENT: 2311 Log.d(TAG,"Network connection established"); 2312 stateChangeResult = (StateChangeResult) message.obj; 2313 2314 //TODO: make supplicant modification to push this in events 2315 mWifiInfo.setSSID(fetchSSID()); 2316 mWifiInfo.setBSSID(mLastBssid = stateChangeResult.BSSID); 2317 mWifiInfo.setNetworkId(stateChangeResult.networkId); 2318 mLastNetworkId = stateChangeResult.networkId; 2319 /* send event to CM & network change broadcast */ 2320 setDetailedState(DetailedState.OBTAINING_IPADDR); 2321 sendNetworkStateChangeBroadcast(mLastBssid); 2322 transitionTo(mConnectingState); 2323 break; 2324 case NETWORK_DISCONNECTION_EVENT: 2325 Log.d(TAG,"Network connection lost"); 2326 handleNetworkDisconnect(); 2327 transitionTo(mDisconnectedState); 2328 break; 2329 case CMD_GET_RSSI: 2330 syncParams = (SyncParams) message.obj; 2331 syncParams.mSyncReturn.intValue = WifiNative.getRssiCommand(); 2332 notifyOnMsgObject(message); 2333 break; 2334 case CMD_GET_RSSI_APPROX: 2335 syncParams = (SyncParams) message.obj; 2336 syncParams.mSyncReturn.intValue = WifiNative.getRssiApproxCommand(); 2337 notifyOnMsgObject(message); 2338 break; 2339 case CMD_GET_LINK_SPEED: 2340 syncParams = (SyncParams) message.obj; 2341 syncParams.mSyncReturn.intValue = WifiNative.getLinkSpeedCommand(); 2342 notifyOnMsgObject(message); 2343 break; 2344 default: 2345 return NOT_HANDLED; 2346 } 2347 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2348 return HANDLED; 2349 } 2350 } 2351 2352 class ConnectingState extends HierarchicalState { 2353 boolean mModifiedBluetoothCoexistenceMode; 2354 int mPowerMode; 2355 boolean mUseStaticIp; 2356 Thread mDhcpThread; 2357 2358 @Override 2359 public void enter() { 2360 if (DBG) Log.d(TAG, getName() + "\n"); 2361 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2362 2363 mUseStaticIp = WifiConfigStore.isUsingStaticIp(mLastNetworkId); 2364 if (!mUseStaticIp) { 2365 mDhcpThread = null; 2366 mModifiedBluetoothCoexistenceMode = false; 2367 mPowerMode = DRIVER_POWER_MODE_AUTO; 2368 2369 if (shouldDisableCoexistenceMode()) { 2370 /* 2371 * There are problems setting the Wi-Fi driver's power 2372 * mode to active when bluetooth coexistence mode is 2373 * enabled or sense. 2374 * <p> 2375 * We set Wi-Fi to active mode when 2376 * obtaining an IP address because we've found 2377 * compatibility issues with some routers with low power 2378 * mode. 2379 * <p> 2380 * In order for this active power mode to properly be set, 2381 * we disable coexistence mode until we're done with 2382 * obtaining an IP address. One exception is if we 2383 * are currently connected to a headset, since disabling 2384 * coexistence would interrupt that connection. 2385 */ 2386 mModifiedBluetoothCoexistenceMode = true; 2387 2388 // Disable the coexistence mode 2389 WifiNative.setBluetoothCoexistenceModeCommand( 2390 WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); 2391 } 2392 2393 mPowerMode = WifiNative.getPowerModeCommand(); 2394 if (mPowerMode < 0) { 2395 // Handle the case where supplicant driver does not support 2396 // getPowerModeCommand. 2397 mPowerMode = DRIVER_POWER_MODE_AUTO; 2398 } 2399 if (mPowerMode != DRIVER_POWER_MODE_ACTIVE) { 2400 WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_ACTIVE); 2401 } 2402 2403 Log.d(TAG, "DHCP request started"); 2404 mDhcpThread = new Thread(new Runnable() { 2405 public void run() { 2406 DhcpInfo dhcpInfo = new DhcpInfo(); 2407 if (NetworkUtils.runDhcp(mInterfaceName, dhcpInfo)) { 2408 Log.d(TAG, "DHCP request succeeded"); 2409 synchronized (mDhcpInfo) { 2410 mDhcpInfo = dhcpInfo; 2411 } 2412 sendMessage(CMD_IP_CONFIG_SUCCESS); 2413 } else { 2414 Log.d(TAG, "DHCP request failed: " + 2415 NetworkUtils.getDhcpError()); 2416 sendMessage(CMD_IP_CONFIG_FAILURE); 2417 } 2418 } 2419 }); 2420 mDhcpThread.start(); 2421 } else { 2422 DhcpInfo dhcpInfo = WifiConfigStore.getIpConfiguration(mLastNetworkId); 2423 if (NetworkUtils.configureInterface(mInterfaceName, dhcpInfo)) { 2424 Log.v(TAG, "Static IP configuration succeeded"); 2425 synchronized (mDhcpInfo) { 2426 mDhcpInfo = dhcpInfo; 2427 } 2428 sendMessage(CMD_IP_CONFIG_SUCCESS); 2429 } else { 2430 Log.v(TAG, "Static IP configuration failed"); 2431 sendMessage(CMD_IP_CONFIG_FAILURE); 2432 } 2433 } 2434 } 2435 @Override 2436 public boolean processMessage(Message message) { 2437 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2438 2439 switch(message.what) { 2440 case CMD_IP_CONFIG_SUCCESS: 2441 mReconnectCount = 0; 2442 mLastSignalLevel = -1; // force update of signal strength 2443 synchronized (mDhcpInfo) { 2444 mWifiInfo.setIpAddress(mDhcpInfo.ipAddress); 2445 Log.d(TAG, "IP configuration: " + mDhcpInfo); 2446 } 2447 configureLinkProperties(); 2448 setDetailedState(DetailedState.CONNECTED); 2449 sendNetworkStateChangeBroadcast(mLastBssid); 2450 //TODO: The framework is not detecting a DHCP renewal and a possible 2451 //IP change. we should detect this and send out a config change broadcast 2452 transitionTo(mConnectedState); 2453 break; 2454 case CMD_IP_CONFIG_FAILURE: 2455 mWifiInfo.setIpAddress(0); 2456 2457 Log.e(TAG, "IP configuration failed"); 2458 /** 2459 * If we've exceeded the maximum number of retries for DHCP 2460 * to a given network, disable the network 2461 */ 2462 if (++mReconnectCount > getMaxDhcpRetries()) { 2463 Log.e(TAG, "Failed " + 2464 mReconnectCount + " times, Disabling " + mLastNetworkId); 2465 WifiConfigStore.disableNetwork(mLastNetworkId); 2466 } 2467 2468 /* DHCP times out after about 30 seconds, we do a 2469 * disconnect and an immediate reconnect to try again 2470 */ 2471 WifiNative.disconnectCommand(); 2472 WifiNative.reconnectCommand(); 2473 transitionTo(mDisconnectingState); 2474 break; 2475 case CMD_DISCONNECT: 2476 WifiNative.disconnectCommand(); 2477 transitionTo(mDisconnectingState); 2478 break; 2479 /* Ignore connection to same network */ 2480 case CMD_CONNECT_NETWORK: 2481 int netId = message.arg1; 2482 if (mWifiInfo.getNetworkId() == netId) { 2483 break; 2484 } 2485 return NOT_HANDLED; 2486 /* Ignore */ 2487 case NETWORK_CONNECTION_EVENT: 2488 break; 2489 case CMD_STOP_DRIVER: 2490 sendMessage(CMD_DISCONNECT); 2491 deferMessage(message); 2492 break; 2493 case CMD_SET_SCAN_MODE: 2494 if (message.arg1 == SCAN_ONLY_MODE) { 2495 sendMessage(CMD_DISCONNECT); 2496 deferMessage(message); 2497 } 2498 break; 2499 case CMD_RECONFIGURE_IP: 2500 deferMessage(message); 2501 break; 2502 default: 2503 return NOT_HANDLED; 2504 } 2505 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2506 return HANDLED; 2507 } 2508 2509 @Override 2510 public void exit() { 2511 /* reset power state & bluetooth coexistence if on DHCP */ 2512 if (!mUseStaticIp) { 2513 if (mPowerMode != DRIVER_POWER_MODE_ACTIVE) { 2514 WifiNative.setPowerModeCommand(mPowerMode); 2515 } 2516 2517 if (mModifiedBluetoothCoexistenceMode) { 2518 // Set the coexistence mode back to its default value 2519 WifiNative.setBluetoothCoexistenceModeCommand( 2520 WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); 2521 } 2522 } 2523 2524 } 2525 } 2526 2527 class ConnectedState extends HierarchicalState { 2528 @Override 2529 public void enter() { 2530 if (DBG) Log.d(TAG, getName() + "\n"); 2531 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2532 } 2533 @Override 2534 public boolean processMessage(Message message) { 2535 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2536 switch (message.what) { 2537 case CMD_DISCONNECT: 2538 WifiNative.disconnectCommand(); 2539 transitionTo(mDisconnectingState); 2540 break; 2541 case CMD_RECONFIGURE_IP: 2542 Log.d(TAG,"Reconfiguring IP on connection"); 2543 NetworkUtils.resetConnections(mInterfaceName); 2544 transitionTo(mConnectingState); 2545 break; 2546 case CMD_STOP_DRIVER: 2547 sendMessage(CMD_DISCONNECT); 2548 deferMessage(message); 2549 break; 2550 case CMD_SET_SCAN_MODE: 2551 if (message.arg1 == SCAN_ONLY_MODE) { 2552 sendMessage(CMD_DISCONNECT); 2553 deferMessage(message); 2554 } 2555 break; 2556 /* Ignore connection to same network */ 2557 case CMD_CONNECT_NETWORK: 2558 int netId = message.arg1; 2559 if (mWifiInfo.getNetworkId() == netId) { 2560 break; 2561 } 2562 return NOT_HANDLED; 2563 /* Ignore */ 2564 case NETWORK_CONNECTION_EVENT: 2565 break; 2566 default: 2567 return NOT_HANDLED; 2568 } 2569 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2570 return HANDLED; 2571 } 2572 } 2573 2574 class DisconnectingState extends HierarchicalState { 2575 @Override 2576 public void enter() { 2577 if (DBG) Log.d(TAG, getName() + "\n"); 2578 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2579 } 2580 @Override 2581 public boolean processMessage(Message message) { 2582 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2583 switch (message.what) { 2584 case CMD_STOP_DRIVER: /* Stop driver only after disconnect handled */ 2585 deferMessage(message); 2586 break; 2587 case CMD_SET_SCAN_MODE: 2588 if (message.arg1 == SCAN_ONLY_MODE) { 2589 deferMessage(message); 2590 } 2591 break; 2592 default: 2593 return NOT_HANDLED; 2594 } 2595 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2596 return HANDLED; 2597 } 2598 @Override 2599 public void exit() { 2600 if (mEnableAllNetworks) { 2601 mEnableAllNetworks = false; 2602 WifiConfigStore.enableAllNetworks(); 2603 } 2604 } 2605 } 2606 2607 class DisconnectedState extends HierarchicalState { 2608 @Override 2609 public void enter() { 2610 if (DBG) Log.d(TAG, getName() + "\n"); 2611 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2612 } 2613 @Override 2614 public boolean processMessage(Message message) { 2615 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2616 switch (message.what) { 2617 case CMD_SET_SCAN_MODE: 2618 if (message.arg1 == SCAN_ONLY_MODE) { 2619 WifiNative.setScanResultHandlingCommand(message.arg1); 2620 //Supplicant disconnect to prevent further connects 2621 WifiNative.disconnectCommand(); 2622 mIsScanMode = true; 2623 transitionTo(mScanModeState); 2624 } 2625 break; 2626 /* Ignore network disconnect */ 2627 case NETWORK_DISCONNECTION_EVENT: 2628 break; 2629 default: 2630 return NOT_HANDLED; 2631 } 2632 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2633 return HANDLED; 2634 } 2635 } 2636 2637 class SoftApStartedState extends HierarchicalState { 2638 @Override 2639 public void enter() { 2640 if (DBG) Log.d(TAG, getName() + "\n"); 2641 EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); 2642 } 2643 @Override 2644 public boolean processMessage(Message message) { 2645 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2646 switch(message.what) { 2647 case CMD_STOP_AP: 2648 Log.d(TAG,"Stopping Soft AP"); 2649 setWifiApState(WIFI_AP_STATE_DISABLING); 2650 try { 2651 nwService.stopAccessPoint(); 2652 } catch(Exception e) { 2653 Log.e(TAG, "Exception in stopAccessPoint()"); 2654 } 2655 transitionTo(mDriverLoadedState); 2656 break; 2657 case CMD_START_AP: 2658 Log.d(TAG,"SoftAP set on a running access point"); 2659 try { 2660 nwService.setAccessPoint((WifiConfiguration) message.obj, 2661 mInterfaceName, 2662 SOFTAP_IFACE); 2663 } catch(Exception e) { 2664 Log.e(TAG, "Exception in nwService during soft AP set"); 2665 try { 2666 nwService.stopAccessPoint(); 2667 } catch (Exception ee) { 2668 Slog.e(TAG, "Could not stop AP, :" + ee); 2669 } 2670 sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0)); 2671 } 2672 break; 2673 /* Fail client mode operation when soft AP is enabled */ 2674 case CMD_START_SUPPLICANT: 2675 Log.e(TAG,"Cannot start supplicant with a running soft AP"); 2676 setWifiState(WIFI_STATE_UNKNOWN); 2677 break; 2678 default: 2679 return NOT_HANDLED; 2680 } 2681 EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); 2682 return HANDLED; 2683 } 2684 } 2685 2686 2687 class SupplicantStateTracker extends HierarchicalStateMachine { 2688 2689 private int mRssiPollToken = 0; 2690 2691 /** 2692 * The max number of the WPA supplicant loop iterations before we 2693 * decide that the loop should be terminated: 2694 */ 2695 private static final int MAX_SUPPLICANT_LOOP_ITERATIONS = 4; 2696 private int mLoopDetectIndex = 0; 2697 private int mLoopDetectCount = 0; 2698 2699 /** 2700 * Supplicant state change commands follow 2701 * the ordinal values defined in SupplicantState.java 2702 */ 2703 private static final int DISCONNECTED = 0; 2704 private static final int INACTIVE = 1; 2705 private static final int SCANNING = 2; 2706 private static final int ASSOCIATING = 3; 2707 private static final int ASSOCIATED = 4; 2708 private static final int FOUR_WAY_HANDSHAKE = 5; 2709 private static final int GROUP_HANDSHAKE = 6; 2710 private static final int COMPLETED = 7; 2711 private static final int DORMANT = 8; 2712 private static final int UNINITIALIZED = 9; 2713 private static final int INVALID = 10; 2714 2715 private HierarchicalState mUninitializedState = new UninitializedState(); 2716 private HierarchicalState mInitializedState = new InitializedState();; 2717 private HierarchicalState mInactiveState = new InactiveState(); 2718 private HierarchicalState mDisconnectState = new DisconnectedState(); 2719 private HierarchicalState mScanState = new ScanState(); 2720 private HierarchicalState mConnectState = new ConnectState(); 2721 private HierarchicalState mHandshakeState = new HandshakeState(); 2722 private HierarchicalState mCompletedState = new CompletedState(); 2723 private HierarchicalState mDormantState = new DormantState(); 2724 2725 public SupplicantStateTracker(Context context, Handler target) { 2726 super(TAG, target.getLooper()); 2727 2728 addState(mUninitializedState); 2729 addState(mInitializedState); 2730 addState(mInactiveState, mInitializedState); 2731 addState(mDisconnectState, mInitializedState); 2732 addState(mScanState, mInitializedState); 2733 addState(mConnectState, mInitializedState); 2734 addState(mHandshakeState, mConnectState); 2735 addState(mCompletedState, mConnectState); 2736 addState(mDormantState, mInitializedState); 2737 2738 setInitialState(mUninitializedState); 2739 2740 //start the state machine 2741 start(); 2742 } 2743 2744 public void handleEvent(StateChangeResult stateChangeResult) { 2745 SupplicantState newState = (SupplicantState) stateChangeResult.state; 2746 2747 // Supplicant state change 2748 // [31-13] Reserved for future use 2749 // [8 - 0] Supplicant state (as defined in SupplicantState.java) 2750 // 50023 supplicant_state_changed (custom|1|5) 2751 EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, newState.ordinal()); 2752 2753 sendMessage(obtainMessage(newState.ordinal(), stateChangeResult)); 2754 } 2755 2756 public void resetSupplicantState() { 2757 transitionTo(mUninitializedState); 2758 } 2759 2760 private void resetLoopDetection() { 2761 mLoopDetectCount = 0; 2762 mLoopDetectIndex = 0; 2763 } 2764 2765 private boolean handleTransition(Message msg) { 2766 if (DBG) Log.d(TAG, getName() + msg.toString() + "\n"); 2767 switch (msg.what) { 2768 case DISCONNECTED: 2769 transitionTo(mDisconnectState); 2770 break; 2771 case SCANNING: 2772 transitionTo(mScanState); 2773 break; 2774 case ASSOCIATING: 2775 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj; 2776 /* BSSID is valid only in ASSOCIATING state */ 2777 mWifiInfo.setBSSID(stateChangeResult.BSSID); 2778 //$FALL-THROUGH$ 2779 case ASSOCIATED: 2780 case FOUR_WAY_HANDSHAKE: 2781 case GROUP_HANDSHAKE: 2782 transitionTo(mHandshakeState); 2783 break; 2784 case COMPLETED: 2785 transitionTo(mCompletedState); 2786 break; 2787 case DORMANT: 2788 transitionTo(mDormantState); 2789 break; 2790 case INACTIVE: 2791 transitionTo(mInactiveState); 2792 break; 2793 case UNINITIALIZED: 2794 case INVALID: 2795 transitionTo(mUninitializedState); 2796 break; 2797 default: 2798 return NOT_HANDLED; 2799 } 2800 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj; 2801 SupplicantState supState = (SupplicantState) stateChangeResult.state; 2802 setDetailedState(WifiInfo.getDetailedStateOf(supState)); 2803 mWifiInfo.setSupplicantState(supState); 2804 mWifiInfo.setNetworkId(stateChangeResult.networkId); 2805 return HANDLED; 2806 } 2807 2808 /******************************************************** 2809 * HSM states 2810 *******************************************************/ 2811 2812 class InitializedState extends HierarchicalState { 2813 @Override 2814 public void enter() { 2815 if (DBG) Log.d(TAG, getName() + "\n"); 2816 } 2817 @Override 2818 public boolean processMessage(Message message) { 2819 if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); 2820 switch (message.what) { 2821 case CMD_START_SCAN: 2822 WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE); 2823 break; 2824 default: 2825 if (DBG) Log.w(TAG, "Ignoring " + message); 2826 break; 2827 } 2828 return HANDLED; 2829 } 2830 } 2831 2832 class UninitializedState extends HierarchicalState { 2833 @Override 2834 public void enter() { 2835 if (DBG) Log.d(TAG, getName() + "\n"); 2836 mNetworkInfo.setIsAvailable(false); 2837 resetLoopDetection(); 2838 mPasswordKeyMayBeIncorrect = false; 2839 } 2840 @Override 2841 public boolean processMessage(Message message) { 2842 switch(message.what) { 2843 default: 2844 if (!handleTransition(message)) { 2845 if (DBG) Log.w(TAG, "Ignoring " + message); 2846 } 2847 break; 2848 } 2849 return HANDLED; 2850 } 2851 @Override 2852 public void exit() { 2853 mNetworkInfo.setIsAvailable(true); 2854 } 2855 } 2856 2857 class InactiveState extends HierarchicalState { 2858 @Override 2859 public void enter() { 2860 if (DBG) Log.d(TAG, getName() + "\n"); 2861 Message message = getCurrentMessage(); 2862 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 2863 2864 mNetworkInfo.setIsAvailable(false); 2865 resetLoopDetection(); 2866 mPasswordKeyMayBeIncorrect = false; 2867 2868 sendSupplicantStateChangedBroadcast(stateChangeResult, false); 2869 } 2870 @Override 2871 public boolean processMessage(Message message) { 2872 return handleTransition(message); 2873 } 2874 @Override 2875 public void exit() { 2876 mNetworkInfo.setIsAvailable(true); 2877 } 2878 } 2879 2880 2881 class DisconnectedState extends HierarchicalState { 2882 @Override 2883 public void enter() { 2884 if (DBG) Log.d(TAG, getName() + "\n"); 2885 Message message = getCurrentMessage(); 2886 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 2887 2888 resetLoopDetection(); 2889 2890 /* If a disconnect event happens after a password key failure 2891 * event, disable the network 2892 */ 2893 if (mPasswordKeyMayBeIncorrect) { 2894 Log.d(TAG, "Failed to authenticate, disabling network " + 2895 mWifiInfo.getNetworkId()); 2896 WifiConfigStore.disableNetwork(mWifiInfo.getNetworkId()); 2897 mPasswordKeyMayBeIncorrect = false; 2898 sendSupplicantStateChangedBroadcast(stateChangeResult, true); 2899 } 2900 else { 2901 sendSupplicantStateChangedBroadcast(stateChangeResult, false); 2902 } 2903 } 2904 @Override 2905 public boolean processMessage(Message message) { 2906 return handleTransition(message); 2907 } 2908 } 2909 2910 class ScanState extends HierarchicalState { 2911 @Override 2912 public void enter() { 2913 if (DBG) Log.d(TAG, getName() + "\n"); 2914 Message message = getCurrentMessage(); 2915 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 2916 2917 mPasswordKeyMayBeIncorrect = false; 2918 resetLoopDetection(); 2919 sendSupplicantStateChangedBroadcast(stateChangeResult, false); 2920 } 2921 @Override 2922 public boolean processMessage(Message message) { 2923 return handleTransition(message); 2924 } 2925 } 2926 2927 class ConnectState extends HierarchicalState { 2928 @Override 2929 public void enter() { 2930 if (DBG) Log.d(TAG, getName() + "\n"); 2931 } 2932 @Override 2933 public boolean processMessage(Message message) { 2934 switch (message.what) { 2935 case CMD_START_SCAN: 2936 WifiNative.setScanResultHandlingCommand(SCAN_ONLY_MODE); 2937 WifiNative.scanCommand(message.arg1 == SCAN_ACTIVE); 2938 break; 2939 default: 2940 return NOT_HANDLED; 2941 } 2942 return HANDLED; 2943 } 2944 } 2945 2946 class HandshakeState extends HierarchicalState { 2947 @Override 2948 public void enter() { 2949 if (DBG) Log.d(TAG, getName() + "\n"); 2950 final Message message = getCurrentMessage(); 2951 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 2952 2953 if (mLoopDetectIndex > message.what) { 2954 mLoopDetectCount++; 2955 } 2956 if (mLoopDetectCount > MAX_SUPPLICANT_LOOP_ITERATIONS) { 2957 WifiConfigStore.disableNetwork(stateChangeResult.networkId); 2958 mLoopDetectCount = 0; 2959 } 2960 2961 mLoopDetectIndex = message.what; 2962 2963 mPasswordKeyMayBeIncorrect = false; 2964 sendSupplicantStateChangedBroadcast(stateChangeResult, false); 2965 } 2966 @Override 2967 public boolean processMessage(Message message) { 2968 return handleTransition(message); 2969 } 2970 } 2971 2972 class CompletedState extends HierarchicalState { 2973 @Override 2974 public void enter() { 2975 if (DBG) Log.d(TAG, getName() + "\n"); 2976 Message message = getCurrentMessage(); 2977 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 2978 2979 mRssiPollToken++; 2980 if (mEnableRssiPolling) { 2981 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0), 2982 POLL_RSSI_INTERVAL_MSECS); 2983 } 2984 2985 resetLoopDetection(); 2986 2987 mPasswordKeyMayBeIncorrect = false; 2988 sendSupplicantStateChangedBroadcast(stateChangeResult, false); 2989 } 2990 @Override 2991 public boolean processMessage(Message message) { 2992 switch(message.what) { 2993 case ASSOCIATING: 2994 case ASSOCIATED: 2995 case FOUR_WAY_HANDSHAKE: 2996 case GROUP_HANDSHAKE: 2997 case COMPLETED: 2998 break; 2999 case CMD_RSSI_POLL: 3000 if (message.arg1 == mRssiPollToken) { 3001 // Get Info and continue polling 3002 requestPolledInfo(); 3003 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0), 3004 POLL_RSSI_INTERVAL_MSECS); 3005 } else { 3006 // Polling has completed 3007 } 3008 break; 3009 case CMD_ENABLE_RSSI_POLL: 3010 mRssiPollToken++; 3011 if (mEnableRssiPolling) { 3012 // first poll 3013 requestPolledInfo(); 3014 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0), 3015 POLL_RSSI_INTERVAL_MSECS); 3016 } 3017 break; 3018 default: 3019 return handleTransition(message); 3020 } 3021 return HANDLED; 3022 } 3023 } 3024 3025 class DormantState extends HierarchicalState { 3026 @Override 3027 public void enter() { 3028 if (DBG) Log.d(TAG, getName() + "\n"); 3029 Message message = getCurrentMessage(); 3030 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 3031 3032 resetLoopDetection(); 3033 mPasswordKeyMayBeIncorrect = false; 3034 3035 sendSupplicantStateChangedBroadcast(stateChangeResult, false); 3036 3037 /* TODO: reconnect is now being handled at DHCP failure handling 3038 * If we run into issues with staying in Dormant state, might 3039 * need a reconnect here 3040 */ 3041 } 3042 @Override 3043 public boolean processMessage(Message message) { 3044 return handleTransition(message); 3045 } 3046 } 3047 } 3048} 3049