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