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