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