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