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