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