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