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