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