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