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