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