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