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