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