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