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