WifiStateMachine.java revision e57857d829f670c62e8d53ffed580681271a272b
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 com.android.server.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.DhcpResults; 47import android.net.DhcpStateMachine; 48import android.net.InterfaceConfiguration; 49import android.net.LinkAddress; 50import android.net.LinkProperties; 51import android.net.NetworkInfo; 52import android.net.NetworkInfo.DetailedState; 53import android.net.NetworkUtils; 54import android.net.RouteInfo; 55import android.net.wifi.BatchedScanResult; 56import android.net.wifi.BatchedScanSettings; 57import android.net.wifi.RssiPacketCountInfo; 58import android.net.wifi.ScanResult; 59import android.net.wifi.ScanSettings; 60import android.net.wifi.WifiChannel; 61import android.net.wifi.SupplicantState; 62import android.net.wifi.WifiConfiguration; 63import android.net.wifi.WifiInfo; 64import android.net.wifi.WifiManager; 65import android.net.wifi.WifiSsid; 66import android.net.wifi.WpsInfo; 67import android.net.wifi.WpsResult; 68import android.net.wifi.WpsResult.Status; 69import android.net.wifi.p2p.IWifiP2pManager; 70import android.os.BatteryStats; 71import android.os.Bundle; 72import android.os.IBinder; 73import android.os.INetworkManagementService; 74import android.os.Message; 75import android.os.Messenger; 76import android.os.PowerManager; 77import android.os.RemoteException; 78import android.os.ServiceManager; 79import android.os.SystemClock; 80import android.os.SystemProperties; 81import android.os.UserHandle; 82import android.os.WorkSource; 83import android.provider.Settings; 84import android.util.LruCache; 85import android.text.TextUtils; 86import android.util.Log; 87 88import com.android.internal.R; 89import com.android.internal.app.IBatteryStats; 90import com.android.internal.util.AsyncChannel; 91import com.android.internal.util.Protocol; 92import com.android.internal.util.State; 93import com.android.internal.util.StateMachine; 94import com.android.server.net.BaseNetworkObserver; 95import com.android.server.wifi.p2p.WifiP2pServiceImpl; 96 97import java.io.FileDescriptor; 98import java.io.PrintWriter; 99import java.net.InetAddress; 100import java.util.ArrayList; 101import java.util.LinkedList; 102import java.util.List; 103import java.util.Locale; 104import java.util.Queue; 105import java.util.concurrent.atomic.AtomicInteger; 106import java.util.concurrent.atomic.AtomicBoolean; 107import java.util.Iterator; 108import java.util.regex.Pattern; 109import java.io.FileReader; 110import java.io.BufferedReader; 111import java.io.FileNotFoundException; 112import java.io.IOException; 113 114import java.net.InetAddress; 115import java.net.Inet4Address; 116import java.net.Inet6Address; 117 118/** 119 * Track the state of Wifi connectivity. All event handling is done here, 120 * and all changes in connectivity state are initiated here. 121 * 122 * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p 123 * In the current implementation, we support concurrent wifi p2p and wifi operation. 124 * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService 125 * handles p2p operation. 126 * 127 * @hide 128 */ 129public class WifiStateMachine extends StateMachine { 130 131 private static final String NETWORKTYPE = "WIFI"; 132 private static final boolean DBG = true; 133 private static final boolean VDBG = false; 134 private static final boolean mLogMessages = false; 135 136 /* KWD branch temporary debug flag - best network selection development */ 137 private static final boolean PDBG = false; 138 /** 139 * Log with error attribute 140 * 141 * @param s is string log 142 */ 143 protected void loge(String s) { 144 long now = SystemClock.elapsedRealtimeNanos(); 145 String ts = String.format("[%,d us] ", now/1000); 146 Log.e(getName(), ts + s); 147 } 148 protected void log(String s) { 149 long now = SystemClock.elapsedRealtimeNanos(); 150 String ts = String.format("[%,d us] ", now/1000); 151 Log.e(getName(), ts + s); 152 } 153 154 private WifiMonitor mWifiMonitor; 155 private WifiNative mWifiNative; 156 private WifiConfigStore mWifiConfigStore; 157 private WifiAutoJoinController mWifiAutoJoinController; 158 private INetworkManagementService mNwService; 159 private ConnectivityManager mCm; 160 161 private final boolean mP2pSupported; 162 private final AtomicBoolean mP2pConnected = new AtomicBoolean(false); 163 private boolean mTemporarilyDisconnectWifi = false; 164 private final String mPrimaryDeviceType; 165 166 /* Scan results handling */ 167 private List<ScanResult> mScanResults = new ArrayList<ScanResult>(); 168 private static final Pattern scanResultPattern = Pattern.compile("\t+"); 169 private static final int SCAN_RESULT_CACHE_SIZE = 80; 170 private final LruCache<String, ScanResult> mScanResultCache; 171 172 /* Batch scan results */ 173 private final List<BatchedScanResult> mBatchedScanResults = 174 new ArrayList<BatchedScanResult>(); 175 private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE; 176 private int mExpectedBatchedScans = 0; 177 private long mBatchedScanMinPollTime = 0; 178 179 private boolean mScreenOn = false; 180 181 /* Chipset supports background scan */ 182 private final boolean mBackgroundScanSupported; 183 184 private String mInterfaceName; 185 /* Tethering interface could be separate from wlan interface */ 186 private String mTetherInterfaceName; 187 188 private int mLastSignalLevel = -1; 189 private String mLastBssid; 190 private int mLastNetworkId; 191 private boolean mEnableRssiPolling = false; 192 private boolean mEnableBackgroundScan = false; 193 private int mRssiPollToken = 0; 194 private int mReconnectCount = 0; 195 /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE 196 * In CONNECT_MODE, the STA can scan and connect to an access point 197 * In SCAN_ONLY_MODE, the STA can only scan for access points 198 * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off 199 */ 200 private int mOperationalMode = CONNECT_MODE; 201 private boolean mIsScanOngoing = false; 202 private boolean mIsFullScanOngoing = false; 203 private final Queue<Message> mBufferedScanMsg = new LinkedList<Message>(); 204 private WorkSource mScanWorkSource = null; 205 private static final int UNKNOWN_SCAN_SOURCE = -1; 206 private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10; 207 private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings"; 208 private static final String CUSTOMIZED_SCAN_WORKSOURCE = "customized_scan_worksource"; 209 private static final String BATCHED_SETTING = "batched_settings"; 210 private static final String BATCHED_WORKSOURCE = "batched_worksource"; 211 212 /* Tracks if state machine has received any screen state change broadcast yet. 213 * We can miss one of these at boot. 214 */ 215 private AtomicBoolean mScreenBroadcastReceived = new AtomicBoolean(false); 216 217 private boolean mBluetoothConnectionActive = false; 218 219 private PowerManager.WakeLock mSuspendWakeLock; 220 221 /** 222 * Interval in milliseconds between polling for RSSI 223 * and linkspeed information 224 */ 225 private static final int POLL_RSSI_INTERVAL_MSECS = 3000; 226 227 /** 228 * Delay between supplicant restarts upon failure to establish connection 229 */ 230 private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000; 231 232 /** 233 * Number of times we attempt to restart supplicant 234 */ 235 private static final int SUPPLICANT_RESTART_TRIES = 5; 236 237 private int mSupplicantRestartCount = 0; 238 /* Tracks sequence number on stop failure message */ 239 private int mSupplicantStopFailureToken = 0; 240 241 /** 242 * Tether state change notification time out 243 */ 244 private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000; 245 246 /* Tracks sequence number on a tether notification time out */ 247 private int mTetherToken = 0; 248 249 /** 250 * Driver start time out. 251 */ 252 private static final int DRIVER_START_TIME_OUT_MSECS = 10000; 253 254 /* Tracks sequence number on a driver time out */ 255 private int mDriverStartToken = 0; 256 257 /** 258 * The link properties of the wifi interface. 259 * Do not modify this directly; use updateLinkProperties instead. 260 */ 261 private LinkProperties mLinkProperties; 262 263 /** 264 * Subset of link properties coming from netlink. 265 * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers 266 * and domains obtained from router advertisements (RFC 6106). 267 */ 268 private final LinkProperties mNetlinkLinkProperties; 269 270 /* Tracks sequence number on a periodic scan message */ 271 private int mPeriodicScanToken = 0; 272 273 // Wakelock held during wifi start/stop and driver load/unload 274 private PowerManager.WakeLock mWakeLock; 275 276 private Context mContext; 277 278 private final Object mDhcpResultsLock = new Object(); 279 private DhcpResults mDhcpResults; 280 private WifiInfo mWifiInfo; 281 private NetworkInfo mNetworkInfo; 282 private SupplicantStateTracker mSupplicantStateTracker; 283 private DhcpStateMachine mDhcpStateMachine; 284 private boolean mDhcpActive = false; 285 286 // Delay in switching to null country code (non-null has no delay) 287 private final int COUNTRY_CODE_DELAY_MS = 15000; 288 private final AtomicInteger mCountryCodeSequence = new AtomicInteger(); 289 290 private class InterfaceObserver extends BaseNetworkObserver { 291 private WifiStateMachine mWifiStateMachine; 292 293 InterfaceObserver(WifiStateMachine wifiStateMachine) { 294 super(); 295 mWifiStateMachine = wifiStateMachine; 296 } 297 298 private void maybeLog(String operation, String iface, LinkAddress address) { 299 if (DBG) { 300 log(operation + ": " + address + " on " + iface + 301 " flags " + address.getFlags() + " scope " + address.getScope()); 302 } 303 } 304 305 @Override 306 public void addressUpdated(String iface, LinkAddress address) { 307 if (PDBG) { 308 loge(" addressUpdated " + iface + " " + address.toString()); 309 } 310 311 if (mWifiStateMachine.mInterfaceName.equals(iface)) { 312 maybeLog("addressUpdated", iface, address); 313 mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_UPDATED, address); 314 } 315 } 316 317 @Override 318 public void addressRemoved(String iface, LinkAddress address) { 319 if (mWifiStateMachine.mInterfaceName.equals(iface)) { 320 maybeLog("addressRemoved", iface, address); 321 mWifiStateMachine.sendMessage(CMD_IP_ADDRESS_REMOVED, address); 322 } 323 } 324 } 325 326 private InterfaceObserver mInterfaceObserver; 327 328 private AlarmManager mAlarmManager; 329 private PendingIntent mScanIntent; 330 private PendingIntent mDriverStopIntent; 331 private PendingIntent mBatchedScanIntervalIntent; 332 333 /* Tracks current frequency mode */ 334 private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO); 335 336 /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */ 337 private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true); 338 339 // Channel for sending replies. 340 private AsyncChannel mReplyChannel = new AsyncChannel(); 341 342 private WifiP2pServiceImpl mWifiP2pServiceImpl; 343 //Used to initiate a connection with WifiP2pService 344 private AsyncChannel mWifiP2pChannel; 345 private AsyncChannel mWifiApConfigChannel; 346 347 /* The base for wifi message types */ 348 static final int BASE = Protocol.BASE_WIFI; 349 /* Start the supplicant */ 350 static final int CMD_START_SUPPLICANT = BASE + 11; 351 /* Stop the supplicant */ 352 static final int CMD_STOP_SUPPLICANT = BASE + 12; 353 /* Start the driver */ 354 static final int CMD_START_DRIVER = BASE + 13; 355 /* Stop the driver */ 356 static final int CMD_STOP_DRIVER = BASE + 14; 357 /* Indicates Static IP succeeded */ 358 static final int CMD_STATIC_IP_SUCCESS = BASE + 15; 359 /* Indicates Static IP failed */ 360 static final int CMD_STATIC_IP_FAILURE = BASE + 16; 361 /* Indicates supplicant stop failed */ 362 static final int CMD_STOP_SUPPLICANT_FAILED = BASE + 17; 363 /* Delayed stop to avoid shutting down driver too quick*/ 364 static final int CMD_DELAYED_STOP_DRIVER = BASE + 18; 365 /* A delayed message sent to start driver when it fail to come up */ 366 static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19; 367 368 /* Start the soft access point */ 369 static final int CMD_START_AP = BASE + 21; 370 /* Indicates soft ap start succeeded */ 371 static final int CMD_START_AP_SUCCESS = BASE + 22; 372 /* Indicates soft ap start failed */ 373 static final int CMD_START_AP_FAILURE = BASE + 23; 374 /* Stop the soft access point */ 375 static final int CMD_STOP_AP = BASE + 24; 376 /* Set the soft access point configuration */ 377 static final int CMD_SET_AP_CONFIG = BASE + 25; 378 /* Soft access point configuration set completed */ 379 static final int CMD_SET_AP_CONFIG_COMPLETED = BASE + 26; 380 /* Request the soft access point configuration */ 381 static final int CMD_REQUEST_AP_CONFIG = BASE + 27; 382 /* Response to access point configuration request */ 383 static final int CMD_RESPONSE_AP_CONFIG = BASE + 28; 384 /* Invoked when getting a tether state change notification */ 385 static final int CMD_TETHER_STATE_CHANGE = BASE + 29; 386 /* A delayed message sent to indicate tether state change failed to arrive */ 387 static final int CMD_TETHER_NOTIFICATION_TIMED_OUT = BASE + 30; 388 389 static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31; 390 391 /* Supplicant commands */ 392 /* Is supplicant alive ? */ 393 static final int CMD_PING_SUPPLICANT = BASE + 51; 394 /* Add/update a network configuration */ 395 static final int CMD_ADD_OR_UPDATE_NETWORK = BASE + 52; 396 /* Delete a network */ 397 static final int CMD_REMOVE_NETWORK = BASE + 53; 398 /* Enable a network. The device will attempt a connection to the given network. */ 399 static final int CMD_ENABLE_NETWORK = BASE + 54; 400 /* Enable all networks */ 401 static final int CMD_ENABLE_ALL_NETWORKS = BASE + 55; 402 /* Blacklist network. De-prioritizes the given BSSID for connection. */ 403 static final int CMD_BLACKLIST_NETWORK = BASE + 56; 404 /* Clear the blacklist network list */ 405 static final int CMD_CLEAR_BLACKLIST = BASE + 57; 406 /* Save configuration */ 407 static final int CMD_SAVE_CONFIG = BASE + 58; 408 /* Get configured networks */ 409 static final int CMD_GET_CONFIGURED_NETWORKS = BASE + 59; 410 /* Get available frequencies */ 411 static final int CMD_GET_CAPABILITY_FREQ = BASE + 60; 412 413 /* Supplicant commands after driver start*/ 414 /* Initiate a scan */ 415 static final int CMD_START_SCAN = BASE + 71; 416 /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */ 417 static final int CMD_SET_OPERATIONAL_MODE = BASE + 72; 418 /* Disconnect from a network */ 419 static final int CMD_DISCONNECT = BASE + 73; 420 /* Reconnect to a network */ 421 static final int CMD_RECONNECT = BASE + 74; 422 /* Reassociate to a network */ 423 static final int CMD_REASSOCIATE = BASE + 75; 424 /* Controls suspend mode optimizations 425 * 426 * When high perf mode is enabled, suspend mode optimizations are disabled 427 * 428 * When high perf mode is disabled, suspend mode optimizations are enabled 429 * 430 * Suspend mode optimizations include: 431 * - packet filtering 432 * - turn off roaming 433 * - DTIM wake up settings 434 */ 435 static final int CMD_SET_HIGH_PERF_MODE = BASE + 77; 436 /* Set the country code */ 437 static final int CMD_SET_COUNTRY_CODE = BASE + 80; 438 /* Enables RSSI poll */ 439 static final int CMD_ENABLE_RSSI_POLL = BASE + 82; 440 /* RSSI poll */ 441 static final int CMD_RSSI_POLL = BASE + 83; 442 /* Set up packet filtering */ 443 static final int CMD_START_PACKET_FILTERING = BASE + 84; 444 /* Clear packet filter */ 445 static final int CMD_STOP_PACKET_FILTERING = BASE + 85; 446 /* Enable suspend mode optimizations in the driver */ 447 static final int CMD_SET_SUSPEND_OPT_ENABLED = BASE + 86; 448 /* When there are no saved networks, we do a periodic scan to notify user of 449 * an open network */ 450 static final int CMD_NO_NETWORKS_PERIODIC_SCAN = BASE + 88; 451 452 /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */ 453 static final int MULTICAST_V6 = 1; 454 static final int MULTICAST_V4 = 0; 455 456 /* Set the frequency band */ 457 static final int CMD_SET_FREQUENCY_BAND = BASE + 90; 458 /* Enable background scan for configured networks */ 459 static final int CMD_ENABLE_BACKGROUND_SCAN = BASE + 91; 460 /* Enable TDLS on a specific MAC address */ 461 static final int CMD_ENABLE_TDLS = BASE + 92; 462 463 /* Commands from/to the SupplicantStateTracker */ 464 /* Reset the supplicant state tracker */ 465 static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111; 466 467 /* P2p commands */ 468 /* We are ok with no response here since we wont do much with it anyway */ 469 public static final int CMD_ENABLE_P2P = BASE + 131; 470 /* In order to shut down supplicant cleanly, we wait till p2p has 471 * been disabled */ 472 public static final int CMD_DISABLE_P2P_REQ = BASE + 132; 473 public static final int CMD_DISABLE_P2P_RSP = BASE + 133; 474 475 public static final int CMD_BOOT_COMPLETED = BASE + 134; 476 477 /* change the batch scan settings. 478 * arg1 = responsible UID 479 * arg2 = csph (channel scans per hour) 480 * obj = bundle with the new settings and the optional worksource 481 */ 482 public static final int CMD_SET_BATCHED_SCAN = BASE + 135; 483 public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136; 484 public static final int CMD_POLL_BATCHED_SCAN = BASE + 137; 485 486 /* Link configuration (IP address, DNS, ...) changes */ 487 /* An new IP address was added to our interface, or an existing IP address was updated */ 488 static final int CMD_IP_ADDRESS_UPDATED = BASE + 140; 489 /* An IP address was removed from our interface */ 490 static final int CMD_IP_ADDRESS_REMOVED = BASE + 141; 491 /* Reload all networks and reconnect */ 492 static final int CMD_RELOAD_TLS_AND_RECONNECT = BASE + 142; 493 494 static final int CMD_AUTO_CONNECT = BASE + 143; 495 496 /* Wifi state machine modes of operation */ 497 /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ 498 public static final int CONNECT_MODE = 1; 499 /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */ 500 public static final int SCAN_ONLY_MODE = 2; 501 /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */ 502 public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3; 503 504 private static final int SUCCESS = 1; 505 private static final int FAILURE = -1; 506 507 /** 508 * The maximum number of times we will retry a connection to an access point 509 * for which we have failed in acquiring an IP address from DHCP. A value of 510 * N means that we will make N+1 connection attempts in all. 511 * <p> 512 * See {@link Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT}. This is the default 513 * value if a Settings value is not present. 514 */ 515 private static final int DEFAULT_MAX_DHCP_RETRIES = 9; 516 517 /* Tracks if suspend optimizations need to be disabled by DHCP, 518 * screen or due to high perf mode. 519 * When any of them needs to disable it, we keep the suspend optimizations 520 * disabled 521 */ 522 private int mSuspendOptNeedsDisabled = 0; 523 524 private static final int SUSPEND_DUE_TO_DHCP = 1; 525 private static final int SUSPEND_DUE_TO_HIGH_PERF = 1<<1; 526 private static final int SUSPEND_DUE_TO_SCREEN = 1<<2; 527 528 /* Tracks if user has enabled suspend optimizations through settings */ 529 private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true); 530 531 /** 532 * Default framework scan interval in milliseconds. This is used in the scenario in which 533 * wifi chipset does not support background scanning to set up a 534 * periodic wake up scan so that the device can connect to a new access 535 * point on the move. {@link Settings.Global#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can 536 * override this. 537 */ 538 private final int mDefaultFrameworkScanIntervalMs; 539 540 /** 541 * Connected state framework scan interval in milliseconds. 542 * This is used for extended roaming, when screen is lit. 543 */ 544 private final int mConnectedScanPeriodMs = 20000; 545 private final int mDisconnectedScanPeriodMs = 10000; 546 547 /** 548 * Supplicant scan interval in milliseconds. 549 * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or 550 * from the default config if the setting is not set 551 */ 552 private long mSupplicantScanIntervalMs; 553 554 /** 555 * Minimum time interval between enabling all networks. 556 * A device can end up repeatedly connecting to a bad network on screen on/off toggle 557 * due to enabling every time. We add a threshold to avoid this. 558 */ 559 private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */ 560 private long mLastEnableAllNetworksTime; 561 562 /** 563 * Starting and shutting down driver too quick causes problems leading to driver 564 * being in a bad state. Delay driver stop. 565 */ 566 private final int mDriverStopDelayMs; 567 private int mDelayedStopCounter; 568 private boolean mInDelayedStop = false; 569 570 // sometimes telephony gives us this data before boot is complete and we can't store it 571 // until after, so the write is deferred 572 private volatile String mPersistedCountryCode; 573 574 // Supplicant doesn't like setting the same country code multiple times (it may drop 575 // currently connected network), so we save the country code here to avoid redundency 576 private String mLastSetCountryCode; 577 578 private static final int MIN_RSSI = -200; 579 private static final int MAX_RSSI = 256; 580 581 /* Default parent state */ 582 private State mDefaultState = new DefaultState(); 583 /* Temporary initial state */ 584 private State mInitialState = new InitialState(); 585 /* Driver loaded, waiting for supplicant to start */ 586 private State mSupplicantStartingState = new SupplicantStartingState(); 587 /* Driver loaded and supplicant ready */ 588 private State mSupplicantStartedState = new SupplicantStartedState(); 589 /* Waiting for supplicant to stop and monitor to exit */ 590 private State mSupplicantStoppingState = new SupplicantStoppingState(); 591 /* Driver start issued, waiting for completed event */ 592 private State mDriverStartingState = new DriverStartingState(); 593 /* Driver started */ 594 private State mDriverStartedState = new DriverStartedState(); 595 /* Wait until p2p is disabled 596 * This is a special state which is entered right after we exit out of DriverStartedState 597 * before transitioning to another state. 598 */ 599 private State mWaitForP2pDisableState = new WaitForP2pDisableState(); 600 /* Driver stopping */ 601 private State mDriverStoppingState = new DriverStoppingState(); 602 /* Driver stopped */ 603 private State mDriverStoppedState = new DriverStoppedState(); 604 /* Scan for networks, no connection will be established */ 605 private State mScanModeState = new ScanModeState(); 606 /* Connecting to an access point */ 607 private State mConnectModeState = new ConnectModeState(); 608 /* Connected at 802.11 (L2) level */ 609 private State mL2ConnectedState = new L2ConnectedState(); 610 /* fetching IP after connection to access point (assoc+auth complete) */ 611 private State mObtainingIpState = new ObtainingIpState(); 612 /* Waiting for link quality verification to be complete */ 613 private State mVerifyingLinkState = new VerifyingLinkState(); 614 /* Connected with IP addr */ 615 private State mConnectedState = new ConnectedState(); 616 /* disconnect issued, waiting for network disconnect confirmation */ 617 private State mDisconnectingState = new DisconnectingState(); 618 /* Network is not connected, supplicant assoc+auth is not complete */ 619 private State mDisconnectedState = new DisconnectedState(); 620 /* Waiting for WPS to be completed*/ 621 private State mWpsRunningState = new WpsRunningState(); 622 623 /* Soft ap is starting up */ 624 private State mSoftApStartingState = new SoftApStartingState(); 625 /* Soft ap is running */ 626 private State mSoftApStartedState = new SoftApStartedState(); 627 /* Soft ap is running and we are waiting for tether notification */ 628 private State mTetheringState = new TetheringState(); 629 /* Soft ap is running and we are tethered through connectivity service */ 630 private State mTetheredState = new TetheredState(); 631 /* Waiting for untether confirmation before stopping soft Ap */ 632 private State mUntetheringState = new UntetheringState(); 633 634 private class TetherStateChange { 635 ArrayList<String> available; 636 ArrayList<String> active; 637 TetherStateChange(ArrayList<String> av, ArrayList<String> ac) { 638 available = av; 639 active = ac; 640 } 641 } 642 643 644 /** 645 * One of {@link WifiManager#WIFI_STATE_DISABLED}, 646 * {@link WifiManager#WIFI_STATE_DISABLING}, 647 * {@link WifiManager#WIFI_STATE_ENABLED}, 648 * {@link WifiManager#WIFI_STATE_ENABLING}, 649 * {@link WifiManager#WIFI_STATE_UNKNOWN} 650 * 651 */ 652 private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED); 653 654 /** 655 * One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 656 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 657 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 658 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 659 * {@link WifiManager#WIFI_AP_STATE_FAILED} 660 * 661 */ 662 private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED); 663 664 private static final int SCAN_REQUEST = 0; 665 private static final String ACTION_START_SCAN = 666 "com.android.server.WifiManager.action.START_SCAN"; 667 668 private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter"; 669 private static final int DRIVER_STOP_REQUEST = 0; 670 private static final String ACTION_DELAYED_DRIVER_STOP = 671 "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP"; 672 673 private static final String ACTION_REFRESH_BATCHED_SCAN = 674 "com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN"; 675 /** 676 * Keep track of whether WIFI is running. 677 */ 678 private boolean mIsRunning = false; 679 680 /** 681 * Keep track of whether we last told the battery stats we had started. 682 */ 683 private boolean mReportedRunning = false; 684 685 /** 686 * Most recently set source of starting WIFI. 687 */ 688 private final WorkSource mRunningWifiUids = new WorkSource(); 689 690 /** 691 * The last reported UIDs that were responsible for starting WIFI. 692 */ 693 private final WorkSource mLastRunningWifiUids = new WorkSource(); 694 695 private final IBatteryStats mBatteryStats; 696 697 private BatchedScanSettings mBatchedScanSettings = null; 698 699 /** 700 * Track the worksource/cost of the current settings and track what's been noted 701 * to the battery stats, so we can mark the end of the previous when changing. 702 */ 703 private WorkSource mBatchedScanWorkSource = null; 704 private int mBatchedScanCsph = 0; 705 private WorkSource mNotedBatchedScanWorkSource = null; 706 private int mNotedBatchedScanCsph = 0; 707 708 private WifiConfiguration mLastConnectAttempt = null; //at the moment used for debug 709 710 private AtomicBoolean mFrameworkAutoJoin = new AtomicBoolean(true); //enable by default 711 712 public WifiStateMachine(Context context, String wlanInterface, WifiTrafficPoller trafficPoller) { 713 super("WifiStateMachine"); 714 mContext = context; 715 mInterfaceName = wlanInterface; 716 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); 717 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 718 BatteryStats.SERVICE_NAME)); 719 720 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 721 mNwService = INetworkManagementService.Stub.asInterface(b); 722 723 mP2pSupported = mContext.getPackageManager().hasSystemFeature( 724 PackageManager.FEATURE_WIFI_DIRECT); 725 726 mWifiNative = new WifiNative(mInterfaceName); 727 mWifiConfigStore = new WifiConfigStore(context, mWifiNative); 728 mWifiAutoJoinController = new WifiAutoJoinController(context, this, 729 mWifiConfigStore, trafficPoller, mWifiNative); 730 mWifiMonitor = new WifiMonitor(this, mWifiNative); 731 mWifiInfo = new WifiInfo(); 732 mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, 733 getHandler()); 734 mLinkProperties = new LinkProperties(); 735 mNetlinkLinkProperties = new LinkProperties(); 736 737 IBinder s = ServiceManager.getService(Context.WIFI_P2P_SERVICE); 738 mWifiP2pServiceImpl = (WifiP2pServiceImpl)IWifiP2pManager.Stub.asInterface(s); 739 740 mNetworkInfo.setIsAvailable(false); 741 mLastBssid = null; 742 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 743 mLastSignalLevel = -1; 744 745 mInterfaceObserver = new InterfaceObserver(this); 746 try { 747 mNwService.registerObserver(mInterfaceObserver); 748 } catch (RemoteException e) { 749 loge("Couldn't register interface observer: " + e.toString()); 750 } 751 752 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 753 Intent scanIntent = new Intent(ACTION_START_SCAN, null); 754 mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0); 755 756 Intent batchedIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null); 757 mBatchedScanIntervalIntent = PendingIntent.getBroadcast(mContext, 0, batchedIntent, 0); 758 759 mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger( 760 R.integer.config_wifi_framework_scan_interval); 761 762 mDriverStopDelayMs = mContext.getResources().getInteger( 763 R.integer.config_wifi_driver_stop_delay); 764 765 mBackgroundScanSupported = mContext.getResources().getBoolean( 766 R.bool.config_wifi_background_scan_support); 767 768 mPrimaryDeviceType = mContext.getResources().getString( 769 R.string.config_wifi_p2p_device_type); 770 771 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 772 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 773 774 mFrameworkAutoJoin.set(Settings.Global.getInt(mContext.getContentResolver(), 775 Settings.Global.WIFI_ENHANCED_AUTO_JOIN, 1) == 1); 776 777 778 mContext.registerReceiver( 779 new BroadcastReceiver() { 780 @Override 781 public void onReceive(Context context, Intent intent) { 782 ArrayList<String> available = intent.getStringArrayListExtra( 783 ConnectivityManager.EXTRA_AVAILABLE_TETHER); 784 ArrayList<String> active = intent.getStringArrayListExtra( 785 ConnectivityManager.EXTRA_ACTIVE_TETHER); 786 sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active)); 787 } 788 },new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); 789 790 mContext.registerReceiver( 791 new BroadcastReceiver() { 792 @Override 793 public void onReceive(Context context, Intent intent) { 794 startScan(UNKNOWN_SCAN_SOURCE, null, null); 795 if (VDBG) 796 loge("WiFiStateMachine SCAN ALARM"); 797 } 798 }, 799 new IntentFilter(ACTION_START_SCAN)); 800 801 IntentFilter filter = new IntentFilter(); 802 filter.addAction(Intent.ACTION_SCREEN_ON); 803 filter.addAction(Intent.ACTION_SCREEN_OFF); 804 filter.addAction(ACTION_REFRESH_BATCHED_SCAN); 805 mContext.registerReceiver( 806 new BroadcastReceiver() { 807 @Override 808 public void onReceive(Context context, Intent intent) { 809 String action = intent.getAction(); 810 811 if (action.equals(Intent.ACTION_SCREEN_ON)) { 812 handleScreenStateChanged(true); 813 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 814 handleScreenStateChanged(false); 815 } else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) { 816 startNextBatchedScanAsync(); 817 } 818 } 819 }, filter); 820 821 mContext.registerReceiver( 822 new BroadcastReceiver() { 823 @Override 824 public void onReceive(Context context, Intent intent) { 825 int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0); 826 sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0); 827 } 828 }, 829 new IntentFilter(ACTION_DELAYED_DRIVER_STOP)); 830 831 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 832 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false, 833 new ContentObserver(getHandler()) { 834 @Override 835 public void onChange(boolean selfChange) { 836 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 837 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 838 } 839 }); 840 841 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 842 Settings.Global.WIFI_ENHANCED_AUTO_JOIN), false, 843 new ContentObserver(getHandler()) { 844 @Override 845 public void onChange(boolean selfChange) { 846 mFrameworkAutoJoin.set(Settings.Global.getInt(mContext.getContentResolver(), 847 Settings.Global.WIFI_ENHANCED_AUTO_JOIN, 0) == 1); 848 } 849 }); 850 851 852 mContext.registerReceiver( 853 new BroadcastReceiver() { 854 @Override 855 public void onReceive(Context context, Intent intent) { 856 sendMessage(CMD_BOOT_COMPLETED); 857 } 858 }, 859 new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); 860 861 mScanResultCache = new LruCache<String, ScanResult>(SCAN_RESULT_CACHE_SIZE); 862 863 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 864 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName()); 865 866 mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend"); 867 mSuspendWakeLock.setReferenceCounted(false); 868 869 addState(mDefaultState); 870 addState(mInitialState, mDefaultState); 871 addState(mSupplicantStartingState, mDefaultState); 872 addState(mSupplicantStartedState, mDefaultState); 873 addState(mDriverStartingState, mSupplicantStartedState); 874 addState(mDriverStartedState, mSupplicantStartedState); 875 addState(mScanModeState, mDriverStartedState); 876 addState(mConnectModeState, mDriverStartedState); 877 addState(mL2ConnectedState, mConnectModeState); 878 addState(mObtainingIpState, mL2ConnectedState); 879 addState(mVerifyingLinkState, mL2ConnectedState); 880 addState(mConnectedState, mL2ConnectedState); 881 addState(mDisconnectingState, mConnectModeState); 882 addState(mDisconnectedState, mConnectModeState); 883 addState(mWpsRunningState, mConnectModeState); 884 addState(mWaitForP2pDisableState, mSupplicantStartedState); 885 addState(mDriverStoppingState, mSupplicantStartedState); 886 addState(mDriverStoppedState, mSupplicantStartedState); 887 addState(mSupplicantStoppingState, mDefaultState); 888 addState(mSoftApStartingState, mDefaultState); 889 addState(mSoftApStartedState, mDefaultState); 890 addState(mTetheringState, mSoftApStartedState); 891 addState(mTetheredState, mSoftApStartedState); 892 addState(mUntetheringState, mSoftApStartedState); 893 894 setInitialState(mInitialState); 895 896 setLogRecSize(2000); 897 setLogOnlyTransitions(false); 898 if (VDBG) setDbg(true); 899 900 //start the state machine 901 start(); 902 903 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 904 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 905 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 906 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 907 } 908 909 /* 910 * 911 * Framework scan control 912 */ 913 914 private boolean mAlarmEnabled = false; 915 /* This is set from the overlay config file or from a secure setting. 916 * A value of 0 disables scanning in the framework. 917 */ 918 private long mFrameworkScanIntervalMs = 10000; 919 920 private long mCurrentScanAlarmMs = 10000; 921 922 923 private void setScanAlarm(boolean enabled) { 924 if (PDBG) { 925 loge("setScanAlarm " + enabled + " period " + mCurrentScanAlarmMs); 926 } 927 if (enabled == mAlarmEnabled) return; 928 if (enabled) { 929 if (mCurrentScanAlarmMs > 0) { 930 if (mCurrentScanAlarmMs < 10000) { 931 //paranoia 932 mCurrentScanAlarmMs = 10000; 933 } 934 935 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, 936 System.currentTimeMillis() + mCurrentScanAlarmMs, 937 mCurrentScanAlarmMs, 938 mScanIntent); 939 mAlarmEnabled = true; 940 } 941 } else { 942 mAlarmManager.cancel(mScanIntent); 943 mAlarmEnabled = false; 944 } 945 } 946 947 /********************************************************* 948 * Methods exposed for public use 949 ********************************************************/ 950 951 public Messenger getMessenger() { 952 return new Messenger(getHandler()); 953 } 954 /** 955 * TODO: doc 956 */ 957 public boolean syncPingSupplicant(AsyncChannel channel) { 958 Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT); 959 boolean result = (resultMsg.arg1 != FAILURE); 960 resultMsg.recycle(); 961 return result; 962 } 963 964 public List<WifiChannel> syncGetChannelList(AsyncChannel channel) { 965 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CAPABILITY_FREQ); 966 List<WifiChannel> list = null; 967 if (resultMsg.obj != null) { 968 list = new ArrayList<WifiChannel>(); 969 String freqs = (String) resultMsg.obj; 970 String[] lines = freqs.split("\n"); 971 for (String line : lines) 972 if (line.contains("MHz")) { 973 // line format: " 52 = 5260 MHz (NO_IBSS) (DFS)" 974 WifiChannel c = new WifiChannel(); 975 String[] prop = line.split(" "); 976 if (prop.length < 5) continue; 977 try { 978 c.channelNum = Integer.parseInt(prop[1]); 979 c.freqMHz = Integer.parseInt(prop[3]); 980 } catch (NumberFormatException e) { } 981 c.isDFS = line.contains("(DFS)"); 982 list.add(c); 983 } else if (line.contains("Mode[B] Channels:")) { 984 // B channels are the same as G channels, skipped 985 break; 986 } 987 } 988 resultMsg.recycle(); 989 return (list != null && list.size() > 0) ? list : null; 990 } 991 992 993 /** 994 * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is 995 * given to callingUid. 996 * 997 * @param callingUid The uid initiating the wifi scan. Blame will be given here unless 998 * workSource is specified. 999 * @param workSource If not null, blame is given to workSource. 1000 * @param settings Scan settings, see {@link ScanSettings}. 1001 */ 1002 public void startScan(int callingUid, ScanSettings settings, WorkSource workSource) { 1003 Bundle bundle = new Bundle(); 1004 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings); 1005 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1006 sendMessage(CMD_START_SCAN, callingUid, 0, bundle); 1007 } 1008 1009 /** 1010 * start or stop batched scanning using the given settings 1011 */ 1012 public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph, 1013 WorkSource workSource) { 1014 Bundle bundle = new Bundle(); 1015 bundle.putParcelable(BATCHED_SETTING, settings); 1016 bundle.putParcelable(BATCHED_WORKSOURCE, workSource); 1017 sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle); 1018 } 1019 1020 public List<BatchedScanResult> syncGetBatchedScanResultsList() { 1021 synchronized (mBatchedScanResults) { 1022 List<BatchedScanResult> batchedScanList = 1023 new ArrayList<BatchedScanResult>(mBatchedScanResults.size()); 1024 for(BatchedScanResult result: mBatchedScanResults) { 1025 batchedScanList.add(new BatchedScanResult(result)); 1026 } 1027 return batchedScanList; 1028 } 1029 } 1030 1031 public void requestBatchedScanPoll() { 1032 sendMessage(CMD_POLL_BATCHED_SCAN); 1033 } 1034 1035 private void startBatchedScan() { 1036 if (mBatchedScanSettings == null) return; 1037 1038 if (mDhcpActive) { 1039 if (DBG) log("not starting Batched Scans due to DHCP"); 1040 return; 1041 } 1042 1043 // first grab any existing data 1044 retrieveBatchedScanData(); 1045 1046 if (PDBG) loge("try starting Batched Scans due to DHCP"); 1047 1048 1049 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1050 1051 String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings); 1052 try { 1053 mExpectedBatchedScans = Integer.parseInt(scansExpected); 1054 setNextBatchedAlarm(mExpectedBatchedScans); 1055 if (mExpectedBatchedScans > 0) noteBatchedScanStart(); 1056 } catch (NumberFormatException e) { 1057 stopBatchedScan(); 1058 loge("Exception parsing WifiNative.setBatchedScanSettings response " + e); 1059 } 1060 } 1061 1062 // called from BroadcastListener 1063 private void startNextBatchedScanAsync() { 1064 sendMessage(CMD_START_NEXT_BATCHED_SCAN); 1065 } 1066 1067 private void startNextBatchedScan() { 1068 // first grab any existing data 1069 retrieveBatchedScanData(); 1070 1071 setNextBatchedAlarm(mExpectedBatchedScans); 1072 } 1073 1074 private void handleBatchedScanPollRequest() { 1075 if (DBG) { 1076 log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" + 1077 mBatchedScanMinPollTime + " , mBatchedScanSettings=" + 1078 mBatchedScanSettings); 1079 } 1080 // if there is no appropriate PollTime that's because we either aren't 1081 // batching or we've already set a time for a poll request 1082 if (mBatchedScanMinPollTime == 0) return; 1083 if (mBatchedScanSettings == null) return; 1084 1085 long now = System.currentTimeMillis(); 1086 1087 if (now > mBatchedScanMinPollTime) { 1088 // do the poll and reset our timers 1089 startNextBatchedScan(); 1090 } else { 1091 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime, 1092 mBatchedScanIntervalIntent); 1093 mBatchedScanMinPollTime = 0; 1094 } 1095 } 1096 1097 // return true if new/different 1098 private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) { 1099 BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING); 1100 WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE); 1101 1102 if (DBG) { 1103 log("set batched scan to " + settings + " for uid=" + responsibleUid + 1104 ", worksource=" + responsibleWorkSource); 1105 } 1106 if (settings != null) { 1107 if (settings.equals(mBatchedScanSettings)) return false; 1108 } else { 1109 if (mBatchedScanSettings == null) return false; 1110 } 1111 mBatchedScanSettings = settings; 1112 if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid); 1113 mBatchedScanWorkSource = responsibleWorkSource; 1114 mBatchedScanCsph = csph; 1115 return true; 1116 } 1117 1118 private void stopBatchedScan() { 1119 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1120 retrieveBatchedScanData(); 1121 mWifiNative.setBatchedScanSettings(null); 1122 noteBatchedScanStop(); 1123 } 1124 1125 private void setNextBatchedAlarm(int scansExpected) { 1126 1127 if (mBatchedScanSettings == null || scansExpected < 1) return; 1128 1129 mBatchedScanMinPollTime = System.currentTimeMillis() + 1130 mBatchedScanSettings.scanIntervalSec * 1000; 1131 1132 if (mBatchedScanSettings.maxScansPerBatch < scansExpected) { 1133 scansExpected = mBatchedScanSettings.maxScansPerBatch; 1134 } 1135 1136 int secToFull = mBatchedScanSettings.scanIntervalSec; 1137 secToFull *= scansExpected; 1138 1139 int debugPeriod = SystemProperties.getInt("wifi.batchedScan.pollPeriod", 0); 1140 if (debugPeriod > 0) secToFull = debugPeriod; 1141 1142 // set the alarm to do the next poll. We set it a little short as we'd rather 1143 // wake up wearly than miss a scan due to buffer overflow 1144 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 1145 + ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000), 1146 mBatchedScanIntervalIntent); 1147 } 1148 1149 /** 1150 * Start reading new scan data 1151 * Data comes in as: 1152 * "scancount=5\n" 1153 * "nextcount=5\n" 1154 * "apcount=3\n" 1155 * "trunc\n" (optional) 1156 * "bssid=...\n" 1157 * "ssid=...\n" 1158 * "freq=...\n" (in Mhz) 1159 * "level=...\n" 1160 * "dist=...\n" (in cm) 1161 * "distsd=...\n" (standard deviation, in cm) 1162 * "====" 1163 * "bssid=...\n" 1164 * etc 1165 * "====" 1166 * "bssid=...\n" 1167 * etc 1168 * "%%%%" 1169 * "apcount=2\n" 1170 * "bssid=...\n" 1171 * etc 1172 * "%%%% 1173 * etc 1174 * "----" 1175 */ 1176 private final static boolean DEBUG_PARSE = false; 1177 private void retrieveBatchedScanData() { 1178 String rawData = mWifiNative.getBatchedScanResults(); 1179 if (DEBUG_PARSE) log("rawData = " + rawData); 1180 mBatchedScanMinPollTime = 0; 1181 if (rawData == null || rawData.equalsIgnoreCase("OK")) { 1182 loge("Unexpected BatchedScanResults :" + rawData); 1183 return; 1184 } 1185 1186 int scanCount = 0; 1187 final String END_OF_BATCHES = "----"; 1188 final String SCANCOUNT = "scancount="; 1189 final String TRUNCATED = "trunc"; 1190 final String AGE = "age="; 1191 final String DIST = "dist="; 1192 final String DISTSD = "distSd="; 1193 1194 String splitData[] = rawData.split("\n"); 1195 int n = 0; 1196 if (splitData[n].startsWith(SCANCOUNT)) { 1197 try { 1198 scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length())); 1199 } catch (NumberFormatException e) { 1200 loge("scancount parseInt Exception from " + splitData[n]); 1201 } 1202 } else log("scancount not found"); 1203 if (scanCount == 0) { 1204 loge("scanCount==0 - aborting"); 1205 return; 1206 } 1207 1208 final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION); 1209 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1210 1211 synchronized (mBatchedScanResults) { 1212 mBatchedScanResults.clear(); 1213 BatchedScanResult batchedScanResult = new BatchedScanResult(); 1214 1215 String bssid = null; 1216 WifiSsid wifiSsid = null; 1217 int level = 0; 1218 int freq = 0; 1219 int dist, distSd; 1220 long tsf = 0; 1221 dist = distSd = ScanResult.UNSPECIFIED; 1222 final long now = SystemClock.elapsedRealtime(); 1223 final int bssidStrLen = BSSID_STR.length(); 1224 1225 while (true) { 1226 while (n < splitData.length) { 1227 if (DEBUG_PARSE) logd("parsing " + splitData[n]); 1228 if (splitData[n].equals(END_OF_BATCHES)) { 1229 if (n+1 != splitData.length) { 1230 loge("didn't consume " + (splitData.length-n)); 1231 } 1232 if (mBatchedScanResults.size() > 0) { 1233 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1234 } 1235 logd("retrieveBatchedScanResults X"); 1236 return; 1237 } 1238 if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) { 1239 if (bssid != null) { 1240 batchedScanResult.scanResults.add(new ScanResult( 1241 wifiSsid, bssid, "", level, freq, tsf, dist, distSd)); 1242 wifiSsid = null; 1243 bssid = null; 1244 level = 0; 1245 freq = 0; 1246 tsf = 0; 1247 dist = distSd = ScanResult.UNSPECIFIED; 1248 } 1249 if (splitData[n].equals(END_STR)) { 1250 if (batchedScanResult.scanResults.size() != 0) { 1251 mBatchedScanResults.add(batchedScanResult); 1252 batchedScanResult = new BatchedScanResult(); 1253 } else { 1254 logd("Found empty batch"); 1255 } 1256 } 1257 } else if (splitData[n].equals(TRUNCATED)) { 1258 batchedScanResult.truncated = true; 1259 } else if (splitData[n].startsWith(BSSID_STR)) { 1260 bssid = new String(splitData[n].getBytes(), bssidStrLen, 1261 splitData[n].length() - bssidStrLen); 1262 } else if (splitData[n].startsWith(FREQ_STR)) { 1263 try { 1264 freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length())); 1265 } catch (NumberFormatException e) { 1266 loge("Invalid freqency: " + splitData[n]); 1267 freq = 0; 1268 } 1269 } else if (splitData[n].startsWith(AGE)) { 1270 try { 1271 tsf = now - Long.parseLong(splitData[n].substring(AGE.length())); 1272 tsf *= 1000; // convert mS -> uS 1273 } catch (NumberFormatException e) { 1274 loge("Invalid timestamp: " + splitData[n]); 1275 tsf = 0; 1276 } 1277 } else if (splitData[n].startsWith(SSID_STR)) { 1278 wifiSsid = WifiSsid.createFromAsciiEncoded( 1279 splitData[n].substring(SSID_STR.length())); 1280 } else if (splitData[n].startsWith(LEVEL_STR)) { 1281 try { 1282 level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length())); 1283 if (level > 0) level -= 256; 1284 } catch (NumberFormatException e) { 1285 loge("Invalid level: " + splitData[n]); 1286 level = 0; 1287 } 1288 } else if (splitData[n].startsWith(DIST)) { 1289 try { 1290 dist = Integer.parseInt(splitData[n].substring(DIST.length())); 1291 } catch (NumberFormatException e) { 1292 loge("Invalid distance: " + splitData[n]); 1293 dist = ScanResult.UNSPECIFIED; 1294 } 1295 } else if (splitData[n].startsWith(DISTSD)) { 1296 try { 1297 distSd = Integer.parseInt(splitData[n].substring(DISTSD.length())); 1298 } catch (NumberFormatException e) { 1299 loge("Invalid distanceSd: " + splitData[n]); 1300 distSd = ScanResult.UNSPECIFIED; 1301 } 1302 } else { 1303 loge("Unable to parse batched scan result line: " + splitData[n]); 1304 } 1305 n++; 1306 } 1307 rawData = mWifiNative.getBatchedScanResults(); 1308 if (DEBUG_PARSE) log("reading more data:\n" + rawData); 1309 if (rawData == null) { 1310 loge("Unexpected null BatchedScanResults"); 1311 return; 1312 } 1313 splitData = rawData.split("\n"); 1314 if (splitData.length == 0 || splitData[0].equals("ok")) { 1315 loge("batch scan results just ended!"); 1316 if (mBatchedScanResults.size() > 0) { 1317 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1318 } 1319 return; 1320 } 1321 n = 0; 1322 } 1323 } 1324 } 1325 1326 // If workSource is not null, blame is given to it, otherwise blame is given to callingUid. 1327 private void noteScanStart(int callingUid, WorkSource workSource) { 1328 if (DBG) { 1329 long now = SystemClock.elapsedRealtimeNanos(); 1330 String ts = String.format("[%,d us]", now/1000); 1331 if (workSource != null) { 1332 loge(ts + " noteScanStart" + workSource.toString() 1333 + " uid " + Integer.toString(callingUid)); 1334 } else { 1335 loge(ts + " noteScanstart no scan source"); 1336 } 1337 } 1338 if (mScanWorkSource == null && (callingUid != UNKNOWN_SCAN_SOURCE || workSource != null)) { 1339 mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid); 1340 try { 1341 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource); 1342 } catch (RemoteException e) { 1343 log(e.toString()); 1344 } 1345 } 1346 } 1347 1348 private void noteScanEnd() { 1349 if (DBG) { 1350 long now = SystemClock.elapsedRealtimeNanos(); 1351 String ts = String.format("[%,d us]", now/1000); 1352 1353 if (mScanWorkSource != null) 1354 loge(ts + " noteScanEnd " + mScanWorkSource.toString()); 1355 else 1356 loge(ts + " noteScanEnd no scan source"); 1357 } 1358 if (mScanWorkSource != null) { 1359 try { 1360 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource); 1361 } catch (RemoteException e) { 1362 log(e.toString()); 1363 } finally { 1364 mScanWorkSource = null; 1365 } 1366 } 1367 } 1368 1369 private void noteBatchedScanStart() { 1370 if (PDBG) loge("noteBatchedScanstart()"); 1371 // note the end of a previous scan set 1372 if (mNotedBatchedScanWorkSource != null && 1373 (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false || 1374 mNotedBatchedScanCsph != mBatchedScanCsph)) { 1375 try { 1376 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1377 } catch (RemoteException e) { 1378 log(e.toString()); 1379 } finally { 1380 mNotedBatchedScanWorkSource = null; 1381 mNotedBatchedScanCsph = 0; 1382 } 1383 } 1384 // note the start of the new 1385 try { 1386 mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource, 1387 mBatchedScanCsph); 1388 mNotedBatchedScanWorkSource = mBatchedScanWorkSource; 1389 mNotedBatchedScanCsph = mBatchedScanCsph; 1390 } catch (RemoteException e) { 1391 log(e.toString()); 1392 } 1393 } 1394 1395 private void noteBatchedScanStop() { 1396 if (PDBG) loge("noteBatchedScanstop()"); 1397 1398 if (mNotedBatchedScanWorkSource != null) { 1399 try { 1400 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1401 } catch (RemoteException e) { 1402 log(e.toString()); 1403 } finally { 1404 mNotedBatchedScanWorkSource = null; 1405 mNotedBatchedScanCsph = 0; 1406 } 1407 } 1408 } 1409 1410 private void handleScanRequest(int type, Message message) { 1411 // unbundle parameters 1412 Bundle bundle = (Bundle) message.obj; 1413 ScanSettings settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING); 1414 WorkSource workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE); 1415 1416 // parse scan settings 1417 String freqs = null; 1418 if (settings != null && settings.channelSet != null) { 1419 StringBuilder sb = new StringBuilder(); 1420 boolean first = true; 1421 for (WifiChannel channel : settings.channelSet) { 1422 if (!first) sb.append(','); else first = false; 1423 sb.append(channel.freqMHz); 1424 } 1425 freqs = sb.toString(); 1426 } 1427 1428 // call wifi native to start the scan 1429 if (startScanNative(type, freqs)) { 1430 // only count battery consumption if scan request is accepted 1431 noteScanStart(message.arg1, workSource); 1432 // a full scan covers everything, clearing scan request buffer 1433 if (freqs == null) 1434 mBufferedScanMsg.clear(); 1435 return; 1436 } 1437 1438 // if reach here, scan request is rejected 1439 1440 if (!mIsScanOngoing) { 1441 // if rejection is NOT due to ongoing scan (e.g. bad scan parameters), 1442 // discard this request and pop up the next one 1443 if (mBufferedScanMsg.size() > 0) 1444 sendMessage(mBufferedScanMsg.remove()); 1445 } else if (!mIsFullScanOngoing) { 1446 // if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan, 1447 // buffer the scan request to make sure specified channels will be scanned eventually 1448 if (freqs == null) 1449 mBufferedScanMsg.clear(); 1450 if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) { 1451 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, 0, bundle); 1452 mBufferedScanMsg.add(msg); 1453 } else { 1454 // if too many requests in buffer, combine them into a single full scan 1455 bundle = new Bundle(); 1456 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null); 1457 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1458 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, 0, bundle); 1459 mBufferedScanMsg.clear(); 1460 mBufferedScanMsg.add(msg); 1461 } 1462 } 1463 } 1464 1465 1466 /** return true iff scan request is accepted */ 1467 private boolean startScanNative(int type, String freqs) { 1468 if (mWifiNative.scan(type, freqs)) { 1469 mIsScanOngoing = true; 1470 mIsFullScanOngoing = (freqs == null); 1471 return true; 1472 } 1473 return false; 1474 } 1475 1476 /** 1477 * TODO: doc 1478 */ 1479 public void setSupplicantRunning(boolean enable) { 1480 if (enable) { 1481 sendMessage(CMD_START_SUPPLICANT); 1482 } else { 1483 sendMessage(CMD_STOP_SUPPLICANT); 1484 } 1485 } 1486 1487 /** 1488 * TODO: doc 1489 */ 1490 public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) { 1491 if (enable) { 1492 sendMessage(CMD_START_AP, wifiConfig); 1493 } else { 1494 sendMessage(CMD_STOP_AP); 1495 } 1496 } 1497 1498 public void setWifiApConfiguration(WifiConfiguration config) { 1499 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 1500 } 1501 1502 public WifiConfiguration syncGetWifiApConfiguration() { 1503 Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG); 1504 WifiConfiguration ret = (WifiConfiguration) resultMsg.obj; 1505 resultMsg.recycle(); 1506 return ret; 1507 } 1508 1509 /** 1510 * TODO: doc 1511 */ 1512 public int syncGetWifiState() { 1513 return mWifiState.get(); 1514 } 1515 1516 /** 1517 * TODO: doc 1518 */ 1519 public String syncGetWifiStateByName() { 1520 switch (mWifiState.get()) { 1521 case WIFI_STATE_DISABLING: 1522 return "disabling"; 1523 case WIFI_STATE_DISABLED: 1524 return "disabled"; 1525 case WIFI_STATE_ENABLING: 1526 return "enabling"; 1527 case WIFI_STATE_ENABLED: 1528 return "enabled"; 1529 case WIFI_STATE_UNKNOWN: 1530 return "unknown state"; 1531 default: 1532 return "[invalid state]"; 1533 } 1534 } 1535 1536 /** 1537 * TODO: doc 1538 */ 1539 public int syncGetWifiApState() { 1540 return mWifiApState.get(); 1541 } 1542 1543 /** 1544 * TODO: doc 1545 */ 1546 public String syncGetWifiApStateByName() { 1547 switch (mWifiApState.get()) { 1548 case WIFI_AP_STATE_DISABLING: 1549 return "disabling"; 1550 case WIFI_AP_STATE_DISABLED: 1551 return "disabled"; 1552 case WIFI_AP_STATE_ENABLING: 1553 return "enabling"; 1554 case WIFI_AP_STATE_ENABLED: 1555 return "enabled"; 1556 case WIFI_AP_STATE_FAILED: 1557 return "failed"; 1558 default: 1559 return "[invalid state]"; 1560 } 1561 } 1562 1563 /** 1564 * Get status information for the current connection, if any. 1565 * @return a {@link WifiInfo} object containing information about the current connection 1566 * 1567 */ 1568 public WifiInfo syncRequestConnectionInfo() { 1569 return mWifiInfo; 1570 } 1571 1572 public DhcpResults syncGetDhcpResults() { 1573 synchronized (mDhcpResultsLock) { 1574 return new DhcpResults(mDhcpResults); 1575 } 1576 } 1577 1578 /** 1579 * TODO: doc 1580 */ 1581 public void setDriverStart(boolean enable) { 1582 if (enable) { 1583 sendMessage(CMD_START_DRIVER); 1584 } else { 1585 sendMessage(CMD_STOP_DRIVER); 1586 } 1587 } 1588 1589 /** 1590 * TODO: doc 1591 */ 1592 public void setOperationalMode(int mode) { 1593 if (DBG) log("setting operational mode to " + String.valueOf(mode)); 1594 sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0); 1595 } 1596 1597 /** 1598 * TODO: doc 1599 */ 1600 public List<ScanResult> syncGetScanResultsList() { 1601 synchronized (mScanResultCache) { 1602 List<ScanResult> scanList = new ArrayList<ScanResult>(); 1603 for(ScanResult result: mScanResults) { 1604 scanList.add(new ScanResult(result)); 1605 } 1606 return scanList; 1607 } 1608 } 1609 1610 /** 1611 * Disconnect from Access Point 1612 */ 1613 public void disconnectCommand() { 1614 sendMessage(CMD_DISCONNECT); 1615 } 1616 1617 /** 1618 * Initiate a reconnection to AP 1619 */ 1620 public void reconnectCommand() { 1621 sendMessage(CMD_RECONNECT); 1622 } 1623 1624 /** 1625 * Initiate a re-association to AP 1626 */ 1627 public void reassociateCommand() { 1628 sendMessage(CMD_REASSOCIATE); 1629 } 1630 1631 /** 1632 * Reload networks and then reconnect; helps load correct data for TLS networks 1633 */ 1634 1635 public void reloadTlsNetworksAndReconnect() { 1636 sendMessage(CMD_RELOAD_TLS_AND_RECONNECT); 1637 } 1638 1639 /** 1640 * Add a network synchronously 1641 * 1642 * @return network id of the new network 1643 */ 1644 public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) { 1645 Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config); 1646 int result = resultMsg.arg1; 1647 resultMsg.recycle(); 1648 return result; 1649 } 1650 1651 public List<WifiConfiguration> syncGetConfiguredNetworks(AsyncChannel channel) { 1652 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS); 1653 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 1654 resultMsg.recycle(); 1655 return result; 1656 } 1657 1658 /** 1659 * Delete a network 1660 * 1661 * @param networkId id of the network to be removed 1662 */ 1663 public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) { 1664 Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId); 1665 boolean result = (resultMsg.arg1 != FAILURE); 1666 resultMsg.recycle(); 1667 return result; 1668 } 1669 1670 /** 1671 * Enable a network 1672 * 1673 * @param netId network id of the network 1674 * @param disableOthers true, if all other networks have to be disabled 1675 * @return {@code true} if the operation succeeds, {@code false} otherwise 1676 */ 1677 public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) { 1678 Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId, 1679 disableOthers ? 1 : 0); 1680 boolean result = (resultMsg.arg1 != FAILURE); 1681 resultMsg.recycle(); 1682 return result; 1683 } 1684 1685 /** 1686 * Disable a network 1687 * 1688 * @param netId network id of the network 1689 * @return {@code true} if the operation succeeds, {@code false} otherwise 1690 */ 1691 public boolean syncDisableNetwork(AsyncChannel channel, int netId) { 1692 Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId); 1693 boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED); 1694 resultMsg.recycle(); 1695 return result; 1696 } 1697 1698 /** 1699 * Retrieves a WPS-NFC configuration token for the specified network 1700 * @return a hex string representation of the WPS-NFC configuration token 1701 */ 1702 public String syncGetWpsNfcConfigurationToken(int netId) { 1703 return mWifiNative.getNfcWpsConfigurationToken(netId); 1704 } 1705 1706 /** 1707 * Blacklist a BSSID. This will avoid the AP if there are 1708 * alternate APs to connect 1709 * 1710 * @param bssid BSSID of the network 1711 */ 1712 public void addToBlacklist(String bssid) { 1713 sendMessage(CMD_BLACKLIST_NETWORK, bssid); 1714 } 1715 1716 /** 1717 * Clear the blacklist list 1718 * 1719 */ 1720 public void clearBlacklist() { 1721 sendMessage(CMD_CLEAR_BLACKLIST); 1722 } 1723 1724 public void enableRssiPolling(boolean enabled) { 1725 sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0); 1726 } 1727 1728 public void enableBackgroundScanCommand(boolean enabled) { 1729 sendMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0); 1730 } 1731 1732 public void enableAllNetworks() { 1733 sendMessage(CMD_ENABLE_ALL_NETWORKS); 1734 } 1735 1736 /** 1737 * Start filtering Multicast v4 packets 1738 */ 1739 public void startFilteringMulticastV4Packets() { 1740 mFilteringMulticastV4Packets.set(true); 1741 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0); 1742 } 1743 1744 /** 1745 * Stop filtering Multicast v4 packets 1746 */ 1747 public void stopFilteringMulticastV4Packets() { 1748 mFilteringMulticastV4Packets.set(false); 1749 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0); 1750 } 1751 1752 /** 1753 * Start filtering Multicast v4 packets 1754 */ 1755 public void startFilteringMulticastV6Packets() { 1756 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0); 1757 } 1758 1759 /** 1760 * Stop filtering Multicast v4 packets 1761 */ 1762 public void stopFilteringMulticastV6Packets() { 1763 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0); 1764 } 1765 1766 /** 1767 * Set high performance mode of operation. 1768 * Enabling would set active power mode and disable suspend optimizations; 1769 * disabling would set auto power mode and enable suspend optimizations 1770 * @param enable true if enable, false otherwise 1771 */ 1772 public void setHighPerfModeEnabled(boolean enable) { 1773 sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0); 1774 } 1775 1776 /** 1777 * Set the country code 1778 * @param countryCode following ISO 3166 format 1779 * @param persist {@code true} if the setting should be remembered. 1780 */ 1781 public void setCountryCode(String countryCode, boolean persist) { 1782 // if it's a country code, apply immediately, 1783 // if it's empty, delay it in case it's a momentary dropout 1784 int countryCodeSequence = mCountryCodeSequence.incrementAndGet(); 1785 if (TextUtils.isEmpty(countryCode)) { 1786 sendMessageDelayed(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, 1787 countryCode, COUNTRY_CODE_DELAY_MS); 1788 } else { 1789 sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, countryCode); 1790 } 1791 } 1792 1793 /** 1794 * Set the operational frequency band 1795 * @param band 1796 * @param persist {@code true} if the setting should be remembered. 1797 */ 1798 public void setFrequencyBand(int band, boolean persist) { 1799 if (persist) { 1800 Settings.Global.putInt(mContext.getContentResolver(), 1801 Settings.Global.WIFI_FREQUENCY_BAND, 1802 band); 1803 } 1804 sendMessage(CMD_SET_FREQUENCY_BAND, band, 0); 1805 } 1806 1807 /** 1808 * Enable TDLS for a specific MAC address 1809 */ 1810 public void enableTdls(String remoteMacAddress, boolean enable) { 1811 int enabler = enable ? 1 : 0; 1812 sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress); 1813 } 1814 1815 /** 1816 * Returns the operational frequency band 1817 */ 1818 public int getFrequencyBand() { 1819 return mFrequencyBand.get(); 1820 } 1821 1822 /** 1823 * Returns the wifi configuration file 1824 */ 1825 public String getConfigFile() { 1826 return mWifiConfigStore.getConfigFile(); 1827 } 1828 1829 /** 1830 * Send a message indicating bluetooth adapter connection state changed 1831 */ 1832 public void sendBluetoothAdapterStateChange(int state) { 1833 sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0); 1834 } 1835 1836 /** 1837 * Save configuration on supplicant 1838 * 1839 * @return {@code true} if the operation succeeds, {@code false} otherwise 1840 * 1841 * TODO: deprecate this 1842 */ 1843 public boolean syncSaveConfig(AsyncChannel channel) { 1844 Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG); 1845 boolean result = (resultMsg.arg1 != FAILURE); 1846 resultMsg.recycle(); 1847 return result; 1848 } 1849 1850 public void updateBatteryWorkSource(WorkSource newSource) { 1851 synchronized (mRunningWifiUids) { 1852 try { 1853 if (newSource != null) { 1854 mRunningWifiUids.set(newSource); 1855 } 1856 if (mIsRunning) { 1857 if (mReportedRunning) { 1858 // If the work source has changed since last time, need 1859 // to remove old work from battery stats. 1860 if (mLastRunningWifiUids.diff(mRunningWifiUids)) { 1861 mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids, 1862 mRunningWifiUids); 1863 mLastRunningWifiUids.set(mRunningWifiUids); 1864 } 1865 } else { 1866 // Now being started, report it. 1867 mBatteryStats.noteWifiRunning(mRunningWifiUids); 1868 mLastRunningWifiUids.set(mRunningWifiUids); 1869 mReportedRunning = true; 1870 } 1871 } else { 1872 if (mReportedRunning) { 1873 // Last reported we were running, time to stop. 1874 mBatteryStats.noteWifiStopped(mLastRunningWifiUids); 1875 mLastRunningWifiUids.clear(); 1876 mReportedRunning = false; 1877 } 1878 } 1879 mWakeLock.setWorkSource(newSource); 1880 } catch (RemoteException ignore) { 1881 } 1882 } 1883 } 1884 1885 @Override 1886 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1887 super.dump(fd, pw, args); 1888 mSupplicantStateTracker.dump(fd, pw, args); 1889 pw.println("mLinkProperties " + mLinkProperties); 1890 pw.println("mWifiInfo " + mWifiInfo); 1891 pw.println("mDhcpResults " + mDhcpResults); 1892 pw.println("mNetworkInfo " + mNetworkInfo); 1893 pw.println("mLastSignalLevel " + mLastSignalLevel); 1894 pw.println("mLastBssid " + mLastBssid); 1895 pw.println("mLastNetworkId " + mLastNetworkId); 1896 pw.println("mReconnectCount " + mReconnectCount); 1897 pw.println("mOperationalMode " + mOperationalMode); 1898 pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt); 1899 pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 1900 pw.println("Supplicant status " + mWifiNative.status()); 1901 pw.println("mEnableBackgroundScan " + mEnableBackgroundScan); 1902 pw.println(); 1903 mWifiConfigStore.dump(fd, pw, args); 1904 } 1905 1906 /********************************************************* 1907 * Internal private functions 1908 ********************************************************/ 1909 1910 private void logStateAndMessage(Message message, String state) { 1911 if (mLogMessages) { 1912 //long now = SystemClock.elapsedRealtimeNanos(); 1913 //String ts = String.format("[%,d us]", now/1000); 1914 1915 loge(/*ts + " " + */this.getClass().getSimpleName() 1916 + "state:" + state + " what:" + Integer.toString(message.what, 16) 1917 + " " + smToString(message) + " "); 1918 } 1919 } 1920 1921 private void handleScreenStateChanged(boolean screenOn) { 1922 mScreenOn = screenOn; 1923 if (PDBG) { 1924 loge(" handleScreenStateChanged Enter: screenOn=" + screenOn 1925 + "mCurrentScanAlarmMs = " + Long.toString(mCurrentScanAlarmMs) 1926 + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt 1927 + " autojoin " + mFrameworkAutoJoin 1928 + " state " + getCurrentState().getName() 1929 + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); 1930 } 1931 enableRssiPolling(screenOn); 1932 if (mBackgroundScanSupported) { 1933 enableBackgroundScanCommand(screenOn == false); 1934 } 1935 1936 if (screenOn) enableAllNetworks(); 1937 if (mUserWantsSuspendOpt.get()) { 1938 if (screenOn) { 1939 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0); 1940 } else { 1941 //Allow 2s for suspend optimizations to be set 1942 mSuspendWakeLock.acquire(2000); 1943 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0); 1944 } 1945 } 1946 mScreenBroadcastReceived.set(true); 1947 1948 if (screenOn) { 1949 if (mFrameworkAutoJoin.get()) { 1950 //start the scan alarm so as to enable autojoin 1951 if (getCurrentState() == mConnectedState) { 1952 mCurrentScanAlarmMs = mConnectedScanPeriodMs; 1953 } else if (getCurrentState() == mDisconnectedState) { 1954 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 1955 //kick a scan right now 1956 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 1957 1958 } else if (getCurrentState() == mDisconnectingState) { 1959 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 1960 //kick a scan right now 1961 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 1962 1963 } 1964 } 1965 setScanAlarm(true); 1966 1967 } else { 1968 setScanAlarm(false); 1969 } 1970 1971 1972 if (DBG) log("handleScreenStateChanged Exit: " + screenOn); 1973 1974 } 1975 1976 private void checkAndSetConnectivityInstance() { 1977 if (mCm == null) { 1978 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 1979 } 1980 } 1981 1982 private boolean startTethering(ArrayList<String> available) { 1983 1984 boolean wifiAvailable = false; 1985 1986 checkAndSetConnectivityInstance(); 1987 1988 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 1989 1990 for (String intf : available) { 1991 for (String regex : wifiRegexs) { 1992 if (intf.matches(regex)) { 1993 1994 InterfaceConfiguration ifcg = null; 1995 try { 1996 ifcg = mNwService.getInterfaceConfig(intf); 1997 if (ifcg != null) { 1998 /* IP/netmask: 192.168.43.1/255.255.255.0 */ 1999 ifcg.setLinkAddress(new LinkAddress( 2000 NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); 2001 ifcg.setInterfaceUp(); 2002 2003 mNwService.setInterfaceConfig(intf, ifcg); 2004 } 2005 } catch (Exception e) { 2006 loge("Error configuring interface " + intf + ", :" + e); 2007 return false; 2008 } 2009 2010 if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 2011 loge("Error tethering on " + intf); 2012 return false; 2013 } 2014 mTetherInterfaceName = intf; 2015 return true; 2016 } 2017 } 2018 } 2019 // We found no interfaces to tether 2020 return false; 2021 } 2022 2023 private void stopTethering() { 2024 2025 checkAndSetConnectivityInstance(); 2026 2027 /* Clear the interface config to allow dhcp correctly configure new 2028 ip settings */ 2029 InterfaceConfiguration ifcg = null; 2030 try { 2031 ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName); 2032 if (ifcg != null) { 2033 ifcg.setLinkAddress( 2034 new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); 2035 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg); 2036 } 2037 } catch (Exception e) { 2038 loge("Error resetting interface " + mTetherInterfaceName + ", :" + e); 2039 } 2040 2041 if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 2042 loge("Untether initiate failed!"); 2043 } 2044 } 2045 2046 private boolean isWifiTethered(ArrayList<String> active) { 2047 2048 checkAndSetConnectivityInstance(); 2049 2050 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 2051 for (String intf : active) { 2052 for (String regex : wifiRegexs) { 2053 if (intf.matches(regex)) { 2054 return true; 2055 } 2056 } 2057 } 2058 // We found no interfaces that are tethered 2059 return false; 2060 } 2061 2062 /** 2063 * Set the country code from the system setting value, if any. 2064 */ 2065 private void setCountryCode() { 2066 String countryCode = Settings.Global.getString(mContext.getContentResolver(), 2067 Settings.Global.WIFI_COUNTRY_CODE); 2068 if (countryCode != null && !countryCode.isEmpty()) { 2069 setCountryCode(countryCode, false); 2070 } else { 2071 //use driver default 2072 } 2073 } 2074 2075 /** 2076 * Set the frequency band from the system setting value, if any. 2077 */ 2078 private void setFrequencyBand() { 2079 int band = Settings.Global.getInt(mContext.getContentResolver(), 2080 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO); 2081 setFrequencyBand(band, false); 2082 } 2083 2084 private void setSuspendOptimizationsNative(int reason, boolean enabled) { 2085 if (DBG) { 2086 log("setSuspendOptimizationsNative: " + reason + " " + enabled 2087 + " -want " + mUserWantsSuspendOpt.get() 2088 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2089 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 2090 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 2091 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 2092 } 2093 mWifiNative.setSuspendOptimizations(enabled); 2094 2095 if (enabled) { 2096 mSuspendOptNeedsDisabled &= ~reason; 2097 /* None of dhcp, screen or highperf need it disabled and user wants it enabled */ 2098 if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) { 2099 if (DBG) { 2100 log("setSuspendOptimizationsNative do it " + reason + " " + enabled 2101 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 2102 +" - "+ Thread.currentThread().getStackTrace()[3].getMethodName() 2103 +" - "+ Thread.currentThread().getStackTrace()[4].getMethodName() 2104 +" - "+ Thread.currentThread().getStackTrace()[5].getMethodName()); 2105 } 2106 mWifiNative.setSuspendOptimizations(true); 2107 } 2108 } else { 2109 mSuspendOptNeedsDisabled |= reason; 2110 mWifiNative.setSuspendOptimizations(false); 2111 } 2112 } 2113 2114 private void setSuspendOptimizations(int reason, boolean enabled) { 2115 if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled); 2116 if (enabled) { 2117 mSuspendOptNeedsDisabled &= ~reason; 2118 } else { 2119 mSuspendOptNeedsDisabled |= reason; 2120 } 2121 if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 2122 } 2123 2124 private void setWifiState(int wifiState) { 2125 final int previousWifiState = mWifiState.get(); 2126 2127 try { 2128 if (wifiState == WIFI_STATE_ENABLED) { 2129 mBatteryStats.noteWifiOn(); 2130 } else if (wifiState == WIFI_STATE_DISABLED) { 2131 mBatteryStats.noteWifiOff(); 2132 } 2133 } catch (RemoteException e) { 2134 loge("Failed to note battery stats in wifi"); 2135 } 2136 2137 mWifiState.set(wifiState); 2138 2139 if (DBG) log("setWifiState: " + syncGetWifiStateByName()); 2140 2141 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 2142 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2143 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 2144 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 2145 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2146 } 2147 2148 private void setWifiApState(int wifiApState) { 2149 final int previousWifiApState = mWifiApState.get(); 2150 2151 try { 2152 if (wifiApState == WIFI_AP_STATE_ENABLED) { 2153 mBatteryStats.noteWifiOn(); 2154 } else if (wifiApState == WIFI_AP_STATE_DISABLED) { 2155 mBatteryStats.noteWifiOff(); 2156 } 2157 } catch (RemoteException e) { 2158 loge("Failed to note battery stats in wifi"); 2159 } 2160 2161 // Update state 2162 mWifiApState.set(wifiApState); 2163 2164 if (DBG) log("setWifiApState: " + syncGetWifiApStateByName()); 2165 2166 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 2167 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2168 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); 2169 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); 2170 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2171 } 2172 2173 private static final String ID_STR = "id="; 2174 private static final String BSSID_STR = "bssid="; 2175 private static final String FREQ_STR = "freq="; 2176 private static final String LEVEL_STR = "level="; 2177 private static final String TSF_STR = "tsf="; 2178 private static final String FLAGS_STR = "flags="; 2179 private static final String SSID_STR = "ssid="; 2180 private static final String DELIMITER_STR = "===="; 2181 private static final String END_STR = "####"; 2182 2183 /** 2184 * Format: 2185 * 2186 * id=1 2187 * bssid=68:7f:76:d7:1a:6e 2188 * freq=2412 2189 * level=-44 2190 * tsf=1344626243700342 2191 * flags=[WPA2-PSK-CCMP][WPS][ESS] 2192 * ssid=zfdy 2193 * ==== 2194 * id=2 2195 * bssid=68:5f:74:d7:1a:6f 2196 * freq=5180 2197 * level=-73 2198 * tsf=1344626243700373 2199 * flags=[WPA2-PSK-CCMP][WPS][ESS] 2200 * ssid=zuby 2201 * ==== 2202 */ 2203 private void setScanResults() { 2204 String bssid = ""; 2205 int level = 0; 2206 int freq = 0; 2207 long tsf = 0; 2208 String flags = ""; 2209 WifiSsid wifiSsid = null; 2210 String scanResults; 2211 String tmpResults; 2212 StringBuffer scanResultsBuf = new StringBuffer(); 2213 int sid = 0; 2214 2215 while (true) { 2216 tmpResults = mWifiNative.scanResults(sid); 2217 if (TextUtils.isEmpty(tmpResults)) break; 2218 scanResultsBuf.append(tmpResults); 2219 scanResultsBuf.append("\n"); 2220 String[] lines = tmpResults.split("\n"); 2221 sid = -1; 2222 for (int i=lines.length - 1; i >= 0; i--) { 2223 if (lines[i].startsWith(END_STR)) { 2224 break; 2225 } else if (lines[i].startsWith(ID_STR)) { 2226 try { 2227 sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1; 2228 } catch (NumberFormatException e) { 2229 // Nothing to do 2230 } 2231 break; 2232 } 2233 } 2234 if (sid == -1) break; 2235 } 2236 2237 scanResults = scanResultsBuf.toString(); 2238 if (TextUtils.isEmpty(scanResults)) { 2239 return; 2240 } 2241 2242 // note that all these splits and substrings keep references to the original 2243 // huge string buffer while the amount we really want is generally pretty small 2244 // so make copies instead (one example b/11087956 wasted 400k of heap here). 2245 synchronized(mScanResultCache) { 2246 mScanResults = new ArrayList<ScanResult>(); 2247 String[] lines = scanResults.split("\n"); 2248 final int bssidStrLen = BSSID_STR.length(); 2249 final int flagLen = FLAGS_STR.length(); 2250 2251 for (String line : lines) { 2252 if (line.startsWith(BSSID_STR)) { 2253 bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen); 2254 } else if (line.startsWith(FREQ_STR)) { 2255 try { 2256 freq = Integer.parseInt(line.substring(FREQ_STR.length())); 2257 } catch (NumberFormatException e) { 2258 freq = 0; 2259 } 2260 } else if (line.startsWith(LEVEL_STR)) { 2261 try { 2262 level = Integer.parseInt(line.substring(LEVEL_STR.length())); 2263 /* some implementations avoid negative values by adding 256 2264 * so we need to adjust for that here. 2265 */ 2266 if (level > 0) level -= 256; 2267 } catch(NumberFormatException e) { 2268 level = 0; 2269 } 2270 } else if (line.startsWith(TSF_STR)) { 2271 try { 2272 tsf = Long.parseLong(line.substring(TSF_STR.length())); 2273 } catch (NumberFormatException e) { 2274 tsf = 0; 2275 } 2276 } else if (line.startsWith(FLAGS_STR)) { 2277 flags = new String(line.getBytes(), flagLen, line.length() - flagLen); 2278 } else if (line.startsWith(SSID_STR)) { 2279 wifiSsid = WifiSsid.createFromAsciiEncoded( 2280 line.substring(SSID_STR.length())); 2281 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) { 2282 if (bssid != null) { 2283 String ssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 2284 String key = bssid + ssid; 2285 ScanResult scanResult = mScanResultCache.get(key); 2286 if (scanResult != null) { 2287 scanResult.level = level; 2288 scanResult.wifiSsid = wifiSsid; 2289 // Keep existing API 2290 scanResult.SSID = (wifiSsid != null) ? wifiSsid.toString() : 2291 WifiSsid.NONE; 2292 scanResult.capabilities = flags; 2293 scanResult.frequency = freq; 2294 scanResult.timestamp = tsf; 2295 } else { 2296 scanResult = 2297 new ScanResult( 2298 wifiSsid, bssid, flags, level, freq, tsf); 2299 mScanResultCache.put(key, scanResult); 2300 } 2301 mScanResults.add(scanResult); 2302 } 2303 bssid = null; 2304 level = 0; 2305 freq = 0; 2306 tsf = 0; 2307 flags = ""; 2308 wifiSsid = null; 2309 } 2310 } 2311 } 2312 if (mFrameworkAutoJoin.get() == true) 2313 mWifiAutoJoinController.newSupplicantResults(); 2314 2315 } 2316 2317 /* 2318 * Fetch RSSI, linkspeed, and frequency on current connection 2319 */ 2320 private void fetchRssiLinkSpeedAndFrequencyNative() { 2321 int newRssi = -1; 2322 int newLinkSpeed = -1; 2323 int newFrequency = -1; 2324 2325 String signalPoll = mWifiNative.signalPoll(); 2326 2327 if (signalPoll != null) { 2328 String[] lines = signalPoll.split("\n"); 2329 for (String line : lines) { 2330 String[] prop = line.split("="); 2331 if (prop.length < 2) continue; 2332 try { 2333 if (prop[0].equals("RSSI")) { 2334 newRssi = Integer.parseInt(prop[1]); 2335 } else if (prop[0].equals("LINKSPEED")) { 2336 newLinkSpeed = Integer.parseInt(prop[1]); 2337 } else if (prop[0].equals("FREQUENCY")) { 2338 newFrequency = Integer.parseInt(prop[1]); 2339 } 2340 } catch (NumberFormatException e) { 2341 //Ignore, defaults on rssi and linkspeed are assigned 2342 } 2343 } 2344 } 2345 2346 if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values 2347 /* some implementations avoid negative values by adding 256 2348 * so we need to adjust for that here. 2349 */ 2350 if (newRssi > 0) newRssi -= 256; 2351 mWifiInfo.setRssi(newRssi); 2352 /* 2353 * Rather then sending the raw RSSI out every time it 2354 * changes, we precalculate the signal level that would 2355 * be displayed in the status bar, and only send the 2356 * broadcast if that much more coarse-grained number 2357 * changes. This cuts down greatly on the number of 2358 * broadcasts, at the cost of not informing others 2359 * interested in RSSI of all the changes in signal 2360 * level. 2361 */ 2362 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); 2363 if (newSignalLevel != mLastSignalLevel) { 2364 sendRssiChangeBroadcast(newRssi); 2365 } 2366 mLastSignalLevel = newSignalLevel; 2367 } else { 2368 mWifiInfo.setRssi(MIN_RSSI); 2369 } 2370 2371 if (newLinkSpeed != -1) { 2372 mWifiInfo.setLinkSpeed(newLinkSpeed); 2373 } 2374 if (newFrequency > 0) { 2375 mWifiInfo.setFrequency(newFrequency); 2376 } 2377 } 2378 2379 /* 2380 * Fetch TX packet counters on current connection 2381 */ 2382 private void fetchPktcntNative(RssiPacketCountInfo info) { 2383 String pktcntPoll = mWifiNative.pktcntPoll(); 2384 2385 if (pktcntPoll != null) { 2386 String[] lines = pktcntPoll.split("\n"); 2387 for (String line : lines) { 2388 String[] prop = line.split("="); 2389 if (prop.length < 2) continue; 2390 try { 2391 if (prop[0].equals("TXGOOD")) { 2392 info.txgood = Integer.parseInt(prop[1]); 2393 } else if (prop[0].equals("TXBAD")) { 2394 info.txbad = Integer.parseInt(prop[1]); 2395 } 2396 } catch (NumberFormatException e) { 2397 //Ignore 2398 } 2399 } 2400 } 2401 } 2402 2403 /** 2404 * Updates mLinkProperties by merging information from various sources. 2405 * 2406 * This is needed because the information in mLinkProperties comes from multiple sources (DHCP, 2407 * netlink, static configuration, ...). When one of these sources of information has updated 2408 * link properties, we can't just assign them to mLinkProperties or we'd lose track of the 2409 * information that came from other sources. Instead, when one of those sources has new 2410 * information, we update the object that tracks the information from that source and then 2411 * call this method to apply the change to mLinkProperties. 2412 * 2413 * The information in mLinkProperties is currently obtained as follows: 2414 * - Interface name: set in the constructor. 2415 * - IPv4 and IPv6 addresses: netlink, via mInterfaceObserver. 2416 * - IPv4 routes, DNS servers, and domains: DHCP. 2417 * - HTTP proxy: the wifi config store. 2418 */ 2419 private void updateLinkProperties() { 2420 LinkProperties newLp = new LinkProperties(); 2421 2422 // Interface name and proxy are locally configured. 2423 newLp.setInterfaceName(mInterfaceName); 2424 newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); 2425 2426 // IPv4 and IPv6 addresses come from netlink. 2427 newLp.setLinkAddresses(mNetlinkLinkProperties.getLinkAddresses()); 2428 2429 // For now, routing and DNS only come from DHCP or static configuration. In the future, 2430 // we'll need to merge IPv6 DNS servers and domains coming from netlink. 2431 synchronized (mDhcpResultsLock) { 2432 // Even when we're using static configuration, we don't need to look at the config 2433 // store, because static IP configuration also populates mDhcpResults. 2434 if ((mDhcpResults != null) && (mDhcpResults.linkProperties != null)) { 2435 LinkProperties lp = mDhcpResults.linkProperties; 2436 for (RouteInfo route: lp.getRoutes()) { 2437 newLp.addRoute(route); 2438 } 2439 for (InetAddress dns: lp.getDnses()) { 2440 newLp.addDns(dns); 2441 } 2442 newLp.setDomains(lp.getDomains()); 2443 } 2444 } 2445 2446 // If anything has changed, and we're already connected, send out a notification. 2447 // If we're still connecting, apps will be notified when we connect. 2448 if (!newLp.equals(mLinkProperties)) { 2449 if (DBG) { 2450 log("Link configuration changed for netId: " + mLastNetworkId 2451 + " old: " + mLinkProperties + "new: " + newLp); 2452 } 2453 mLinkProperties = newLp; 2454 if (getNetworkDetailedState() == DetailedState.CONNECTED) { 2455 sendLinkConfigurationChangedBroadcast(); 2456 } 2457 } 2458 } 2459 /** 2460 * Clears all our link properties. 2461 */ 2462 private void clearLinkProperties() { 2463 // If the network used DHCP, clear the LinkProperties we stored in the config store. 2464 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 2465 mWifiConfigStore.clearLinkProperties(mLastNetworkId); 2466 } 2467 2468 // Clear the link properties obtained from DHCP and netlink. 2469 synchronized(mDhcpResultsLock) { 2470 if (mDhcpResults != null && mDhcpResults.linkProperties != null) { 2471 mDhcpResults.linkProperties.clear(); 2472 } 2473 } 2474 mNetlinkLinkProperties.clear(); 2475 2476 // Now clear the merged link properties. 2477 mLinkProperties.clear(); 2478 } 2479 2480 2481 /** 2482 * try to update default route MAC address. 2483 */ 2484 private String updateDefaultRouteMacAddress(int timeout) { 2485 String address = null; 2486 2487 for (RouteInfo route: mLinkProperties.getRoutes()) { 2488 if (route.isDefaultRoute() && route.hasGateway()) { 2489 InetAddress gateway = route.getGateway(); 2490 2491 if (gateway instanceof Inet4Address) { 2492 if (PDBG) { 2493 loge("updateDefaultRouteMacAddress found Ipv4 default :" 2494 + gateway.getHostAddress()); 2495 } 2496 address = macAddressFromRoute(gateway.getHostAddress()); 2497 /* the gateway's MAC address is known */ 2498 if ((address == null) && (timeout > 0)) { 2499 boolean reachable = false; 2500 try { 2501 reachable = gateway.isReachable(timeout); 2502 } catch (Exception e) { 2503 loge("updateDefaultRouteMacAddress exception reaching :" 2504 + gateway.getHostAddress()); 2505 2506 } finally { 2507 if (reachable == true) { 2508 2509 address = macAddressFromRoute(gateway.getHostAddress()); 2510 if(PDBG) { 2511 loge("updateDefaultRouteMacAddress reachable (tried again) :" 2512 + gateway.getHostAddress() + " found " + address); 2513 } 2514 } 2515 } 2516 } 2517 if (address != null) { 2518 mWifiConfigStore.setLinkProperties(mLastNetworkId, 2519 new LinkProperties(mLinkProperties)); 2520 mWifiConfigStore.setDefaultGwMacAddress(mLastNetworkId, address); 2521 2522 } 2523 } 2524 } 2525 } 2526 return address; 2527 } 2528 2529 private int getMaxDhcpRetries() { 2530 return Settings.Global.getInt(mContext.getContentResolver(), 2531 Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT, 2532 DEFAULT_MAX_DHCP_RETRIES); 2533 } 2534 2535 private void sendScanResultsAvailableBroadcast() { 2536 noteScanEnd(); 2537 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 2538 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2539 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2540 } 2541 2542 private void sendRssiChangeBroadcast(final int newRssi) { 2543 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); 2544 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2545 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); 2546 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2547 } 2548 2549 private void sendNetworkStateChangeBroadcast(String bssid) { 2550 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); 2551 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2552 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 2553 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties (mLinkProperties)); 2554 if (bssid != null) 2555 intent.putExtra(WifiManager.EXTRA_BSSID, bssid); 2556 if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK || 2557 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { 2558 intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo)); 2559 } 2560 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2561 } 2562 2563 private void sendLinkConfigurationChangedBroadcast() { 2564 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); 2565 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2566 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); 2567 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2568 } 2569 2570 private void sendSupplicantConnectionChangedBroadcast(boolean connected) { 2571 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 2572 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2573 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); 2574 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2575 } 2576 2577 /** 2578 * Record the detailed state of a network. 2579 * @param state the new {@code DetailedState} 2580 */ 2581 private void setNetworkDetailedState(NetworkInfo.DetailedState state) { 2582 if (DBG) { 2583 log("setDetailed state, old =" 2584 + mNetworkInfo.getDetailedState() + " and new state=" + state); 2585 } 2586 2587 if (state != mNetworkInfo.getDetailedState()) { 2588 mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); 2589 } 2590 } 2591 2592 private DetailedState getNetworkDetailedState() { 2593 return mNetworkInfo.getDetailedState(); 2594 } 2595 2596 2597 private SupplicantState handleSupplicantStateChange(Message message) { 2598 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 2599 SupplicantState state = stateChangeResult.state; 2600 // Supplicant state change 2601 // [31-13] Reserved for future use 2602 // [8 - 0] Supplicant state (as defined in SupplicantState.java) 2603 // 50023 supplicant_state_changed (custom|1|5) 2604 mWifiInfo.setSupplicantState(state); 2605 // Network id is only valid when we start connecting 2606 if (SupplicantState.isConnecting(state)) { 2607 mWifiInfo.setNetworkId(stateChangeResult.networkId); 2608 } else { 2609 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 2610 } 2611 2612 mWifiInfo.setBSSID(stateChangeResult.BSSID); 2613 mWifiInfo.setSSID(stateChangeResult.wifiSsid); 2614 2615 mSupplicantStateTracker.sendMessage(Message.obtain(message)); 2616 2617 return state; 2618 } 2619 2620 /** 2621 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 2622 * using the interface, stopping DHCP & disabling interface 2623 */ 2624 private void handleNetworkDisconnect() { 2625 if (DBG) log("Stopping DHCP and clearing IP"); 2626 2627 stopDhcp(); 2628 2629 try { 2630 mNwService.clearInterfaceAddresses(mInterfaceName); 2631 mNwService.disableIpv6(mInterfaceName); 2632 } catch (Exception e) { 2633 loge("Failed to clear addresses or disable ipv6" + e); 2634 } 2635 2636 /* Reset data structures */ 2637 // TODO: use a WifiInfo.reset(), although it would require moving the 2638 // MIN_RSSI to WifiInfo. 2639 mWifiInfo.setInetAddress(null); 2640 mWifiInfo.setBSSID(null); 2641 mWifiInfo.setSSID(null); 2642 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 2643 mWifiInfo.setRssi(MIN_RSSI); 2644 mWifiInfo.setLinkSpeed(-1); 2645 mWifiInfo.setFrequency(-1); 2646 mWifiInfo.setMeteredHint(false); 2647 2648 setNetworkDetailedState(DetailedState.DISCONNECTED); 2649 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 2650 2651 /* Clear network properties */ 2652 clearLinkProperties(); 2653 2654 /* send event to CM & network change broadcast */ 2655 sendNetworkStateChangeBroadcast(mLastBssid); 2656 2657 mLastBssid= null; 2658 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 2659 } 2660 2661 private void handleSupplicantConnectionLoss() { 2662 /* Socket connection can be lost when we do a graceful shutdown 2663 * or when the driver is hung. Ensure supplicant is stopped here. 2664 */ 2665 mWifiMonitor.killSupplicant(mP2pSupported); 2666 mWifiNative.closeSupplicantConnection(); 2667 sendSupplicantConnectionChangedBroadcast(false); 2668 setWifiState(WIFI_STATE_DISABLED); 2669 } 2670 2671 void handlePreDhcpSetup() { 2672 mDhcpActive = true; 2673 if (!mBluetoothConnectionActive) { 2674 /* 2675 * There are problems setting the Wi-Fi driver's power 2676 * mode to active when bluetooth coexistence mode is 2677 * enabled or sense. 2678 * <p> 2679 * We set Wi-Fi to active mode when 2680 * obtaining an IP address because we've found 2681 * compatibility issues with some routers with low power 2682 * mode. 2683 * <p> 2684 * In order for this active power mode to properly be set, 2685 * we disable coexistence mode until we're done with 2686 * obtaining an IP address. One exception is if we 2687 * are currently connected to a headset, since disabling 2688 * coexistence would interrupt that connection. 2689 */ 2690 // Disable the coexistence mode 2691 mWifiNative.setBluetoothCoexistenceMode( 2692 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); 2693 } 2694 2695 /* Disable power save and suspend optimizations during DHCP */ 2696 // Note: The order here is important for now. Brcm driver changes 2697 // power settings when we control suspend mode optimizations. 2698 // TODO: Remove this comment when the driver is fixed. 2699 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false); 2700 mWifiNative.setPowerSave(false); 2701 2702 stopBatchedScan(); 2703 2704 /* P2p discovery breaks dhcp, shut it down in order to get through this */ 2705 Message msg = new Message(); 2706 msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY; 2707 msg.arg1 = WifiP2pServiceImpl.ENABLED; 2708 msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE; 2709 msg.obj = mDhcpStateMachine; 2710 mWifiP2pChannel.sendMessage(msg); 2711 } 2712 2713 2714 void startDhcp() { 2715 if (mDhcpStateMachine == null) { 2716 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 2717 mContext, WifiStateMachine.this, mInterfaceName); 2718 2719 } 2720 mDhcpStateMachine.registerForPreDhcpNotification(); 2721 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); 2722 } 2723 2724 void stopDhcp() { 2725 if (mDhcpStateMachine != null) { 2726 /* In case we were in middle of DHCP operation restore back powermode */ 2727 handlePostDhcpSetup(); 2728 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); 2729 } 2730 } 2731 2732 void handlePostDhcpSetup() { 2733 /* Restore power save and suspend optimizations */ 2734 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true); 2735 mWifiNative.setPowerSave(true); 2736 2737 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED); 2738 2739 // Set the coexistence mode back to its default value 2740 mWifiNative.setBluetoothCoexistenceMode( 2741 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); 2742 2743 mDhcpActive = false; 2744 2745 startBatchedScan(); 2746 } 2747 2748 private void handleSuccessfulIpConfiguration(DhcpResults dhcpResults) { 2749 2750 if (PDBG) { 2751 loge("handleSuccessfulIpConfiguration <" + dhcpResults.toString() 2752 + "> linkaddress num " + dhcpResults.linkProperties.getLinkAddresses().size()); 2753 for (LinkAddress linkAddress : dhcpResults.linkProperties.getLinkAddresses()) { 2754 loge("link address " + linkAddress.toString()); 2755 } 2756 } 2757 2758 mLastSignalLevel = -1; // force update of signal strength 2759 mReconnectCount = 0; //Reset IP failure tracking 2760 synchronized (mDhcpResultsLock) { 2761 mDhcpResults = dhcpResults; 2762 } 2763 LinkProperties linkProperties = dhcpResults.linkProperties; 2764 mWifiConfigStore.setLinkProperties(mLastNetworkId, new LinkProperties(linkProperties)); 2765 InetAddress addr = null; 2766 Iterator<InetAddress> addrs = linkProperties.getAddresses().iterator(); 2767 if (addrs.hasNext()) { 2768 addr = addrs.next(); 2769 } 2770 mWifiInfo.setInetAddress(addr); 2771 mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint()); 2772 updateLinkProperties(); 2773 } 2774 2775 private void handleFailedIpConfiguration() { 2776 2777 mWifiInfo.setInetAddress(null); 2778 mWifiInfo.setMeteredHint(false); 2779 /** 2780 * If we've exceeded the maximum number of retries for DHCP 2781 * to a given network, disable the network 2782 */ 2783 int maxRetries = getMaxDhcpRetries(); 2784 // maxRetries == 0 means keep trying forever 2785 if (maxRetries > 0 && ++mReconnectCount > maxRetries) { 2786 loge("Failed " + 2787 mReconnectCount + " times, Disabling " + mLastNetworkId); 2788 mWifiConfigStore.disableNetwork(mLastNetworkId, 2789 WifiConfiguration.DISABLED_DHCP_FAILURE); 2790 mReconnectCount = 0; 2791 } 2792 2793 /* DHCP times out after about 30 seconds, we do a 2794 * disconnect and an immediate reconnect to try again 2795 */ 2796 mWifiNative.disconnect(); 2797 mWifiNative.reconnect(); 2798 } 2799 2800 /* Current design is to not set the config on a running hostapd but instead 2801 * stop and start tethering when user changes config on a running access point 2802 * 2803 * TODO: Add control channel setup through hostapd that allows changing config 2804 * on a running daemon 2805 */ 2806 private void startSoftApWithConfig(final WifiConfiguration config) { 2807 // start hostapd on a seperate thread 2808 new Thread(new Runnable() { 2809 public void run() { 2810 try { 2811 mNwService.startAccessPoint(config, mInterfaceName); 2812 } catch (Exception e) { 2813 loge("Exception in softap start " + e); 2814 try { 2815 mNwService.stopAccessPoint(mInterfaceName); 2816 mNwService.startAccessPoint(config, mInterfaceName); 2817 } catch (Exception e1) { 2818 loge("Exception in softap re-start " + e1); 2819 sendMessage(CMD_START_AP_FAILURE); 2820 return; 2821 } 2822 } 2823 if (DBG) log("Soft AP start successful"); 2824 sendMessage(CMD_START_AP_SUCCESS); 2825 } 2826 }).start(); 2827 } 2828 2829 2830 /* 2831 * Read a MAC address in /proc/arp/table, used by WifistateMachine 2832 * so as to record MAC address of default gateway. 2833 **/ 2834 private String macAddressFromRoute(String ipAddress) { 2835 String macAddress = null; 2836 BufferedReader reader = null; 2837 try { 2838 reader = new BufferedReader(new FileReader("/proc/net/arp")); 2839 2840 // Skip over the line bearing colum titles 2841 String line = reader.readLine(); 2842 2843 while ((line = reader.readLine()) != null) { 2844 String[] tokens = line.split("[ ]+"); 2845 if (tokens.length < 6) { 2846 continue; 2847 } 2848 2849 // ARP column format is 2850 // Address HWType HWAddress Flags Mask IFace 2851 String ip = tokens[0]; 2852 String mac = tokens[3]; 2853 2854 if (ipAddress.equals(ip)) { 2855 macAddress = mac; 2856 break; 2857 } 2858 } 2859 2860 if (macAddress == null) { 2861 loge("Did not find remoteAddress {" + ipAddress + "} in " + 2862 "/proc/net/arp"); 2863 } 2864 2865 } catch (FileNotFoundException e) { 2866 loge("Could not open /proc/net/arp to lookup mac address"); 2867 } catch (IOException e) { 2868 loge("Could not read /proc/net/arp to lookup mac address"); 2869 } finally { 2870 try { 2871 if (reader != null) { 2872 reader.close(); 2873 } 2874 } catch (IOException e) { 2875 // Do nothing 2876 } 2877 } 2878 return macAddress; 2879 2880 } 2881 /******************************************************** 2882 * HSM states 2883 *******************************************************/ 2884 2885 class DefaultState extends State { 2886 @Override 2887 public boolean processMessage(Message message) { 2888 logStateAndMessage(message, getClass().getSimpleName()); 2889 2890 switch (message.what) { 2891 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 2892 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 2893 mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 2894 } else { 2895 loge("WifiP2pService connection failure, error=" + message.arg1); 2896 } 2897 break; 2898 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 2899 loge("WifiP2pService channel lost, message.arg1 =" + message.arg1); 2900 //TODO: Re-establish connection to state machine after a delay 2901 //mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger()); 2902 break; 2903 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 2904 mBluetoothConnectionActive = (message.arg1 != 2905 BluetoothAdapter.STATE_DISCONNECTED); 2906 break; 2907 /* Synchronous call returns */ 2908 case CMD_PING_SUPPLICANT: 2909 case CMD_ENABLE_NETWORK: 2910 case CMD_ADD_OR_UPDATE_NETWORK: 2911 case CMD_REMOVE_NETWORK: 2912 case CMD_SAVE_CONFIG: 2913 replyToMessage(message, message.what, FAILURE); 2914 break; 2915 case CMD_GET_CAPABILITY_FREQ: 2916 replyToMessage(message, message.what, null); 2917 break; 2918 case CMD_GET_CONFIGURED_NETWORKS: 2919 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 2920 break; 2921 case CMD_ENABLE_RSSI_POLL: 2922 mEnableRssiPolling = (message.arg1 == 1); 2923 break; 2924 case CMD_ENABLE_BACKGROUND_SCAN: 2925 mEnableBackgroundScan = (message.arg1 == 1); 2926 break; 2927 case CMD_SET_HIGH_PERF_MODE: 2928 if (message.arg1 == 1) { 2929 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false); 2930 } else { 2931 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true); 2932 } 2933 break; 2934 case CMD_BOOT_COMPLETED: 2935 String countryCode = mPersistedCountryCode; 2936 if (TextUtils.isEmpty(countryCode) == false) { 2937 Settings.Global.putString(mContext.getContentResolver(), 2938 Settings.Global.WIFI_COUNTRY_CODE, 2939 countryCode); 2940 // it may be that the state transition that should send this info 2941 // to the driver happened between mPersistedCountryCode getting set 2942 // and now, so simply persisting it here would mean we have sent 2943 // nothing to the driver. Send the cmd so it might be set now. 2944 int sequenceNum = mCountryCodeSequence.incrementAndGet(); 2945 sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE, 2946 sequenceNum, 0, countryCode); 2947 } 2948 break; 2949 case CMD_SET_BATCHED_SCAN: 2950 recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj); 2951 break; 2952 case CMD_POLL_BATCHED_SCAN: 2953 handleBatchedScanPollRequest(); 2954 break; 2955 case CMD_START_NEXT_BATCHED_SCAN: 2956 startNextBatchedScan(); 2957 break; 2958 /* Discard */ 2959 case CMD_START_SCAN: 2960 case CMD_START_SUPPLICANT: 2961 case CMD_STOP_SUPPLICANT: 2962 case CMD_STOP_SUPPLICANT_FAILED: 2963 case CMD_START_DRIVER: 2964 case CMD_STOP_DRIVER: 2965 case CMD_DELAYED_STOP_DRIVER: 2966 case CMD_DRIVER_START_TIMED_OUT: 2967 case CMD_START_AP: 2968 case CMD_START_AP_SUCCESS: 2969 case CMD_START_AP_FAILURE: 2970 case CMD_STOP_AP: 2971 case CMD_TETHER_STATE_CHANGE: 2972 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 2973 case CMD_DISCONNECT: 2974 case CMD_RECONNECT: 2975 case CMD_REASSOCIATE: 2976 case CMD_RELOAD_TLS_AND_RECONNECT: 2977 case WifiMonitor.SUP_CONNECTION_EVENT: 2978 case WifiMonitor.SUP_DISCONNECTION_EVENT: 2979 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2980 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2981 case WifiMonitor.SCAN_RESULTS_EVENT: 2982 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2983 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 2984 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 2985 case WifiMonitor.WPS_OVERLAP_EVENT: 2986 case CMD_BLACKLIST_NETWORK: 2987 case CMD_CLEAR_BLACKLIST: 2988 case CMD_SET_OPERATIONAL_MODE: 2989 case CMD_SET_COUNTRY_CODE: 2990 case CMD_SET_FREQUENCY_BAND: 2991 case CMD_RSSI_POLL: 2992 case CMD_ENABLE_ALL_NETWORKS: 2993 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 2994 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 2995 /* Handled by WifiApConfigStore */ 2996 case CMD_SET_AP_CONFIG: 2997 case CMD_SET_AP_CONFIG_COMPLETED: 2998 case CMD_REQUEST_AP_CONFIG: 2999 case CMD_RESPONSE_AP_CONFIG: 3000 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 3001 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 3002 case CMD_NO_NETWORKS_PERIODIC_SCAN: 3003 case CMD_DISABLE_P2P_RSP: 3004 break; 3005 case DhcpStateMachine.CMD_ON_QUIT: 3006 mDhcpStateMachine = null; 3007 break; 3008 case CMD_SET_SUSPEND_OPT_ENABLED: 3009 if (message.arg1 == 1) { 3010 mSuspendWakeLock.release(); 3011 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true); 3012 } else { 3013 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false); 3014 } 3015 break; 3016 case WifiMonitor.DRIVER_HUNG_EVENT: 3017 setSupplicantRunning(false); 3018 setSupplicantRunning(true); 3019 break; 3020 case WifiManager.CONNECT_NETWORK: 3021 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 3022 WifiManager.BUSY); 3023 break; 3024 case WifiManager.FORGET_NETWORK: 3025 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 3026 WifiManager.BUSY); 3027 break; 3028 case WifiManager.SAVE_NETWORK: 3029 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 3030 WifiManager.BUSY); 3031 break; 3032 case WifiManager.START_WPS: 3033 replyToMessage(message, WifiManager.WPS_FAILED, 3034 WifiManager.BUSY); 3035 break; 3036 case WifiManager.CANCEL_WPS: 3037 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, 3038 WifiManager.BUSY); 3039 break; 3040 case WifiManager.DISABLE_NETWORK: 3041 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 3042 WifiManager.BUSY); 3043 break; 3044 case WifiManager.RSSI_PKTCNT_FETCH: 3045 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED, 3046 WifiManager.BUSY); 3047 break; 3048 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 3049 NetworkInfo info = (NetworkInfo) message.obj; 3050 mP2pConnected.set(info.isConnected()); 3051 break; 3052 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 3053 mTemporarilyDisconnectWifi = (message.arg1 == 1); 3054 replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 3055 break; 3056 case CMD_IP_ADDRESS_UPDATED: 3057 // addLinkAddress is a no-op if called more than once with the same address. 3058 if (mNetlinkLinkProperties.addLinkAddress((LinkAddress) message.obj)) { 3059 updateLinkProperties(); 3060 } 3061 break; 3062 case CMD_IP_ADDRESS_REMOVED: 3063 if (mNetlinkLinkProperties.removeLinkAddress((LinkAddress) message.obj)) { 3064 updateLinkProperties(); 3065 } 3066 break; 3067 default: 3068 loge("Error! unhandled message" + message); 3069 break; 3070 } 3071 return HANDLED; 3072 } 3073 } 3074 3075 class InitialState extends State { 3076 @Override 3077 public void enter() { 3078 mWifiNative.unloadDriver(); 3079 3080 if (mWifiP2pChannel == null) { 3081 mWifiP2pChannel = new AsyncChannel(); 3082 mWifiP2pChannel.connect(mContext, getHandler(), 3083 mWifiP2pServiceImpl.getP2pStateMachineMessenger()); 3084 } 3085 3086 if (mWifiApConfigChannel == null) { 3087 mWifiApConfigChannel = new AsyncChannel(); 3088 WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore( 3089 mContext, getHandler()); 3090 wifiApConfigStore.loadApConfiguration(); 3091 mWifiApConfigChannel.connectSync(mContext, getHandler(), 3092 wifiApConfigStore.getMessenger()); 3093 } 3094 } 3095 @Override 3096 public boolean processMessage(Message message) { 3097 logStateAndMessage(message, getClass().getSimpleName()); 3098 switch (message.what) { 3099 case CMD_START_SUPPLICANT: 3100 if (mWifiNative.loadDriver()) { 3101 try { 3102 mNwService.wifiFirmwareReload(mInterfaceName, "STA"); 3103 } catch (Exception e) { 3104 loge("Failed to reload STA firmware " + e); 3105 // continue 3106 } 3107 3108 try { 3109 // A runtime crash can leave the interface up and 3110 // this affects connectivity when supplicant starts up. 3111 // Ensure interface is down before a supplicant start. 3112 mNwService.setInterfaceDown(mInterfaceName); 3113 // Set privacy extensions 3114 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); 3115 3116 // IPv6 is enabled only as long as access point is connected since: 3117 // - IPv6 addresses and routes stick around after disconnection 3118 // - kernel is unaware when connected and fails to start IPv6 negotiation 3119 // - kernel can start autoconfiguration when 802.1x is not complete 3120 mNwService.disableIpv6(mInterfaceName); 3121 } catch (RemoteException re) { 3122 loge("Unable to change interface settings: " + re); 3123 } catch (IllegalStateException ie) { 3124 loge("Unable to change interface settings: " + ie); 3125 } 3126 3127 /* Stop a running supplicant after a runtime restart 3128 * Avoids issues with drivers that do not handle interface down 3129 * on a running supplicant properly. 3130 */ 3131 mWifiMonitor.killSupplicant(mP2pSupported); 3132 if(mWifiNative.startSupplicant(mP2pSupported)) { 3133 setWifiState(WIFI_STATE_ENABLING); 3134 if (DBG) log("Supplicant start successful"); 3135 mWifiMonitor.startMonitoring(); 3136 transitionTo(mSupplicantStartingState); 3137 } else { 3138 loge("Failed to start supplicant!"); 3139 } 3140 } else { 3141 loge("Failed to load driver"); 3142 } 3143 break; 3144 case CMD_START_AP: 3145 if (mWifiNative.loadDriver()) { 3146 setWifiApState(WIFI_AP_STATE_ENABLING); 3147 transitionTo(mSoftApStartingState); 3148 } else { 3149 loge("Failed to load driver for softap"); 3150 } 3151 default: 3152 return NOT_HANDLED; 3153 } 3154 return HANDLED; 3155 } 3156 } 3157 3158 class SupplicantStartingState extends State { 3159 private void initializeWpsDetails() { 3160 String detail; 3161 detail = SystemProperties.get("ro.product.name", ""); 3162 if (!mWifiNative.setDeviceName(detail)) { 3163 loge("Failed to set device name " + detail); 3164 } 3165 detail = SystemProperties.get("ro.product.manufacturer", ""); 3166 if (!mWifiNative.setManufacturer(detail)) { 3167 loge("Failed to set manufacturer " + detail); 3168 } 3169 detail = SystemProperties.get("ro.product.model", ""); 3170 if (!mWifiNative.setModelName(detail)) { 3171 loge("Failed to set model name " + detail); 3172 } 3173 detail = SystemProperties.get("ro.product.model", ""); 3174 if (!mWifiNative.setModelNumber(detail)) { 3175 loge("Failed to set model number " + detail); 3176 } 3177 detail = SystemProperties.get("ro.serialno", ""); 3178 if (!mWifiNative.setSerialNumber(detail)) { 3179 loge("Failed to set serial number " + detail); 3180 } 3181 if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) { 3182 loge("Failed to set WPS config methods"); 3183 } 3184 if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) { 3185 loge("Failed to set primary device type " + mPrimaryDeviceType); 3186 } 3187 } 3188 3189 @Override 3190 public boolean processMessage(Message message) { 3191 logStateAndMessage(message, getClass().getSimpleName()); 3192 3193 switch(message.what) { 3194 case WifiMonitor.SUP_CONNECTION_EVENT: 3195 if (DBG) log("Supplicant connection established"); 3196 setWifiState(WIFI_STATE_ENABLED); 3197 mSupplicantRestartCount = 0; 3198 /* Reset the supplicant state to indicate the supplicant 3199 * state is not known at this time */ 3200 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 3201 /* Initialize data structures */ 3202 mLastBssid = null; 3203 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 3204 mLastSignalLevel = -1; 3205 3206 mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); 3207 mWifiNative.enableSaveConfig(); 3208 mWifiConfigStore.loadAndEnableAllNetworks(); 3209 initializeWpsDetails(); 3210 3211 sendSupplicantConnectionChangedBroadcast(true); 3212 transitionTo(mDriverStartedState); 3213 break; 3214 case WifiMonitor.SUP_DISCONNECTION_EVENT: 3215 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { 3216 loge("Failed to setup control channel, restart supplicant"); 3217 mWifiMonitor.killSupplicant(mP2pSupported); 3218 transitionTo(mInitialState); 3219 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 3220 } else { 3221 loge("Failed " + mSupplicantRestartCount + 3222 " times to start supplicant, unload driver"); 3223 mSupplicantRestartCount = 0; 3224 setWifiState(WIFI_STATE_UNKNOWN); 3225 transitionTo(mInitialState); 3226 } 3227 break; 3228 case CMD_START_SUPPLICANT: 3229 case CMD_STOP_SUPPLICANT: 3230 case CMD_START_AP: 3231 case CMD_STOP_AP: 3232 case CMD_START_DRIVER: 3233 case CMD_STOP_DRIVER: 3234 case CMD_SET_OPERATIONAL_MODE: 3235 case CMD_SET_COUNTRY_CODE: 3236 case CMD_SET_FREQUENCY_BAND: 3237 case CMD_START_PACKET_FILTERING: 3238 case CMD_STOP_PACKET_FILTERING: 3239 deferMessage(message); 3240 break; 3241 default: 3242 return NOT_HANDLED; 3243 } 3244 return HANDLED; 3245 } 3246 } 3247 3248 class SupplicantStartedState extends State { 3249 @Override 3250 public void enter() { 3251 /* Wifi is available as long as we have a connection to supplicant */ 3252 mNetworkInfo.setIsAvailable(true); 3253 3254 int defaultInterval = mContext.getResources().getInteger( 3255 R.integer.config_wifi_supplicant_scan_interval); 3256 3257 mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 3258 Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, 3259 defaultInterval); 3260 3261 mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000); 3262 3263 if (mFrameworkAutoJoin.get()) { 3264 mWifiNative.enableAutoConnect(false); 3265 } 3266 3267 } 3268 @Override 3269 public boolean processMessage(Message message) { 3270 logStateAndMessage(message, getClass().getSimpleName()); 3271 3272 switch(message.what) { 3273 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ 3274 if (mP2pSupported) { 3275 transitionTo(mWaitForP2pDisableState); 3276 } else { 3277 transitionTo(mSupplicantStoppingState); 3278 } 3279 break; 3280 case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ 3281 loge("Connection lost, restart supplicant"); 3282 handleSupplicantConnectionLoss(); 3283 handleNetworkDisconnect(); 3284 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 3285 if (mP2pSupported) { 3286 transitionTo(mWaitForP2pDisableState); 3287 } else { 3288 transitionTo(mInitialState); 3289 } 3290 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 3291 break; 3292 case WifiMonitor.SCAN_RESULTS_EVENT: 3293 setScanResults(); 3294 sendScanResultsAvailableBroadcast(); 3295 mIsScanOngoing = false; 3296 mIsFullScanOngoing = false; 3297 if (mBufferedScanMsg.size() > 0) 3298 sendMessage(mBufferedScanMsg.remove()); 3299 break; 3300 case CMD_PING_SUPPLICANT: 3301 boolean ok = mWifiNative.ping(); 3302 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 3303 break; 3304 case CMD_GET_CAPABILITY_FREQ: 3305 String freqs = mWifiNative.getFreqCapability(); 3306 replyToMessage(message, message.what, freqs); 3307 break; 3308 case CMD_START_AP: 3309 /* Cannot start soft AP while in client mode */ 3310 loge("Failed to start soft AP with a running supplicant"); 3311 setWifiApState(WIFI_AP_STATE_FAILED); 3312 break; 3313 case CMD_SET_OPERATIONAL_MODE: 3314 mOperationalMode = message.arg1; 3315 break; 3316 default: 3317 return NOT_HANDLED; 3318 } 3319 return HANDLED; 3320 } 3321 3322 @Override 3323 public void exit() { 3324 mNetworkInfo.setIsAvailable(false); 3325 } 3326 } 3327 3328 class SupplicantStoppingState extends State { 3329 @Override 3330 public void enter() { 3331 /* Send any reset commands to supplicant before shutting it down */ 3332 handleNetworkDisconnect(); 3333 if (mDhcpStateMachine != null) { 3334 mDhcpStateMachine.doQuit(); 3335 } 3336 3337 if (DBG) log("stopping supplicant"); 3338 mWifiMonitor.stopSupplicant(); 3339 3340 /* Send ourselves a delayed message to indicate failure after a wait time */ 3341 sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED, 3342 ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS); 3343 setWifiState(WIFI_STATE_DISABLING); 3344 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 3345 } 3346 @Override 3347 public boolean processMessage(Message message) { 3348 logStateAndMessage(message, getClass().getSimpleName()); 3349 3350 switch(message.what) { 3351 case WifiMonitor.SUP_CONNECTION_EVENT: 3352 loge("Supplicant connection received while stopping"); 3353 break; 3354 case WifiMonitor.SUP_DISCONNECTION_EVENT: 3355 if (DBG) log("Supplicant connection lost"); 3356 handleSupplicantConnectionLoss(); 3357 transitionTo(mInitialState); 3358 break; 3359 case CMD_STOP_SUPPLICANT_FAILED: 3360 if (message.arg1 == mSupplicantStopFailureToken) { 3361 loge("Timed out on a supplicant stop, kill and proceed"); 3362 handleSupplicantConnectionLoss(); 3363 transitionTo(mInitialState); 3364 } 3365 break; 3366 case CMD_START_SUPPLICANT: 3367 case CMD_STOP_SUPPLICANT: 3368 case CMD_START_AP: 3369 case CMD_STOP_AP: 3370 case CMD_START_DRIVER: 3371 case CMD_STOP_DRIVER: 3372 case CMD_SET_OPERATIONAL_MODE: 3373 case CMD_SET_COUNTRY_CODE: 3374 case CMD_SET_FREQUENCY_BAND: 3375 case CMD_START_PACKET_FILTERING: 3376 case CMD_STOP_PACKET_FILTERING: 3377 deferMessage(message); 3378 break; 3379 default: 3380 return NOT_HANDLED; 3381 } 3382 return HANDLED; 3383 } 3384 } 3385 3386 class DriverStartingState extends State { 3387 private int mTries; 3388 @Override 3389 public void enter() { 3390 mTries = 1; 3391 /* Send ourselves a delayed message to start driver a second time */ 3392 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 3393 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 3394 } 3395 @Override 3396 public boolean processMessage(Message message) { 3397 logStateAndMessage(message, getClass().getSimpleName()); 3398 3399 switch(message.what) { 3400 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3401 SupplicantState state = handleSupplicantStateChange(message); 3402 /* If suplicant is exiting out of INTERFACE_DISABLED state into 3403 * a state that indicates driver has started, it is ready to 3404 * receive driver commands 3405 */ 3406 if (SupplicantState.isDriverActive(state)) { 3407 transitionTo(mDriverStartedState); 3408 } 3409 break; 3410 case CMD_DRIVER_START_TIMED_OUT: 3411 if (message.arg1 == mDriverStartToken) { 3412 if (mTries >= 2) { 3413 loge("Failed to start driver after " + mTries); 3414 transitionTo(mDriverStoppedState); 3415 } else { 3416 loge("Driver start failed, retrying"); 3417 mWakeLock.acquire(); 3418 mWifiNative.startDriver(); 3419 mWakeLock.release(); 3420 3421 ++mTries; 3422 /* Send ourselves a delayed message to start driver again */ 3423 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 3424 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 3425 } 3426 } 3427 break; 3428 /* Queue driver commands & connection events */ 3429 case CMD_START_DRIVER: 3430 case CMD_STOP_DRIVER: 3431 case WifiMonitor.NETWORK_CONNECTION_EVENT: 3432 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 3433 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 3434 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 3435 case WifiMonitor.WPS_OVERLAP_EVENT: 3436 case CMD_SET_COUNTRY_CODE: 3437 case CMD_SET_FREQUENCY_BAND: 3438 case CMD_START_PACKET_FILTERING: 3439 case CMD_STOP_PACKET_FILTERING: 3440 case CMD_START_SCAN: 3441 case CMD_DISCONNECT: 3442 case CMD_REASSOCIATE: 3443 case CMD_RECONNECT: 3444 deferMessage(message); 3445 break; 3446 default: 3447 return NOT_HANDLED; 3448 } 3449 return HANDLED; 3450 } 3451 } 3452 3453 class DriverStartedState extends State { 3454 @Override 3455 public void enter() { 3456 3457 if (PDBG) { 3458 loge("Driverstarted State enter"); 3459 } 3460 mIsRunning = true; 3461 mInDelayedStop = false; 3462 mDelayedStopCounter++; 3463 updateBatteryWorkSource(null); 3464 /** 3465 * Enable bluetooth coexistence scan mode when bluetooth connection is active. 3466 * When this mode is on, some of the low-level scan parameters used by the 3467 * driver are changed to reduce interference with bluetooth 3468 */ 3469 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 3470 /* set country code */ 3471 setCountryCode(); 3472 /* set frequency band of operation */ 3473 setFrequencyBand(); 3474 /* initialize network state */ 3475 setNetworkDetailedState(DetailedState.DISCONNECTED); 3476 3477 /* Remove any filtering on Multicast v6 at start */ 3478 mWifiNative.stopFilteringMulticastV6Packets(); 3479 3480 /* Reset Multicast v4 filtering state */ 3481 if (mFilteringMulticastV4Packets.get()) { 3482 mWifiNative.startFilteringMulticastV4Packets(); 3483 } else { 3484 mWifiNative.stopFilteringMulticastV4Packets(); 3485 } 3486 3487 mDhcpActive = false; 3488 3489 startBatchedScan(); 3490 3491 if (mOperationalMode != CONNECT_MODE) { 3492 mWifiNative.disconnect(); 3493 mWifiConfigStore.disableAllNetworks(); 3494 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 3495 setWifiState(WIFI_STATE_DISABLED); 3496 } 3497 transitionTo(mScanModeState); 3498 } else { 3499 /* Driver stop may have disabled networks, enable right after start */ 3500 mWifiConfigStore.enableAllNetworks(); 3501 3502 if (DBG) loge("Attempting to reconnect to wifi network .."); 3503 mWifiNative.reconnect(); 3504 3505 // Status pulls in the current supplicant state and network connection state 3506 // events over the monitor connection. This helps framework sync up with 3507 // current supplicant state 3508 mWifiNative.status(); 3509 transitionTo(mDisconnectedState); 3510 } 3511 3512 // We may have missed screen update at boot 3513 if (mScreenBroadcastReceived.get() == false) { 3514 PowerManager powerManager = (PowerManager)mContext.getSystemService( 3515 Context.POWER_SERVICE); 3516 handleScreenStateChanged(powerManager.isScreenOn()); 3517 } else { 3518 // Set the right suspend mode settings 3519 mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0 3520 && mUserWantsSuspendOpt.get()); 3521 } 3522 mWifiNative.setPowerSave(true); 3523 3524 if (mP2pSupported) { 3525 if (mOperationalMode == CONNECT_MODE) { 3526 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); 3527 } else { 3528 // P2P statemachine starts in disabled state, and is not enabled until 3529 // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to 3530 // keep it disabled. 3531 } 3532 } 3533 3534 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 3535 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3536 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED); 3537 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3538 3539 if (PDBG) { 3540 loge("Driverstarted State enter done"); 3541 } 3542 } 3543 3544 @Override 3545 public boolean processMessage(Message message) { 3546 logStateAndMessage(message, getClass().getSimpleName()); 3547 3548 switch(message.what) { 3549 case CMD_START_SCAN: 3550 if (mFrameworkAutoJoin.get()) { 3551 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 3552 } else { 3553 handleScanRequest(WifiNative.SCAN_WITH_CONNECTION_SETUP, message); 3554 } 3555 break; 3556 case CMD_SET_BATCHED_SCAN: 3557 if (recordBatchedScanSettings(message.arg1, message.arg2, 3558 (Bundle)message.obj)) { 3559 if (mBatchedScanSettings != null) { 3560 startBatchedScan(); 3561 } else { 3562 stopBatchedScan(); 3563 } 3564 } 3565 break; 3566 case CMD_SET_COUNTRY_CODE: 3567 String country = (String) message.obj; 3568 final boolean persist = (message.arg2 == 1); 3569 final int sequence = message.arg1; 3570 if (sequence != mCountryCodeSequence.get()) { 3571 if (DBG) log("set country code ignored due to sequnce num"); 3572 break; 3573 } 3574 if (DBG) log("set country code " + country); 3575 if (persist) { 3576 mPersistedCountryCode = country; 3577 Settings.Global.putString(mContext.getContentResolver(), 3578 Settings.Global.WIFI_COUNTRY_CODE, 3579 country); 3580 } 3581 country = country.toUpperCase(Locale.ROOT); 3582 if (mLastSetCountryCode == null 3583 || country.equals(mLastSetCountryCode) == false) { 3584 if (mWifiNative.setCountryCode(country)) { 3585 mLastSetCountryCode = country; 3586 } else { 3587 loge("Failed to set country code " + country); 3588 } 3589 } 3590 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.SET_COUNTRY_CODE, country); 3591 break; 3592 case CMD_SET_FREQUENCY_BAND: 3593 int band = message.arg1; 3594 if (DBG) log("set frequency band " + band); 3595 if (mWifiNative.setBand(band)) { 3596 3597 if (PDBG) loge("did set frequency band " + band); 3598 3599 mFrequencyBand.set(band); 3600 // flush old data - like scan results 3601 mWifiNative.bssFlush(); 3602 // fetch the latest scan results when frequency band is set 3603 if (mFrameworkAutoJoin.get()) 3604 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 3605 else 3606 startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP, null); 3607 if (PDBG) loge("done set frequency band " + band); 3608 3609 } else { 3610 loge("Failed to set frequency band " + band); 3611 } 3612 break; 3613 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 3614 mBluetoothConnectionActive = (message.arg1 != 3615 BluetoothAdapter.STATE_DISCONNECTED); 3616 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 3617 break; 3618 case CMD_STOP_DRIVER: 3619 int mode = message.arg1; 3620 3621 /* Already doing a delayed stop */ 3622 if (mInDelayedStop) { 3623 if (DBG) log("Already in delayed stop"); 3624 break; 3625 } 3626 /* disconnect right now, but leave the driver running for a bit */ 3627 mWifiConfigStore.disableAllNetworks(); 3628 3629 mInDelayedStop = true; 3630 mDelayedStopCounter++; 3631 if (DBG) log("Delayed stop message " + mDelayedStopCounter); 3632 3633 /* send regular delayed shut down */ 3634 Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); 3635 driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); 3636 mDriverStopIntent = PendingIntent.getBroadcast(mContext, 3637 DRIVER_STOP_REQUEST, driverStopIntent, 3638 PendingIntent.FLAG_UPDATE_CURRENT); 3639 3640 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 3641 + mDriverStopDelayMs, mDriverStopIntent); 3642 break; 3643 case CMD_START_DRIVER: 3644 if (mInDelayedStop) { 3645 mInDelayedStop = false; 3646 mDelayedStopCounter++; 3647 mAlarmManager.cancel(mDriverStopIntent); 3648 if (DBG) log("Delayed stop ignored due to start"); 3649 if (mOperationalMode == CONNECT_MODE) { 3650 mWifiConfigStore.enableAllNetworks(); 3651 } 3652 } 3653 break; 3654 case CMD_DELAYED_STOP_DRIVER: 3655 if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter); 3656 if (message.arg1 != mDelayedStopCounter) break; 3657 if (getCurrentState() != mDisconnectedState) { 3658 mWifiNative.disconnect(); 3659 handleNetworkDisconnect(); 3660 } 3661 mWakeLock.acquire(); 3662 mWifiNative.stopDriver(); 3663 mWakeLock.release(); 3664 if (mP2pSupported) { 3665 transitionTo(mWaitForP2pDisableState); 3666 } else { 3667 transitionTo(mDriverStoppingState); 3668 } 3669 break; 3670 case CMD_START_PACKET_FILTERING: 3671 if (message.arg1 == MULTICAST_V6) { 3672 mWifiNative.startFilteringMulticastV6Packets(); 3673 } else if (message.arg1 == MULTICAST_V4) { 3674 mWifiNative.startFilteringMulticastV4Packets(); 3675 } else { 3676 loge("Illegal arugments to CMD_START_PACKET_FILTERING"); 3677 } 3678 break; 3679 case CMD_STOP_PACKET_FILTERING: 3680 if (message.arg1 == MULTICAST_V6) { 3681 mWifiNative.stopFilteringMulticastV6Packets(); 3682 } else if (message.arg1 == MULTICAST_V4) { 3683 mWifiNative.stopFilteringMulticastV4Packets(); 3684 } else { 3685 loge("Illegal arugments to CMD_STOP_PACKET_FILTERING"); 3686 } 3687 break; 3688 case CMD_SET_SUSPEND_OPT_ENABLED: 3689 if (message.arg1 == 1) { 3690 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true); 3691 mSuspendWakeLock.release(); 3692 } else { 3693 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false); 3694 } 3695 break; 3696 case CMD_SET_HIGH_PERF_MODE: 3697 if (message.arg1 == 1) { 3698 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false); 3699 } else { 3700 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true); 3701 } 3702 break; 3703 case CMD_ENABLE_TDLS: 3704 if (message.obj != null) { 3705 String remoteAddress = (String) message.obj; 3706 boolean enable = (message.arg1 == 1); 3707 mWifiNative.startTdls(remoteAddress, enable); 3708 } 3709 break; 3710 default: 3711 return NOT_HANDLED; 3712 } 3713 return HANDLED; 3714 } 3715 @Override 3716 public void exit() { 3717 mIsRunning = false; 3718 updateBatteryWorkSource(null); 3719 mScanResults = new ArrayList<ScanResult>(); 3720 3721 stopBatchedScan(); 3722 3723 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 3724 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3725 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 3726 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3727 noteScanEnd(); // wrap up any pending request. 3728 mBufferedScanMsg.clear(); 3729 3730 mLastSetCountryCode = null; 3731 } 3732 } 3733 3734 class WaitForP2pDisableState extends State { 3735 private State mTransitionToState; 3736 @Override 3737 public void enter() { 3738 switch (getCurrentMessage().what) { 3739 case WifiMonitor.SUP_DISCONNECTION_EVENT: 3740 mTransitionToState = mInitialState; 3741 break; 3742 case CMD_DELAYED_STOP_DRIVER: 3743 mTransitionToState = mDriverStoppingState; 3744 break; 3745 case CMD_STOP_SUPPLICANT: 3746 mTransitionToState = mSupplicantStoppingState; 3747 break; 3748 default: 3749 mTransitionToState = mDriverStoppingState; 3750 break; 3751 } 3752 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ); 3753 } 3754 @Override 3755 public boolean processMessage(Message message) { 3756 logStateAndMessage(message, getClass().getSimpleName()); 3757 3758 switch(message.what) { 3759 case WifiStateMachine.CMD_DISABLE_P2P_RSP: 3760 transitionTo(mTransitionToState); 3761 break; 3762 /* Defer wifi start/shut and driver commands */ 3763 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3764 case CMD_START_SUPPLICANT: 3765 case CMD_STOP_SUPPLICANT: 3766 case CMD_START_AP: 3767 case CMD_STOP_AP: 3768 case CMD_START_DRIVER: 3769 case CMD_STOP_DRIVER: 3770 case CMD_SET_OPERATIONAL_MODE: 3771 case CMD_SET_COUNTRY_CODE: 3772 case CMD_SET_FREQUENCY_BAND: 3773 case CMD_START_PACKET_FILTERING: 3774 case CMD_STOP_PACKET_FILTERING: 3775 case CMD_START_SCAN: 3776 case CMD_DISCONNECT: 3777 case CMD_REASSOCIATE: 3778 case CMD_RECONNECT: 3779 deferMessage(message); 3780 break; 3781 default: 3782 return NOT_HANDLED; 3783 } 3784 return HANDLED; 3785 } 3786 } 3787 3788 class DriverStoppingState extends State { 3789 @Override 3790 public boolean processMessage(Message message) { 3791 logStateAndMessage(message, getClass().getSimpleName()); 3792 3793 switch(message.what) { 3794 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3795 SupplicantState state = handleSupplicantStateChange(message); 3796 if (state == SupplicantState.INTERFACE_DISABLED) { 3797 transitionTo(mDriverStoppedState); 3798 } 3799 break; 3800 /* Queue driver commands */ 3801 case CMD_START_DRIVER: 3802 case CMD_STOP_DRIVER: 3803 case CMD_SET_COUNTRY_CODE: 3804 case CMD_SET_FREQUENCY_BAND: 3805 case CMD_START_PACKET_FILTERING: 3806 case CMD_STOP_PACKET_FILTERING: 3807 case CMD_START_SCAN: 3808 case CMD_DISCONNECT: 3809 case CMD_REASSOCIATE: 3810 case CMD_RECONNECT: 3811 deferMessage(message); 3812 break; 3813 default: 3814 return NOT_HANDLED; 3815 } 3816 return HANDLED; 3817 } 3818 } 3819 3820 class DriverStoppedState extends State { 3821 @Override 3822 public boolean processMessage(Message message) { 3823 logStateAndMessage(message, getClass().getSimpleName()); 3824 switch (message.what) { 3825 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 3826 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 3827 SupplicantState state = stateChangeResult.state; 3828 // A WEXT bug means that we can be back to driver started state 3829 // unexpectedly 3830 if (SupplicantState.isDriverActive(state)) { 3831 transitionTo(mDriverStartedState); 3832 } 3833 break; 3834 case CMD_START_DRIVER: 3835 mWakeLock.acquire(); 3836 mWifiNative.startDriver(); 3837 mWakeLock.release(); 3838 transitionTo(mDriverStartingState); 3839 break; 3840 default: 3841 return NOT_HANDLED; 3842 } 3843 return HANDLED; 3844 } 3845 } 3846 3847 class ScanModeState extends State { 3848 private int mLastOperationMode; 3849 @Override 3850 public void enter() { 3851 mLastOperationMode = mOperationalMode; 3852 } 3853 @Override 3854 public boolean processMessage(Message message) { 3855 logStateAndMessage(message, getClass().getSimpleName()); 3856 3857 switch(message.what) { 3858 case CMD_SET_OPERATIONAL_MODE: 3859 if (message.arg1 == CONNECT_MODE) { 3860 3861 if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 3862 setWifiState(WIFI_STATE_ENABLED); 3863 // Load and re-enable networks when going back to enabled state 3864 // This is essential for networks to show up after restore 3865 mWifiConfigStore.loadAndEnableAllNetworks(); 3866 mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P); 3867 } else { 3868 mWifiConfigStore.enableAllNetworks(); 3869 } 3870 3871 mWifiNative.reconnect(); 3872 3873 mOperationalMode = CONNECT_MODE; 3874 transitionTo(mDisconnectedState); 3875 } else { 3876 // Nothing to do 3877 return HANDLED; 3878 } 3879 break; 3880 // Handle scan. All the connection related commands are 3881 // handled only in ConnectModeState 3882 case CMD_START_SCAN: 3883 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 3884 break; 3885 default: 3886 return NOT_HANDLED; 3887 } 3888 return HANDLED; 3889 } 3890 } 3891 3892 3893 String smToString(Message message) { 3894 String s = "unknown"; 3895 switch(message.what) { 3896 3897 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 3898 s = "AsyncChannel.CMD_CHANNEL_HALF_CONNECTED"; 3899 break; 3900 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 3901 s = "AsyncChannel.CMD_CHANNEL_DISCONNECTED"; 3902 break; 3903 case CMD_SET_FREQUENCY_BAND: 3904 s = "CMD_SET_FREQUENCY_BAND"; 3905 break; 3906 case CMD_START_DRIVER: 3907 s = "CMD_START_DRIVER"; 3908 break; 3909 case CMD_STOP_DRIVER: 3910 s = "CMD_STOP_DRIVER"; 3911 break; 3912 case CMD_STOP_SUPPLICANT: 3913 s = "CMD_STOP_SUPPLICANT"; 3914 break; 3915 case CMD_START_SUPPLICANT: 3916 s = "CMD_START_SUPPLICANT"; 3917 break; 3918 case CMD_REQUEST_AP_CONFIG: 3919 s = "CMD_REQUEST_AP_CONFIG"; 3920 break; 3921 case CMD_RESPONSE_AP_CONFIG: 3922 s = "CMD_RESPONSE_AP_CONFIG"; 3923 break; 3924 case CMD_TETHER_STATE_CHANGE: 3925 s = "CMD_TETHER_STATE_CHANGE"; 3926 break; 3927 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 3928 s = "CMD_TETHER_NOTIFICATION_TIMED_OUT"; 3929 break; 3930 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 3931 s = "CMD_BLUETOOTH_ADAPTER_STATE_CHANGE"; 3932 break; 3933 case CMD_ADD_OR_UPDATE_NETWORK: 3934 s= "CMD_ADD_OR_UPDATE_NETWORK"; 3935 break; 3936 case CMD_REMOVE_NETWORK: 3937 s= "CMD_REMOVE_NETWORK"; 3938 break; 3939 case CMD_ENABLE_NETWORK: 3940 s= "CMD_ENABLE_NETWORK"; 3941 break; 3942 case CMD_ENABLE_ALL_NETWORKS: 3943 s= "CMD_ENABLE_ALL_NETWORKS"; 3944 break; 3945 case CMD_AUTO_CONNECT: 3946 s = "CMD_AUTO_CONNECT"; 3947 break; 3948 case CMD_BOOT_COMPLETED: 3949 s = "CMD_BOOT_COMPLETED"; 3950 break; 3951 case DhcpStateMachine.CMD_START_DHCP: 3952 s = "DhcpStateMachine.CMD_START_DHCP"; 3953 break; 3954 case DhcpStateMachine.CMD_STOP_DHCP: 3955 s = "DhcpStateMachine.CMD_STOP_DHCP"; 3956 break; 3957 case DhcpStateMachine.CMD_RENEW_DHCP: 3958 s = "DhcpStateMachine.CMD_RENEW_DHCP"; 3959 break; 3960 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 3961 s = "DhcpStateMachine.CMD_PRE_DHCP_ACTION"; 3962 break; 3963 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 3964 s = "DhcpStateMachine.CMD_POST_DHCP_ACTION"; 3965 break; 3966 case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE: 3967 s = "DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE"; 3968 break; 3969 case DhcpStateMachine.CMD_ON_QUIT: 3970 s = "DhcpStateMachine.CMD_ON_QUIT"; 3971 break; 3972 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 3973 s = "WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST"; 3974 break; 3975 case WifiManager.DISABLE_NETWORK: 3976 s="WifiManager.DISABLE_NETWORK"; 3977 break; 3978 case CMD_BLACKLIST_NETWORK: 3979 s="CMD_BLACKLIST_NETWORK"; 3980 break; 3981 case CMD_CLEAR_BLACKLIST: 3982 s="CMD_CLEAR_BLACKLIST"; 3983 break; 3984 case CMD_SAVE_CONFIG: 3985 s="CMD_SAVE_CONFIG"; 3986 break; 3987 case CMD_GET_CONFIGURED_NETWORKS: 3988 s="CMD_GET_CONFIGURED_NETWORKS"; 3989 break; 3990 case CMD_DISCONNECT: 3991 s="CMD_DISCONNECT"; 3992 break; 3993 case CMD_RECONNECT: 3994 s= "CMD_RECONNECT"; 3995 break; 3996 case CMD_REASSOCIATE: 3997 s= "CMD_REASSOCIATE"; 3998 break; 3999 case CMD_SET_HIGH_PERF_MODE: 4000 s="CMD_SET_HIGH_PERF_MODE"; 4001 break; 4002 case CMD_SET_COUNTRY_CODE: 4003 s="CMD_SET_COUNTRY_CODE"; 4004 break; 4005 case CMD_ENABLE_RSSI_POLL: 4006 s="CMD_ENABLE_RSSI_POLL"; 4007 break; 4008 case CMD_RSSI_POLL: 4009 s="CMD_RSSI_POLL"; 4010 break; 4011 case CMD_START_PACKET_FILTERING: 4012 s="CMD_START_PACKET_FILTERING"; 4013 break; 4014 case CMD_STOP_PACKET_FILTERING: 4015 s="CMD_STOP_PACKET_FILTERING"; 4016 break; 4017 case CMD_SET_SUSPEND_OPT_ENABLED: 4018 s="CMD_SET_SUSPEND_OPT_ENABLED"; 4019 break; 4020 case CMD_NO_NETWORKS_PERIODIC_SCAN: 4021 s="CMD_NO_NETWORKS_PERIODIC_SCAN"; 4022 break; 4023 case CMD_SET_BATCHED_SCAN: 4024 s="CMD_SET_BATCHED_SCAN"; 4025 break; 4026 case CMD_START_NEXT_BATCHED_SCAN: 4027 s="CMD_START_NEXT_BATCHED_SCAN"; 4028 break; 4029 case CMD_POLL_BATCHED_SCAN: 4030 s="CMD_POLL_BATCHED_SCAN"; 4031 break; 4032 case CMD_IP_ADDRESS_UPDATED: 4033 s="CMD_IP_ADDRESS_UPDATED"; 4034 break; 4035 case CMD_IP_ADDRESS_REMOVED: 4036 s="CMD_IP_ADDRESS_REMOVED"; 4037 break; 4038 case CMD_RELOAD_TLS_AND_RECONNECT: 4039 s= "CMD_RELOAD_TLS_AND_RECONNECT"; 4040 break; 4041 case WifiManager.CONNECT_NETWORK: 4042 s= "WifiManager.CONNECT_NETWORK"; 4043 break; 4044 case WifiManager.SAVE_NETWORK: 4045 s= "WifiManager.SAVE_NETWORK"; 4046 break; 4047 case WifiManager.FORGET_NETWORK: 4048 s = "WifiManager.FORGET_NETWORK"; 4049 break; 4050 case WifiManager.START_WPS: 4051 s= "WifiManager.START_WPS"; 4052 break; 4053 case WifiMonitor.SUP_CONNECTION_EVENT: 4054 s= "WifiMonitor.SUP_CONNECTION_EVENT"; 4055 break; 4056 case WifiMonitor.SUP_DISCONNECTION_EVENT: 4057 s= "WifiMonitor.SUP_DISCONNECTION_EVENT"; 4058 break; 4059 case WifiMonitor.SCAN_RESULTS_EVENT: 4060 s= "WifiMonitor.SCAN_RESULTS_EVENT"; 4061 break; 4062 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4063 s= "WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT"; 4064 break; 4065 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 4066 s= "WifiMonitor.AUTHENTICATION_FAILURE_EVENT"; 4067 break; 4068 case WifiMonitor.WPS_SUCCESS_EVENT: 4069 s= "WPS_SUCCESS_EVENT"; 4070 break; 4071 case WifiMonitor.WPS_FAIL_EVENT: 4072 s= "WPS_FAIL_EVENT"; 4073 break; 4074 case WifiMonitor.NETWORK_CONNECTION_EVENT: 4075 s= "networkConnectionEvent"; 4076 break; 4077 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 4078 s="networkDisconnectionEvent"; 4079 break; 4080 case CMD_SET_OPERATIONAL_MODE: 4081 s="CMD_SET_OPERATIONAL_MODE"; 4082 break; 4083 case CMD_START_SCAN: 4084 s="CMD_START_SCAN"; 4085 break; 4086 case CMD_ENABLE_BACKGROUND_SCAN: 4087 s="CMD_ENABLE_BACKGROUND_SCAN"; 4088 break; 4089 } 4090 return s; 4091 } 4092 4093 WifiConfiguration getCurrentWifiConfiguration() { 4094 if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) { 4095 return null; 4096 } 4097 return mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 4098 } 4099 4100 class ConnectModeState extends State { 4101 @Override 4102 public boolean processMessage(Message message) { 4103 WifiConfiguration config; 4104 int netId; 4105 boolean ok; 4106 logStateAndMessage(message, getClass().getSimpleName()); 4107 4108 switch(message.what) { 4109 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 4110 mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT); 4111 break; 4112 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 4113 mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT); 4114 String substr = (String)message.obj; 4115 netId = -1; 4116 if (substr != null) { 4117 String status[] = substr.split(" "); 4118 for (String key : status) { 4119 if (key.regionMatches(0, "id=", 0, 3)) { 4120 int idx = 3; 4121 netId = 0; 4122 while (idx < key.length()) { 4123 char c = key.charAt(idx); 4124 if ((c >= 0x30) && (c <= 0x39)) { 4125 netId *= 10; 4126 netId += c - 0x30; 4127 idx++; 4128 } else { 4129 break; 4130 } 4131 } 4132 } 4133 } 4134 loge("ConnectModeState got auth failure nid=" 4135 + Integer.toString(netId) + " [" + substr + "]"); 4136 } else { 4137 loge("ConnectModeState got auth failure - unknown network"); 4138 } 4139 mWifiConfigStore.handleAuthenticationFailure(netId); 4140 break; 4141 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4142 SupplicantState state = handleSupplicantStateChange(message); 4143 // A driver/firmware hang can now put the interface in a down state. 4144 // We detect the interface going down and recover from it 4145 if (!SupplicantState.isDriverActive(state)) { 4146 if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 4147 handleNetworkDisconnect(); 4148 } 4149 log("Detected an interface down, restart driver"); 4150 transitionTo(mDriverStoppedState); 4151 sendMessage(CMD_START_DRIVER); 4152 break; 4153 } 4154 4155 // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT 4156 // when authentication times out after a successful connection, 4157 // we can figure this from the supplicant state. If supplicant 4158 // state is DISCONNECTED, but the mNetworkInfo says we are not 4159 // disconnected, we need to handle a disconnection 4160 if (state == SupplicantState.DISCONNECTED && 4161 mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 4162 if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect"); 4163 handleNetworkDisconnect(); 4164 transitionTo(mDisconnectedState); 4165 } 4166 break; 4167 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 4168 if (message.arg1 == 1) { 4169 mWifiNative.disconnect(); 4170 mTemporarilyDisconnectWifi = true; 4171 } else { 4172 mWifiNative.reconnect(); 4173 mTemporarilyDisconnectWifi = false; 4174 } 4175 break; 4176 case CMD_ADD_OR_UPDATE_NETWORK: 4177 config = (WifiConfiguration) message.obj; 4178 replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, 4179 mWifiConfigStore.addOrUpdateNetwork(config)); 4180 break; 4181 case CMD_REMOVE_NETWORK: 4182 ok = mWifiConfigStore.removeNetwork(message.arg1); 4183 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 4184 break; 4185 case CMD_ENABLE_NETWORK: 4186 ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); 4187 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 4188 break; 4189 case CMD_ENABLE_ALL_NETWORKS: 4190 long time = android.os.SystemClock.elapsedRealtime(); 4191 if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { 4192 mWifiConfigStore.enableAllNetworks(); 4193 mLastEnableAllNetworksTime = time; 4194 } 4195 break; 4196 case WifiManager.DISABLE_NETWORK: 4197 if (mWifiConfigStore.disableNetwork(message.arg1, 4198 WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) { 4199 replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); 4200 } else { 4201 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 4202 WifiManager.ERROR); 4203 } 4204 break; 4205 case CMD_BLACKLIST_NETWORK: 4206 mWifiNative.addToBlacklist((String)message.obj); 4207 break; 4208 case CMD_CLEAR_BLACKLIST: 4209 mWifiNative.clearBlacklist(); 4210 break; 4211 case CMD_SAVE_CONFIG: 4212 ok = mWifiConfigStore.saveConfig(); 4213 4214 loge("wifistatemachine did save config " + ok); 4215 replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); 4216 4217 // Inform the backup manager about a data change 4218 IBackupManager ibm = IBackupManager.Stub.asInterface( 4219 ServiceManager.getService(Context.BACKUP_SERVICE)); 4220 if (ibm != null) { 4221 try { 4222 ibm.dataChanged("com.android.providers.settings"); 4223 } catch (Exception e) { 4224 // Try again later 4225 } 4226 } 4227 break; 4228 case CMD_GET_CONFIGURED_NETWORKS: 4229 replyToMessage(message, message.what, 4230 mWifiConfigStore.getConfiguredNetworks()); 4231 break; 4232 /* Do a redundant disconnect without transition */ 4233 case CMD_DISCONNECT: 4234 mLastConnectAttempt = null; 4235 mWifiNative.disconnect(); 4236 break; 4237 case CMD_RECONNECT: 4238 mWifiNative.reconnect(); 4239 break; 4240 case CMD_REASSOCIATE: 4241 mWifiNative.reassociate(); 4242 break; 4243 case CMD_RELOAD_TLS_AND_RECONNECT: 4244 if (mWifiConfigStore.needsUnlockedKeyStore()) { 4245 logd("Reconnecting to give a chance to un-connected TLS networks"); 4246 mWifiNative.disconnect(); 4247 mWifiNative.reconnect(); 4248 } 4249 break; 4250 case CMD_AUTO_CONNECT: 4251 /* Work Around: wpa_supplicant can get in a bad state where it returns a non 4252 * associated status thus the STATUS command but somehow-someplace still thinks 4253 * it is associated and thus will ignore select/reconnect command with 4254 * following message: 4255 * "Already associated with the selected network - do nothing" 4256 * 4257 * Hence, sends a disconnect to supplicant first. 4258 */ 4259 mWifiNative.disconnect(); 4260 4261 /* connect command coming from auto-join */ 4262 config = (WifiConfiguration) message.obj; 4263 netId = message.arg1; 4264 4265 loge("CMD_AUTO_CONNECT sup state " + mSupplicantStateTracker.getSupplicantStateName() 4266 + " my state " + getCurrentState().getName() 4267 + " nid=" + Integer.toString(netId)); 4268 if (mLastConnectAttempt != null) { 4269 loge("CMD_AUTO_CONNECT last connect attempt " 4270 + mLastConnectAttempt.configKey()); 4271 } 4272 4273 /* Save the network config */ 4274 if (config != null) { 4275 loge("CMD_AUTO_CONNECT will save config -> " + config.SSID 4276 + " nid=" + Integer.toString(netId)); 4277 4278 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 4279 netId = result.getNetworkId(); 4280 loge("CMD_AUTO_CONNECT did save config -> " 4281 + " nid=" + Integer.toString(netId)); 4282 } 4283 4284 mLastConnectAttempt = mWifiConfigStore.getWifiConfiguration(netId); 4285 4286 if (mWifiConfigStore.selectNetwork(netId) && 4287 mWifiNative.reconnect()) { 4288 /* The state tracker handles enabling networks upon completion/failure */ 4289 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 4290 //replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 4291 /* Expect a disconnection from the old connection */ 4292 transitionTo(mDisconnectingState); 4293 } else { 4294 loge("Failed to connect config: " + config + " netId: " + netId); 4295 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 4296 WifiManager.ERROR); 4297 break; 4298 } 4299 break; 4300 case WifiManager.CONNECT_NETWORK: 4301 /* The connect message can contain a network id passed as arg1 on message or 4302 * or a config passed as obj on message. 4303 * For a new network, a config is passed to create and connect. 4304 * For an existing network, a network id is passed 4305 */ 4306 netId = message.arg1; 4307 config = (WifiConfiguration) message.obj; 4308 4309 if (config == null) { 4310 loge("CONNECT_NETWORK id=" + Integer.toString(netId) + " " 4311 + mSupplicantStateTracker.getSupplicantStateName() + " my state " 4312 + getCurrentState().getName()); 4313 } else { 4314 loge("CONNECT_NETWORK id=" + Integer.toString(netId) 4315 + " config=" + config.SSID 4316 + " cnid=" + config.networkId 4317 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 4318 + " my state " + getCurrentState().getName()); 4319 } 4320 4321 /* Save the network config */ 4322 if (config != null) { 4323 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 4324 netId = result.getNetworkId(); 4325 } 4326 4327 mLastConnectAttempt = mWifiConfigStore.getWifiConfiguration(netId); 4328 if (mWifiConfigStore.selectNetwork(netId) && 4329 mWifiNative.reconnect()) { 4330 mWifiAutoJoinController.updateSavedConfigurationsPriorities(netId); 4331 /* The state tracker handles enabling networks upon completion/failure */ 4332 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 4333 replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 4334 /* Expect a disconnection from the old connection */ 4335 transitionTo(mDisconnectingState); 4336 } else { 4337 loge("Failed to connect config: " + config + " netId: " + netId); 4338 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 4339 WifiManager.ERROR); 4340 break; 4341 } 4342 break; 4343 case WifiManager.SAVE_NETWORK: 4344 config = (WifiConfiguration) message.obj; 4345 int nid = config.networkId; 4346 if (config == null) { 4347 loge("SAVE_NETWORK id=" + Integer.toString(nid) 4348 + " " + mSupplicantStateTracker.getSupplicantStateName() 4349 + " my state " + getCurrentState().getName()); 4350 } else { 4351 loge("SAVE_NETWORK id=" + Integer.toString(nid) 4352 + " config=" + config.SSID 4353 + " cnid=" + config.networkId 4354 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 4355 + " my state " + getCurrentState().getName()); 4356 } 4357 4358 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 4359 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 4360 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 4361 if (mFrameworkAutoJoin.get()) { 4362 mWifiAutoJoinController.attemptAutoJoin(); 4363 mWifiConfigStore.writeKnownNetworkHistory(); 4364 } 4365 } else { 4366 loge("Failed to save network"); 4367 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 4368 WifiManager.ERROR); 4369 } 4370 break; 4371 case WifiManager.FORGET_NETWORK: 4372 if (mWifiConfigStore.forgetNetwork(message.arg1)) { 4373 replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); 4374 } else { 4375 loge("Failed to forget network"); 4376 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 4377 WifiManager.ERROR); 4378 } 4379 break; 4380 case WifiManager.START_WPS: 4381 WpsInfo wpsInfo = (WpsInfo) message.obj; 4382 WpsResult wpsResult; 4383 switch (wpsInfo.setup) { 4384 case WpsInfo.PBC: 4385 wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo); 4386 break; 4387 case WpsInfo.KEYPAD: 4388 wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); 4389 break; 4390 case WpsInfo.DISPLAY: 4391 wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); 4392 break; 4393 default: 4394 wpsResult = new WpsResult(Status.FAILURE); 4395 loge("Invalid setup for WPS"); 4396 break; 4397 } 4398 if (wpsResult.status == Status.SUCCESS) { 4399 replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult); 4400 transitionTo(mWpsRunningState); 4401 } else { 4402 loge("Failed to start WPS with config " + wpsInfo.toString()); 4403 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR); 4404 } 4405 break; 4406 case WifiMonitor.NETWORK_CONNECTION_EVENT: 4407 if (DBG) log("Network connection established"); 4408 mLastNetworkId = message.arg1; 4409 mLastBssid = (String) message.obj; 4410 4411 mWifiInfo.setBSSID(mLastBssid); 4412 mWifiInfo.setNetworkId(mLastNetworkId); 4413 /* send event to CM & network change broadcast */ 4414 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 4415 sendNetworkStateChangeBroadcast(mLastBssid); 4416 transitionTo(mObtainingIpState); 4417 break; 4418 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 4419 if (DBG) log("Network connection lost"); 4420 handleNetworkDisconnect(); 4421 transitionTo(mDisconnectedState); 4422 break; 4423 default: 4424 return NOT_HANDLED; 4425 } 4426 return HANDLED; 4427 } 4428 } 4429 4430 class L2ConnectedState extends State { 4431 @Override 4432 public void enter() { 4433 mRssiPollToken++; 4434 if (mEnableRssiPolling) { 4435 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0); 4436 } 4437 } 4438 4439 @Override 4440 public void exit() { 4441 handleNetworkDisconnect(); 4442 } 4443 4444 @Override 4445 public boolean processMessage(Message message) { 4446 logStateAndMessage(message, getClass().getSimpleName()); 4447 4448 switch (message.what) { 4449 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 4450 handlePreDhcpSetup(); 4451 break; 4452 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 4453 handlePostDhcpSetup(); 4454 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 4455 if (DBG) log("DHCP successful"); 4456 handleSuccessfulIpConfiguration((DhcpResults) message.obj); 4457 transitionTo(mVerifyingLinkState); 4458 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { 4459 if (DBG) log("DHCP failed"); 4460 handleFailedIpConfiguration(); 4461 transitionTo(mDisconnectingState); 4462 } 4463 break; 4464 case CMD_DISCONNECT: 4465 mWifiNative.disconnect(); 4466 transitionTo(mDisconnectingState); 4467 break; 4468 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 4469 if (message.arg1 == 1) { 4470 mWifiNative.disconnect(); 4471 mTemporarilyDisconnectWifi = true; 4472 transitionTo(mDisconnectingState); 4473 } 4474 break; 4475 case CMD_SET_OPERATIONAL_MODE: 4476 if (message.arg1 != CONNECT_MODE) { 4477 sendMessage(CMD_DISCONNECT); 4478 deferMessage(message); 4479 } 4480 break; 4481 case CMD_START_SCAN: 4482 /* Do not attempt to connect when we are already connected */ 4483 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 4484 break; 4485 /* Ignore connection to same network */ 4486 case WifiManager.CONNECT_NETWORK: 4487 int netId = message.arg1; 4488 if (mWifiInfo.getNetworkId() == netId) { 4489 break; 4490 } 4491 return NOT_HANDLED; 4492 case WifiManager.SAVE_NETWORK: 4493 WifiConfiguration config = (WifiConfiguration) message.obj; 4494 int nid = config.networkId; 4495 if (config == null) { 4496 loge("SAVE_NETWORK-L2 id=" + Integer.toString(nid) 4497 + " " + mSupplicantStateTracker.getSupplicantStateName() 4498 + " my state " + getCurrentState().getName()); 4499 } else { 4500 loge("SAVE_NETWORK-L2 id=" + Integer.toString(nid) 4501 + " SSID=" + config.SSID 4502 + " cnid=" + config.networkId 4503 + " autojoin=" + Integer.toString(config.autoJoinStatus) 4504 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 4505 + " my state " + getCurrentState().getName()); 4506 } 4507 4508 NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config); 4509 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 4510 if (result.hasIpChanged()) { 4511 log("Reconfiguring IP on connection"); 4512 transitionTo(mObtainingIpState); 4513 } 4514 if (result.hasProxyChanged()) { 4515 log("Reconfiguring proxy on connection"); 4516 updateLinkProperties(); 4517 } 4518 } 4519 4520 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 4521 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 4522 if (mFrameworkAutoJoin.get()) { 4523 mWifiConfigStore.writeKnownNetworkHistory(); 4524 } 4525 } else { 4526 loge("Failed to save network"); 4527 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 4528 WifiManager.ERROR); 4529 } 4530 break; 4531 /* Ignore */ 4532 case WifiMonitor.NETWORK_CONNECTION_EVENT: 4533 break; 4534 case CMD_RSSI_POLL: 4535 if (message.arg1 == mRssiPollToken) { 4536 // Get Info and continue polling 4537 fetchRssiLinkSpeedAndFrequencyNative(); 4538 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 4539 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 4540 } else { 4541 // Polling has completed 4542 } 4543 break; 4544 case CMD_ENABLE_RSSI_POLL: 4545 mEnableRssiPolling = (message.arg1 == 1); 4546 mRssiPollToken++; 4547 if (mEnableRssiPolling) { 4548 // first poll 4549 fetchRssiLinkSpeedAndFrequencyNative(); 4550 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 4551 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 4552 } 4553 break; 4554 case WifiManager.RSSI_PKTCNT_FETCH: 4555 RssiPacketCountInfo info = new RssiPacketCountInfo(); 4556 fetchRssiLinkSpeedAndFrequencyNative(); 4557 info.rssi = mWifiInfo.getRssi(); 4558 fetchPktcntNative(info); 4559 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info); 4560 break; 4561 default: 4562 return NOT_HANDLED; 4563 } 4564 4565 return HANDLED; 4566 } 4567 } 4568 4569 class ObtainingIpState extends State { 4570 @Override 4571 public void enter() { 4572 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 4573 // TODO: If we're switching between static IP configuration and DHCP, remove the 4574 // static configuration first. 4575 startDhcp(); 4576 } else { 4577 // stop any running dhcp before assigning static IP 4578 stopDhcp(); 4579 DhcpResults dhcpResults = new DhcpResults( 4580 mWifiConfigStore.getLinkProperties(mLastNetworkId)); 4581 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 4582 Iterator<LinkAddress> addrs = 4583 dhcpResults.linkProperties.getLinkAddresses().iterator(); 4584 if (!addrs.hasNext()) { 4585 loge("Static IP lacks address"); 4586 sendMessage(CMD_STATIC_IP_FAILURE); 4587 } else { 4588 ifcg.setLinkAddress(addrs.next()); 4589 ifcg.setInterfaceUp(); 4590 try { 4591 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 4592 if (DBG) log("Static IP configuration succeeded"); 4593 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults); 4594 } catch (RemoteException re) { 4595 loge("Static IP configuration failed: " + re); 4596 sendMessage(CMD_STATIC_IP_FAILURE); 4597 } catch (IllegalStateException e) { 4598 loge("Static IP configuration failed: " + e); 4599 sendMessage(CMD_STATIC_IP_FAILURE); 4600 } 4601 } 4602 } 4603 } 4604 @Override 4605 public boolean processMessage(Message message) { 4606 logStateAndMessage(message, getClass().getSimpleName()); 4607 4608 switch(message.what) { 4609 case CMD_STATIC_IP_SUCCESS: 4610 handleSuccessfulIpConfiguration((DhcpResults) message.obj); 4611 transitionTo(mVerifyingLinkState); 4612 break; 4613 case CMD_STATIC_IP_FAILURE: 4614 handleFailedIpConfiguration(); 4615 transitionTo(mDisconnectingState); 4616 break; 4617 case WifiManager.SAVE_NETWORK: 4618 deferMessage(message); 4619 break; 4620 /* Defer any power mode changes since we must keep active power mode at DHCP */ 4621 case CMD_SET_HIGH_PERF_MODE: 4622 deferMessage(message); 4623 break; 4624 /* Defer scan request since we should not switch to other channels at DHCP */ 4625 case CMD_START_SCAN: 4626 deferMessage(message); 4627 break; 4628 default: 4629 return NOT_HANDLED; 4630 } 4631 return HANDLED; 4632 } 4633 } 4634 4635 class VerifyingLinkState extends State { 4636 @Override 4637 public void enter() { 4638 log(getName() + " enter"); 4639 setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); 4640 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); 4641 sendNetworkStateChangeBroadcast(mLastBssid); 4642 } 4643 @Override 4644 public boolean processMessage(Message message) { 4645 logStateAndMessage(message, getClass().getSimpleName()); 4646 4647 switch (message.what) { 4648 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 4649 //stay here 4650 log(getName() + " POOR_LINK_DETECTED: no transition"); 4651 break; 4652 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 4653 log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); 4654 // Send out a broadcast with the CAPTIVE_PORTAL_CHECK to preserve 4655 // existing behaviour. The captive portal check really happens after we 4656 // transition into DetailedState.CONNECTED. 4657 setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); 4658 mWifiConfigStore.updateStatus(mLastNetworkId, 4659 DetailedState.CAPTIVE_PORTAL_CHECK); 4660 sendNetworkStateChangeBroadcast(mLastBssid); 4661 4662 // NOTE: This might look like an odd place to enable IPV6 but this is in 4663 // response to transitioning into GOOD_LINK_DETECTED. Similarly, we disable 4664 // ipv6 when we transition into POOR_LINK_DETECTED in mConnectedState. 4665 try { 4666 mNwService.enableIpv6(mInterfaceName); 4667 } catch (RemoteException re) { 4668 loge("Failed to enable IPv6: " + re); 4669 } catch (IllegalStateException e) { 4670 loge("Failed to enable IPv6: " + e); 4671 } 4672 4673 log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED"); 4674 setNetworkDetailedState(DetailedState.CONNECTED); 4675 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); 4676 sendNetworkStateChangeBroadcast(mLastBssid); 4677 transitionTo(mConnectedState); 4678 4679 break; 4680 default: 4681 if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); 4682 return NOT_HANDLED; 4683 } 4684 return HANDLED; 4685 } 4686 } 4687 4688 class ConnectedState extends State { 4689 @Override 4690 public void enter() { 4691 String address; 4692 updateDefaultRouteMacAddress(1000); 4693 if (DBG) { 4694 log("ConnectedState Enter autojoin=" + mFrameworkAutoJoin.get() 4695 + " mScreenOn=" + mScreenOn 4696 + " scanperiod=" + Integer.toString(mConnectedScanPeriodMs) ); 4697 } 4698 if (mFrameworkAutoJoin.get() && mScreenOn) { 4699 mCurrentScanAlarmMs = mConnectedScanPeriodMs; 4700 setScanAlarm(true); 4701 } else { 4702 mCurrentScanAlarmMs = 0; 4703 } 4704 } 4705 @Override 4706 public boolean processMessage(Message message) { 4707 logStateAndMessage(message, getClass().getSimpleName()); 4708 4709 switch (message.what) { 4710 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 4711 if (DBG) log("Watchdog reports poor link"); 4712 try { 4713 mNwService.disableIpv6(mInterfaceName); 4714 } catch (RemoteException re) { 4715 loge("Failed to disable IPv6: " + re); 4716 } catch (IllegalStateException e) { 4717 loge("Failed to disable IPv6: " + e); 4718 } 4719 /* Report a disconnect */ 4720 setNetworkDetailedState(DetailedState.DISCONNECTED); 4721 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 4722 sendNetworkStateChangeBroadcast(mLastBssid); 4723 4724 transitionTo(mVerifyingLinkState); 4725 break; 4726 default: 4727 return NOT_HANDLED; 4728 } 4729 return HANDLED; 4730 } 4731 4732 @Override 4733 public void exit() { 4734 loge("WifiStateMachine: Leaving Connected state"); 4735 setScanAlarm(false); 4736 4737 /* Request a CS wakelock during transition to mobile */ 4738 checkAndSetConnectivityInstance(); 4739 mCm.requestNetworkTransitionWakelock(getName()); 4740 } 4741 } 4742 4743 class DisconnectingState extends State { 4744 4745 @Override 4746 public void enter() { 4747 if (mFrameworkAutoJoin.get()) { 4748 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 4749 } else { 4750 4751 mCurrentScanAlarmMs = mFrameworkScanIntervalMs; 4752 } 4753 4754 if (PDBG) { 4755 loge(" Enter DisconnectingState State scan interval " + mFrameworkScanIntervalMs 4756 + " mEnableBackgroundScan= " + mEnableBackgroundScan 4757 + " screenOn=" + mScreenOn); 4758 } 4759 if (mScreenOn) 4760 setScanAlarm(true); 4761 } 4762 4763 @Override 4764 public boolean processMessage(Message message) { 4765 logStateAndMessage(message, getClass().getSimpleName()); 4766 switch (message.what) { 4767 case CMD_SET_OPERATIONAL_MODE: 4768 if (message.arg1 != CONNECT_MODE) { 4769 deferMessage(message); 4770 } 4771 break; 4772 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4773 /* If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT 4774 * we have missed the network disconnection, transition to mDisconnectedState 4775 * and handle the rest of the events there 4776 */ 4777 deferMessage(message); 4778 handleNetworkDisconnect(); 4779 transitionTo(mDisconnectedState); 4780 break; 4781 default: 4782 return NOT_HANDLED; 4783 } 4784 return HANDLED; 4785 } 4786 4787 @Override 4788 public void exit() { 4789 mCurrentScanAlarmMs = 0; 4790 } 4791 } 4792 4793 class DisconnectedState extends State { 4794 @Override 4795 public void enter() { 4796 // We dont scan frequently if this is a temporary disconnect 4797 // due to p2p 4798 if (mTemporarilyDisconnectWifi) { 4799 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 4800 return; 4801 } 4802 4803 mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 4804 Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS, 4805 mDefaultFrameworkScanIntervalMs); 4806 4807 if (mFrameworkAutoJoin.get()) { 4808 if (mScreenOn) 4809 mCurrentScanAlarmMs = mDisconnectedScanPeriodMs; 4810 } else { 4811 mCurrentScanAlarmMs = mFrameworkScanIntervalMs; 4812 } 4813 4814 if (PDBG) { 4815 loge(" Enter disconnected State scan interval " + mFrameworkScanIntervalMs 4816 + " mEnableBackgroundScan= " + mEnableBackgroundScan 4817 + " screenOn=" + mScreenOn); 4818 } 4819 4820 /* 4821 * mFrameworkAutoJoin is False: We initiate background scanning if it is enabled, 4822 * otherwise we initiate an infrequent scan that wakes up the device to ensure 4823 * a user connects to an access point on the move 4824 * 4825 * mFrameworkAutoJoin is True: 4826 * - screen dark and PNO supported => scan alarm disabled 4827 * - everything else => scan alarm enabled with mDefaultFrameworkScanIntervalMs period 4828 */ 4829 if ((mScreenOn == false) && mEnableBackgroundScan) { //mEnableBackgroundScan) { 4830 /* If a regular scan result is pending, do not initiate background 4831 * scan until the scan results are returned. This is needed because 4832 * initiating a background scan will cancel the regular scan and 4833 * scan results will not be returned until background scanning is 4834 * cleared 4835 */ 4836 if (!mIsScanOngoing) { 4837 mWifiNative.enableBackgroundScan(true); 4838 } 4839 } else { 4840 setScanAlarm(true); 4841 } 4842 4843 if (mFrameworkAutoJoin.get() && mScreenOn) { 4844 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 4845 } 4846 4847 /** 4848 * If we have no networks saved, the supplicant stops doing the periodic scan. 4849 * The scans are useful to notify the user of the presence of an open network. 4850 * Note that these are not wake up scans. 4851 */ 4852 if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) { 4853 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 4854 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 4855 } 4856 4857 mLastConnectAttempt = null; //make sure we don't accidentally disable the wrong network 4858 4859 } 4860 @Override 4861 public boolean processMessage(Message message) { 4862 boolean ret = HANDLED; 4863 4864 logStateAndMessage(message, getClass().getSimpleName()); 4865 4866 switch (message.what) { 4867 case CMD_NO_NETWORKS_PERIODIC_SCAN: 4868 if (mP2pConnected.get()) break; 4869 if (message.arg1 == mPeriodicScanToken && 4870 mWifiConfigStore.getConfiguredNetworks().size() == 0) { 4871 startScan(UNKNOWN_SCAN_SOURCE, null, null); 4872 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 4873 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 4874 } 4875 break; 4876 case WifiManager.FORGET_NETWORK: 4877 case CMD_REMOVE_NETWORK: 4878 // Set up a delayed message here. After the forget/remove is handled 4879 // the handled delayed message will determine if there is a need to 4880 // scan and continue 4881 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 4882 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 4883 ret = NOT_HANDLED; 4884 break; 4885 case CMD_SET_OPERATIONAL_MODE: 4886 if (message.arg1 != CONNECT_MODE) { 4887 mOperationalMode = message.arg1; 4888 4889 mWifiConfigStore.disableAllNetworks(); 4890 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 4891 mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); 4892 setWifiState(WIFI_STATE_DISABLED); 4893 } 4894 4895 transitionTo(mScanModeState); 4896 } 4897 break; 4898 case CMD_ENABLE_BACKGROUND_SCAN: 4899 mEnableBackgroundScan = (message.arg1 == 1); 4900 loge("enableBackgroundScanCommand enabled=" + mEnableBackgroundScan 4901 + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); 4902 4903 if (mEnableBackgroundScan) { 4904 mWifiNative.enableBackgroundScan(true); 4905 setScanAlarm(false); 4906 } else { 4907 if (mFrameworkAutoJoin.get()) { 4908 // tell supplicant to disconnect so as it doesnt start scanning 4909 // for connection upon disabling background scan 4910 mWifiNative.disconnect(); 4911 } 4912 mWifiNative.enableBackgroundScan(false); 4913 setScanAlarm(true); 4914 } 4915 break; 4916 /* Ignore network disconnect */ 4917 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 4918 break; 4919 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 4920 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 4921 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 4922 /* ConnectModeState does the rest of the handling */ 4923 ret = NOT_HANDLED; 4924 break; 4925 case CMD_START_SCAN: 4926 /* Disable background scan temporarily during a regular scan */ 4927 if (mEnableBackgroundScan) { 4928 mWifiNative.enableBackgroundScan(false); 4929 } 4930 /* Handled in parent state */ 4931 ret = NOT_HANDLED; 4932 break; 4933 case WifiMonitor.SCAN_RESULTS_EVENT: 4934 /* Re-enable background scan when a pending scan result is received */ 4935 if (mEnableBackgroundScan && mIsScanOngoing) { 4936 mWifiNative.enableBackgroundScan(true); 4937 } 4938 /* Handled in parent state */ 4939 ret = NOT_HANDLED; 4940 break; 4941 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 4942 NetworkInfo info = (NetworkInfo) message.obj; 4943 mP2pConnected.set(info.isConnected()); 4944 if (mP2pConnected.get()) { 4945 int defaultInterval = mContext.getResources().getInteger( 4946 R.integer.config_wifi_scan_interval_p2p_connected); 4947 long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 4948 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 4949 defaultInterval); 4950 mWifiNative.setScanInterval((int) scanIntervalMs/1000); 4951 } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { 4952 if (DBG) log("Turn on scanning after p2p disconnected"); 4953 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 4954 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 4955 } 4956 case CMD_RECONNECT: 4957 case CMD_REASSOCIATE: 4958 if (mTemporarilyDisconnectWifi) { 4959 // Drop a third party reconnect/reassociate if STA is 4960 // temporarily disconnected for p2p 4961 break; 4962 } else { 4963 // ConnectModeState handles it 4964 ret = NOT_HANDLED; 4965 } 4966 break; 4967 default: 4968 ret = NOT_HANDLED; 4969 } 4970 return ret; 4971 } 4972 4973 @Override 4974 public void exit() { 4975 /* No need for a background scan upon exit from a disconnected state */ 4976 if (mEnableBackgroundScan) { 4977 mWifiNative.enableBackgroundScan(false); 4978 } 4979 mCurrentScanAlarmMs = 0; 4980 setScanAlarm(false); 4981 } 4982 } 4983 4984 class WpsRunningState extends State { 4985 //Tracks the source to provide a reply 4986 private Message mSourceMessage; 4987 @Override 4988 public void enter() { 4989 mSourceMessage = Message.obtain(getCurrentMessage()); 4990 } 4991 @Override 4992 public boolean processMessage(Message message) { 4993 logStateAndMessage(message, getClass().getSimpleName()); 4994 4995 switch (message.what) { 4996 case WifiMonitor.WPS_SUCCESS_EVENT: 4997 // Ignore intermediate success, wait for full connection 4998 break; 4999 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5000 replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED); 5001 mSourceMessage.recycle(); 5002 mSourceMessage = null; 5003 deferMessage(message); 5004 transitionTo(mDisconnectedState); 5005 break; 5006 case WifiMonitor.WPS_OVERLAP_EVENT: 5007 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 5008 WifiManager.WPS_OVERLAP_ERROR); 5009 mSourceMessage.recycle(); 5010 mSourceMessage = null; 5011 transitionTo(mDisconnectedState); 5012 break; 5013 case WifiMonitor.WPS_FAIL_EVENT: 5014 //arg1 has the reason for the failure 5015 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1); 5016 mSourceMessage.recycle(); 5017 mSourceMessage = null; 5018 transitionTo(mDisconnectedState); 5019 break; 5020 case WifiMonitor.WPS_TIMEOUT_EVENT: 5021 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 5022 WifiManager.WPS_TIMED_OUT); 5023 mSourceMessage.recycle(); 5024 mSourceMessage = null; 5025 transitionTo(mDisconnectedState); 5026 break; 5027 case WifiManager.START_WPS: 5028 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS); 5029 break; 5030 case WifiManager.CANCEL_WPS: 5031 if (mWifiNative.cancelWps()) { 5032 replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED); 5033 } else { 5034 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR); 5035 } 5036 transitionTo(mDisconnectedState); 5037 break; 5038 /* Defer all commands that can cause connections to a different network 5039 * or put the state machine out of connect mode 5040 */ 5041 case CMD_STOP_DRIVER: 5042 case CMD_SET_OPERATIONAL_MODE: 5043 case WifiManager.CONNECT_NETWORK: 5044 case CMD_ENABLE_NETWORK: 5045 case CMD_RECONNECT: 5046 case CMD_REASSOCIATE: 5047 deferMessage(message); 5048 break; 5049 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 5050 if (DBG) log("Network connection lost"); 5051 handleNetworkDisconnect(); 5052 break; 5053 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 5054 if (DBG) log("Ignore Assoc reject event during WPS Connection"); 5055 break; 5056 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 5057 // Disregard auth failure events during WPS connection. The 5058 // EAP sequence is retried several times, and there might be 5059 // failures (especially for wps pin). We will get a WPS_XXX 5060 // event at the end of the sequence anyway. 5061 if (DBG) log("Ignore auth failure during WPS connection"); 5062 break; 5063 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5064 //Throw away supplicant state changes when WPS is running. 5065 //We will start getting supplicant state changes once we get 5066 //a WPS success or failure 5067 break; 5068 default: 5069 return NOT_HANDLED; 5070 } 5071 return HANDLED; 5072 } 5073 5074 @Override 5075 public void exit() { 5076 mWifiConfigStore.enableAllNetworks(); 5077 mWifiConfigStore.loadConfiguredNetworks(); 5078 } 5079 } 5080 5081 class SoftApStartingState extends State { 5082 @Override 5083 public void enter() { 5084 final Message message = getCurrentMessage(); 5085 if (message.what == CMD_START_AP) { 5086 final WifiConfiguration config = (WifiConfiguration) message.obj; 5087 5088 if (config == null) { 5089 mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); 5090 } else { 5091 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 5092 startSoftApWithConfig(config); 5093 } 5094 } else { 5095 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); 5096 } 5097 } 5098 @Override 5099 public boolean processMessage(Message message) { 5100 logStateAndMessage(message, getClass().getSimpleName()); 5101 5102 switch(message.what) { 5103 case CMD_START_SUPPLICANT: 5104 case CMD_STOP_SUPPLICANT: 5105 case CMD_START_AP: 5106 case CMD_STOP_AP: 5107 case CMD_START_DRIVER: 5108 case CMD_STOP_DRIVER: 5109 case CMD_SET_OPERATIONAL_MODE: 5110 case CMD_SET_COUNTRY_CODE: 5111 case CMD_SET_FREQUENCY_BAND: 5112 case CMD_START_PACKET_FILTERING: 5113 case CMD_STOP_PACKET_FILTERING: 5114 case CMD_TETHER_STATE_CHANGE: 5115 deferMessage(message); 5116 break; 5117 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: 5118 WifiConfiguration config = (WifiConfiguration) message.obj; 5119 if (config != null) { 5120 startSoftApWithConfig(config); 5121 } else { 5122 loge("Softap config is null!"); 5123 sendMessage(CMD_START_AP_FAILURE); 5124 } 5125 break; 5126 case CMD_START_AP_SUCCESS: 5127 setWifiApState(WIFI_AP_STATE_ENABLED); 5128 transitionTo(mSoftApStartedState); 5129 break; 5130 case CMD_START_AP_FAILURE: 5131 setWifiApState(WIFI_AP_STATE_FAILED); 5132 transitionTo(mInitialState); 5133 break; 5134 default: 5135 return NOT_HANDLED; 5136 } 5137 return HANDLED; 5138 } 5139 } 5140 5141 class SoftApStartedState extends State { 5142 @Override 5143 public boolean processMessage(Message message) { 5144 logStateAndMessage(message, getClass().getSimpleName()); 5145 5146 switch(message.what) { 5147 case CMD_STOP_AP: 5148 if (DBG) log("Stopping Soft AP"); 5149 /* We have not tethered at this point, so we just shutdown soft Ap */ 5150 try { 5151 mNwService.stopAccessPoint(mInterfaceName); 5152 } catch(Exception e) { 5153 loge("Exception in stopAccessPoint()"); 5154 } 5155 setWifiApState(WIFI_AP_STATE_DISABLED); 5156 transitionTo(mInitialState); 5157 break; 5158 case CMD_START_AP: 5159 // Ignore a start on a running access point 5160 break; 5161 /* Fail client mode operation when soft AP is enabled */ 5162 case CMD_START_SUPPLICANT: 5163 loge("Cannot start supplicant with a running soft AP"); 5164 setWifiState(WIFI_STATE_UNKNOWN); 5165 break; 5166 case CMD_TETHER_STATE_CHANGE: 5167 TetherStateChange stateChange = (TetherStateChange) message.obj; 5168 if (startTethering(stateChange.available)) { 5169 transitionTo(mTetheringState); 5170 } 5171 break; 5172 default: 5173 return NOT_HANDLED; 5174 } 5175 return HANDLED; 5176 } 5177 } 5178 5179 class TetheringState extends State { 5180 @Override 5181 public void enter() { 5182 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 5183 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 5184 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 5185 } 5186 @Override 5187 public boolean processMessage(Message message) { 5188 logStateAndMessage(message, getClass().getSimpleName()); 5189 5190 switch(message.what) { 5191 case CMD_TETHER_STATE_CHANGE: 5192 TetherStateChange stateChange = (TetherStateChange) message.obj; 5193 if (isWifiTethered(stateChange.active)) { 5194 transitionTo(mTetheredState); 5195 } 5196 return HANDLED; 5197 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 5198 if (message.arg1 == mTetherToken) { 5199 loge("Failed to get tether update, shutdown soft access point"); 5200 transitionTo(mSoftApStartedState); 5201 // Needs to be first thing handled 5202 sendMessageAtFrontOfQueue(CMD_STOP_AP); 5203 } 5204 break; 5205 case CMD_START_SUPPLICANT: 5206 case CMD_STOP_SUPPLICANT: 5207 case CMD_START_AP: 5208 case CMD_STOP_AP: 5209 case CMD_START_DRIVER: 5210 case CMD_STOP_DRIVER: 5211 case CMD_SET_OPERATIONAL_MODE: 5212 case CMD_SET_COUNTRY_CODE: 5213 case CMD_SET_FREQUENCY_BAND: 5214 case CMD_START_PACKET_FILTERING: 5215 case CMD_STOP_PACKET_FILTERING: 5216 deferMessage(message); 5217 break; 5218 default: 5219 return NOT_HANDLED; 5220 } 5221 return HANDLED; 5222 } 5223 } 5224 5225 class TetheredState extends State { 5226 @Override 5227 public boolean processMessage(Message message) { 5228 logStateAndMessage(message, getClass().getSimpleName()); 5229 5230 switch(message.what) { 5231 case CMD_TETHER_STATE_CHANGE: 5232 TetherStateChange stateChange = (TetherStateChange) message.obj; 5233 if (!isWifiTethered(stateChange.active)) { 5234 loge("Tethering reports wifi as untethered!, shut down soft Ap"); 5235 setHostApRunning(null, false); 5236 setHostApRunning(null, true); 5237 } 5238 return HANDLED; 5239 case CMD_STOP_AP: 5240 if (DBG) log("Untethering before stopping AP"); 5241 setWifiApState(WIFI_AP_STATE_DISABLING); 5242 stopTethering(); 5243 transitionTo(mUntetheringState); 5244 // More work to do after untethering 5245 deferMessage(message); 5246 break; 5247 default: 5248 return NOT_HANDLED; 5249 } 5250 return HANDLED; 5251 } 5252 } 5253 5254 class UntetheringState extends State { 5255 @Override 5256 public void enter() { 5257 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 5258 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 5259 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 5260 5261 } 5262 @Override 5263 public boolean processMessage(Message message) { 5264 logStateAndMessage(message, getClass().getSimpleName()); 5265 5266 switch(message.what) { 5267 case CMD_TETHER_STATE_CHANGE: 5268 TetherStateChange stateChange = (TetherStateChange) message.obj; 5269 5270 /* Wait till wifi is untethered */ 5271 if (isWifiTethered(stateChange.active)) break; 5272 5273 transitionTo(mSoftApStartedState); 5274 break; 5275 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 5276 if (message.arg1 == mTetherToken) { 5277 loge("Failed to get tether update, force stop access point"); 5278 transitionTo(mSoftApStartedState); 5279 } 5280 break; 5281 case CMD_START_SUPPLICANT: 5282 case CMD_STOP_SUPPLICANT: 5283 case CMD_START_AP: 5284 case CMD_STOP_AP: 5285 case CMD_START_DRIVER: 5286 case CMD_STOP_DRIVER: 5287 case CMD_SET_OPERATIONAL_MODE: 5288 case CMD_SET_COUNTRY_CODE: 5289 case CMD_SET_FREQUENCY_BAND: 5290 case CMD_START_PACKET_FILTERING: 5291 case CMD_STOP_PACKET_FILTERING: 5292 deferMessage(message); 5293 break; 5294 default: 5295 return NOT_HANDLED; 5296 } 5297 return HANDLED; 5298 } 5299 } 5300 5301 //State machine initiated requests can have replyTo set to null indicating 5302 //there are no recepients, we ignore those reply actions 5303 private void replyToMessage(Message msg, int what) { 5304 if (msg.replyTo == null) return; 5305 Message dstMsg = obtainMessageWithArg2(msg); 5306 dstMsg.what = what; 5307 mReplyChannel.replyToMessage(msg, dstMsg); 5308 } 5309 5310 private void replyToMessage(Message msg, int what, int arg1) { 5311 if (msg.replyTo == null) return; 5312 Message dstMsg = obtainMessageWithArg2(msg); 5313 dstMsg.what = what; 5314 dstMsg.arg1 = arg1; 5315 mReplyChannel.replyToMessage(msg, dstMsg); 5316 } 5317 5318 private void replyToMessage(Message msg, int what, Object obj) { 5319 if (msg.replyTo == null) return; 5320 Message dstMsg = obtainMessageWithArg2(msg); 5321 dstMsg.what = what; 5322 dstMsg.obj = obj; 5323 mReplyChannel.replyToMessage(msg, dstMsg); 5324 } 5325 5326 /** 5327 * arg2 on the source message has a unique id that needs to be retained in replies 5328 * to match the request 5329 5330 * see WifiManager for details 5331 */ 5332 private Message obtainMessageWithArg2(Message srcMsg) { 5333 Message msg = Message.obtain(); 5334 msg.arg2 = srcMsg.arg2; 5335 return msg; 5336 } 5337} 5338