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