WifiStateMachine.java revision dd490cf1df37b70a8625dc4ec8e712f740dd1e4a
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_AP_STATE_DISABLED; 20import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; 21import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; 22import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; 23import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; 24import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; 25import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; 26import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; 27import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; 28/** 29 * TODO: 30 * Deprecate WIFI_STATE_UNKNOWN 31 */ 32import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; 33 34import android.app.ActivityManager; 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.BaseDhcpStateMachine; 48import android.net.DhcpStateMachine; 49import android.net.dhcp.DhcpClient; 50import android.net.InterfaceConfiguration; 51import android.net.LinkAddress; 52import android.net.LinkProperties; 53import android.net.NetworkAgent; 54import android.net.NetworkCapabilities; 55import android.net.NetworkFactory; 56import android.net.NetworkInfo; 57import android.net.NetworkInfo.DetailedState; 58import android.net.NetworkRequest; 59import android.net.NetworkUtils; 60import android.net.RouteInfo; 61import android.net.StaticIpConfiguration; 62import android.net.TrafficStats; 63import android.net.wifi.BatchedScanResult; 64import android.net.wifi.BatchedScanSettings; 65import android.net.wifi.RssiPacketCountInfo; 66import android.net.wifi.ScanResult; 67import android.net.wifi.ScanSettings; 68import android.net.wifi.SupplicantState; 69import android.net.wifi.WifiChannel; 70import android.net.wifi.WifiConfiguration; 71import android.net.wifi.WifiConnectionStatistics; 72import android.net.wifi.WifiEnterpriseConfig; 73import android.net.wifi.WifiInfo; 74import android.net.wifi.WifiLinkLayerStats; 75import android.net.wifi.WifiManager; 76import android.net.wifi.WifiScanner; 77import android.net.wifi.WifiSsid; 78import android.net.wifi.WpsInfo; 79import android.net.wifi.WpsResult; 80import android.net.wifi.WpsResult.Status; 81import android.net.wifi.p2p.IWifiP2pManager; 82import android.net.wifi.IWifiScanner; 83import android.os.BatteryStats; 84import android.os.Bundle; 85import android.os.IBinder; 86import android.os.INetworkManagementService; 87import android.os.Looper; 88import android.os.Message; 89import android.os.Messenger; 90import android.os.PowerManager; 91import android.os.Process; 92import android.os.RemoteException; 93import android.os.ServiceManager; 94import android.os.SystemClock; 95import android.os.SystemProperties; 96import android.os.UserHandle; 97import android.os.WorkSource; 98import android.provider.Settings; 99import android.telephony.TelephonyManager; 100import android.text.TextUtils; 101import android.util.Log; 102import android.util.LruCache; 103 104import com.android.internal.R; 105import com.android.internal.app.IBatteryStats; 106import com.android.internal.util.AsyncChannel; 107import com.android.internal.util.Protocol; 108import com.android.internal.util.State; 109import com.android.internal.util.StateMachine; 110import com.android.server.net.NetlinkTracker; 111import com.android.server.wifi.hotspot2.NetworkDetail; 112import com.android.server.wifi.hotspot2.SupplicantBridge; 113import com.android.server.wifi.p2p.WifiP2pServiceImpl; 114 115import java.io.BufferedReader; 116import java.io.FileDescriptor; 117import java.io.FileNotFoundException; 118import java.io.FileReader; 119import java.io.IOException; 120import java.io.PrintWriter; 121import java.net.Inet4Address; 122import java.net.InetAddress; 123import java.net.SocketException; 124import java.nio.BufferUnderflowException; 125import java.util.ArrayList; 126import java.util.Calendar; 127import java.util.HashSet; 128import java.util.LinkedList; 129import java.util.List; 130import java.util.Locale; 131import java.util.Queue; 132import java.util.Random; 133import java.util.concurrent.atomic.AtomicBoolean; 134import java.util.concurrent.atomic.AtomicInteger; 135import java.util.regex.Matcher; 136import java.util.regex.Pattern; 137 138/** 139 * Track the state of Wifi connectivity. All event handling is done here, 140 * and all changes in connectivity state are initiated here. 141 * 142 * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p 143 * In the current implementation, we support concurrent wifi p2p and wifi operation. 144 * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService 145 * handles p2p operation. 146 * 147 * @hide 148 */ 149public class WifiStateMachine extends StateMachine implements WifiNative.WifiPnoEventHandler { 150 151 private static final String NETWORKTYPE = "WIFI"; 152 private static final String NETWORKTYPE_UNTRUSTED = "WIFI_UT"; 153 private static boolean DBG = true; 154 private static boolean VDBG = false; 155 private static boolean VVDBG = false; 156 private static boolean mLogMessages = false; 157 private static final String TAG = "WifiStateMachine"; 158 159 private static final int ONE_HOUR_MILLI = 1000 * 60 * 60; 160 161 private static final String GOOGLE_OUI = "DA-A1-19"; 162 163 /* temporary debug flag - best network selection development */ 164 private static boolean PDBG = true; 165 166 /* debug flag, indicating if handling of ASSOCIATION_REJECT ended up blacklisting 167 * the corresponding BSSID. 168 */ 169 private boolean didBlackListBSSID = false; 170 171 /** 172 * Log with error attribute 173 * 174 * @param s is string log 175 */ 176 protected void loge(String s) { 177 Log.e(getName(), s); 178 } 179 protected void log(String s) { 180 Log.e(getName(), s); 181 } 182 183 private WifiMonitor mWifiMonitor; 184 private WifiNative mWifiNative; 185 private WifiConfigStore mWifiConfigStore; 186 private WifiAutoJoinController mWifiAutoJoinController; 187 private INetworkManagementService mNwService; 188 private ConnectivityManager mCm; 189 private WifiLogger mWifiLogger; 190 191 private final boolean mP2pSupported; 192 private final AtomicBoolean mP2pConnected = new AtomicBoolean(false); 193 private boolean mTemporarilyDisconnectWifi = false; 194 private final String mPrimaryDeviceType; 195 196 /* Scan results handling */ 197 private List<ScanDetail> mScanResults = new ArrayList<>(); 198 private static final Pattern scanResultPattern = Pattern.compile("\t+"); 199 private static final int SCAN_RESULT_CACHE_SIZE = 160; 200 private final LruCache<NetworkDetail, ScanDetail> mScanResultCache; 201 // For debug, number of known scan results that were found as part of last scan result event, 202 // as well the number of scans results returned by the supplicant with that message 203 private int mNumScanResultsKnown; 204 private int mNumScanResultsReturned; 205 206 /* Batch scan results */ 207 private final List<BatchedScanResult> mBatchedScanResults = 208 new ArrayList<BatchedScanResult>(); 209 private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE; 210 private int mExpectedBatchedScans = 0; 211 private long mBatchedScanMinPollTime = 0; 212 213 private boolean mScreenOn = false; 214 215 /* Chipset supports background scan */ 216 private final boolean mBackgroundScanSupported; 217 218 private String mInterfaceName; 219 /* Tethering interface could be separate from wlan interface */ 220 private String mTetherInterfaceName; 221 222 private int mLastSignalLevel = -1; 223 private String mLastBssid; 224 private int mLastNetworkId; // The network Id we successfully joined 225 private boolean linkDebouncing = false; 226 227 private boolean mAlwaysOnPnoSupported = false; 228 private int mHalFeatureSet = 0; 229 private static int mPnoResultFound = 0; 230 231 @Override 232 public void onPnoNetworkFound(ScanResult results[]) { 233 if (DBG) { 234 Log.e(TAG, "onPnoNetworkFound event received num = " + results.length); 235 for (int i = 0; i < results.length; i++) { 236 Log.e(TAG, results[i].toString()); 237 } 238 } 239 sendMessage(CMD_PNO_NETWORK_FOUND, results.length, 0, results); 240 } 241 242 public void processPnoNetworkFound(ScanResult results[]) { 243 ScanSettings settings = new ScanSettings(); 244 settings.channelSet = new ArrayList<WifiChannel>(); 245 246 for (int i=0; i<results.length; i++) { 247 WifiChannel channel = new WifiChannel(); 248 channel.freqMHz = results[i].frequency; 249 settings.channelSet.add(channel); 250 } 251 252 stopPno(); 253 254 Log.e(TAG, "processPnoNetworkFound starting scan cnt=" + mPnoResultFound); 255 startScan(PNO_NETWORK_FOUND_SOURCE, mPnoResultFound, settings, null); 256 mPnoResultFound ++; 257 //sendMessage(CMD_SCAN_RESULTS_AVAILABLE); 258 259 // restart Pno after 30ms 260 sendMessageDelayed(CMD_START_PNO, 30 * 1000); 261 } 262 263 // Testing various network disconnect cases by sending lots of spurious 264 // disconnect to supplicant 265 private boolean testNetworkDisconnect = false; 266 267 private boolean mEnableRssiPolling = false; 268 private boolean mEnableBackgroundScan = false; 269 private int mRssiPollToken = 0; 270 /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE 271 * In CONNECT_MODE, the STA can scan and connect to an access point 272 * In SCAN_ONLY_MODE, the STA can only scan for access points 273 * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off 274 */ 275 private int mOperationalMode = CONNECT_MODE; 276 private boolean mIsScanOngoing = false; 277 private boolean mIsFullScanOngoing = false; 278 private boolean mSendScanResultsBroadcast = false; 279 280 private final Queue<Message> mBufferedScanMsg = new LinkedList<Message>(); 281 private WorkSource mScanWorkSource = null; 282 private static final int UNKNOWN_SCAN_SOURCE = -1; 283 private static final int SCAN_ALARM_SOURCE = -2; 284 private static final int ADD_OR_UPDATE_SOURCE = -3; 285 private static final int SET_ALLOW_UNTRUSTED_SOURCE = -4; 286 private static final int ENABLE_WIFI = -5; 287 public static final int DFS_RESTRICTED_SCAN_REQUEST = -6; 288 public static final int PNO_NETWORK_FOUND_SOURCE = -7; 289 290 private static final int SCAN_REQUEST_BUFFER_MAX_SIZE = 10; 291 private static final String CUSTOMIZED_SCAN_SETTING = "customized_scan_settings"; 292 private static final String CUSTOMIZED_SCAN_WORKSOURCE = "customized_scan_worksource"; 293 private static final String SCAN_REQUEST_TIME = "scan_request_time"; 294 295 private static final String BATCHED_SETTING = "batched_settings"; 296 private static final String BATCHED_WORKSOURCE = "batched_worksource"; 297 298 /* Tracks if state machine has received any screen state change broadcast yet. 299 * We can miss one of these at boot. 300 */ 301 private AtomicBoolean mScreenBroadcastReceived = new AtomicBoolean(false); 302 303 private boolean mBluetoothConnectionActive = false; 304 305 private PowerManager.WakeLock mSuspendWakeLock; 306 307 /** 308 * Interval in milliseconds between polling for RSSI 309 * and linkspeed information 310 */ 311 private static final int POLL_RSSI_INTERVAL_MSECS = 3000; 312 313 /** 314 * Interval in milliseconds between receiving a disconnect event 315 * while connected to a good AP, and handling the disconnect proper 316 */ 317 private static final int LINK_FLAPPING_DEBOUNCE_MSEC = 7000; 318 319 /** 320 * Delay between supplicant restarts upon failure to establish connection 321 */ 322 private static final int SUPPLICANT_RESTART_INTERVAL_MSECS = 5000; 323 324 /** 325 * Number of times we attempt to restart supplicant 326 */ 327 private static final int SUPPLICANT_RESTART_TRIES = 5; 328 329 private int mSupplicantRestartCount = 0; 330 /* Tracks sequence number on stop failure message */ 331 private int mSupplicantStopFailureToken = 0; 332 333 /** 334 * Tether state change notification time out 335 */ 336 private static final int TETHER_NOTIFICATION_TIME_OUT_MSECS = 5000; 337 338 /* Tracks sequence number on a tether notification time out */ 339 private int mTetherToken = 0; 340 341 /** 342 * Driver start time out. 343 */ 344 private static final int DRIVER_START_TIME_OUT_MSECS = 10000; 345 346 /* Tracks sequence number on a driver time out */ 347 private int mDriverStartToken = 0; 348 349 /** 350 * The link properties of the wifi interface. 351 * Do not modify this directly; use updateLinkProperties instead. 352 */ 353 private LinkProperties mLinkProperties; 354 355 /* Tracks sequence number on a periodic scan message */ 356 private int mPeriodicScanToken = 0; 357 358 // Wakelock held during wifi start/stop and driver load/unload 359 private PowerManager.WakeLock mWakeLock; 360 361 private Context mContext; 362 363 private final Object mDhcpResultsLock = new Object(); 364 private DhcpResults mDhcpResults; 365 private WifiInfo mWifiInfo; 366 private NetworkInfo mNetworkInfo; 367 private NetworkCapabilities mNetworkCapabilities; 368 private SupplicantStateTracker mSupplicantStateTracker; 369 private BaseDhcpStateMachine mDhcpStateMachine; 370 private boolean mDhcpActive = false; 371 372 private int mWifiLinkLayerStatsSupported = 4; // Temporary disable 373 374 private final AtomicInteger mCountryCodeSequence = new AtomicInteger(); 375 376 // Whether the state machine goes thru the Disconnecting->Disconnected->ObtainingIpAddress 377 private int mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 378 379 // Roaming failure count 380 private int mRoamFailCount = 0; 381 382 // This is the BSSID we are trying to associate to, it can be set to "any" 383 // if we havent selected a BSSID for joining. 384 // if we havent selected a BSSID for joining. 385 // The BSSID we are associated to is found in mWifiInfo 386 private String mTargetRoamBSSID = "any"; 387 388 private long mLastDriverRoamAttempt = 0; 389 390 private WifiConfiguration targetWificonfiguration = null; 391 392 // Used as debug to indicate which configuration last was saved 393 private WifiConfiguration lastSavedConfigurationAttempt = null; 394 395 // Used as debug to indicate which configuration last was removed 396 private WifiConfiguration lastForgetConfigurationAttempt = null; 397 398 //Random used by softAP channel Selection 399 private static Random mRandom = new Random(Calendar.getInstance().getTimeInMillis()); 400 401 boolean isRoaming() { 402 return mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_ROAMING 403 || mAutoRoaming == WifiAutoJoinController.AUTO_JOIN_EXTENDED_ROAMING; 404 } 405 406 public void autoRoamSetBSSID(int netId, String bssid) { 407 autoRoamSetBSSID(mWifiConfigStore.getWifiConfiguration(netId), bssid); 408 } 409 410 public boolean autoRoamSetBSSID(WifiConfiguration config, String bssid) { 411 boolean ret = true; 412 if (mTargetRoamBSSID == null) mTargetRoamBSSID = "any"; 413 if (bssid == null) bssid = "any"; 414 if (config == null) return false; // Nothing to do 415 416 if (mTargetRoamBSSID != null && bssid == mTargetRoamBSSID && bssid == config.BSSID) { 417 return false; // We didnt change anything 418 } 419 if (!mTargetRoamBSSID.equals("any") && bssid.equals("any")) { 420 // Changing to ANY 421 if (!mWifiConfigStore.roamOnAny) { 422 ret = false; // Nothing to do 423 } 424 } 425 if (VDBG) { 426 loge("autoRoamSetBSSID " + bssid 427 + " key=" + config.configKey()); 428 } 429 config.autoJoinBSSID = bssid; 430 mTargetRoamBSSID = bssid; 431 mWifiConfigStore.saveWifiConfigBSSID(config); 432 return ret; 433 } 434 435 /** 436 * Subset of link properties coming from netlink. 437 * Currently includes IPv4 and IPv6 addresses. In the future will also include IPv6 DNS servers 438 * and domains obtained from router advertisements (RFC 6106). 439 */ 440 private NetlinkTracker mNetlinkTracker; 441 442 private AlarmManager mAlarmManager; 443 private PendingIntent mScanIntent; 444 private PendingIntent mDriverStopIntent; 445 private PendingIntent mBatchedScanIntervalIntent; 446 447 /* Tracks current frequency mode */ 448 private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO); 449 450 /* Tracks if we are filtering Multicast v4 packets. Default is to filter. */ 451 private AtomicBoolean mFilteringMulticastV4Packets = new AtomicBoolean(true); 452 453 // Channel for sending replies. 454 private AsyncChannel mReplyChannel = new AsyncChannel(); 455 456 private WifiP2pServiceImpl mWifiP2pServiceImpl; 457 458 // Used to initiate a connection with WifiP2pService 459 private AsyncChannel mWifiP2pChannel; 460 private AsyncChannel mWifiApConfigChannel; 461 462 private WifiScanner mWifiScanner; 463 464 private int mConnectionRequests = 0; 465 private WifiNetworkFactory mNetworkFactory; 466 private UntrustedWifiNetworkFactory mUntrustedNetworkFactory; 467 private WifiNetworkAgent mNetworkAgent; 468 469 // Keep track of various statistics, for retrieval by System Apps, i.e. under @SystemApi 470 // We should really persist that into the networkHistory.txt file, and read it back when 471 // WifiStateMachine starts up 472 private WifiConnectionStatistics mWifiConnectionStatistics = new WifiConnectionStatistics(); 473 474 // Used to filter out requests we couldn't possibly satisfy. 475 private final NetworkCapabilities mNetworkCapabilitiesFilter = new NetworkCapabilities(); 476 477 /* The base for wifi message types */ 478 static final int BASE = Protocol.BASE_WIFI; 479 /* Start the supplicant */ 480 static final int CMD_START_SUPPLICANT = BASE + 11; 481 /* Stop the supplicant */ 482 static final int CMD_STOP_SUPPLICANT = BASE + 12; 483 /* Start the driver */ 484 static final int CMD_START_DRIVER = BASE + 13; 485 /* Stop the driver */ 486 static final int CMD_STOP_DRIVER = BASE + 14; 487 /* Indicates Static IP succeeded */ 488 static final int CMD_STATIC_IP_SUCCESS = BASE + 15; 489 /* Indicates Static IP failed */ 490 static final int CMD_STATIC_IP_FAILURE = BASE + 16; 491 /* Indicates supplicant stop failed */ 492 static final int CMD_STOP_SUPPLICANT_FAILED = BASE + 17; 493 /* Delayed stop to avoid shutting down driver too quick*/ 494 static final int CMD_DELAYED_STOP_DRIVER = BASE + 18; 495 /* A delayed message sent to start driver when it fail to come up */ 496 static final int CMD_DRIVER_START_TIMED_OUT = BASE + 19; 497 498 /* Start the soft access point */ 499 static final int CMD_START_AP = BASE + 21; 500 /* Indicates soft ap start succeeded */ 501 static final int CMD_START_AP_SUCCESS = BASE + 22; 502 /* Indicates soft ap start failed */ 503 static final int CMD_START_AP_FAILURE = BASE + 23; 504 /* Stop the soft access point */ 505 static final int CMD_STOP_AP = BASE + 24; 506 /* Set the soft access point configuration */ 507 static final int CMD_SET_AP_CONFIG = BASE + 25; 508 /* Soft access point configuration set completed */ 509 static final int CMD_SET_AP_CONFIG_COMPLETED = BASE + 26; 510 /* Request the soft access point configuration */ 511 static final int CMD_REQUEST_AP_CONFIG = BASE + 27; 512 /* Response to access point configuration request */ 513 static final int CMD_RESPONSE_AP_CONFIG = BASE + 28; 514 /* Invoked when getting a tether state change notification */ 515 static final int CMD_TETHER_STATE_CHANGE = BASE + 29; 516 /* A delayed message sent to indicate tether state change failed to arrive */ 517 static final int CMD_TETHER_NOTIFICATION_TIMED_OUT = BASE + 30; 518 519 static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 31; 520 521 /* Supplicant commands */ 522 /* Is supplicant alive ? */ 523 static final int CMD_PING_SUPPLICANT = BASE + 51; 524 /* Add/update a network configuration */ 525 static final int CMD_ADD_OR_UPDATE_NETWORK = BASE + 52; 526 /* Delete a network */ 527 static final int CMD_REMOVE_NETWORK = BASE + 53; 528 /* Enable a network. The device will attempt a connection to the given network. */ 529 static final int CMD_ENABLE_NETWORK = BASE + 54; 530 /* Enable all networks */ 531 static final int CMD_ENABLE_ALL_NETWORKS = BASE + 55; 532 /* Blacklist network. De-prioritizes the given BSSID for connection. */ 533 static final int CMD_BLACKLIST_NETWORK = BASE + 56; 534 /* Clear the blacklist network list */ 535 static final int CMD_CLEAR_BLACKLIST = BASE + 57; 536 /* Save configuration */ 537 static final int CMD_SAVE_CONFIG = BASE + 58; 538 /* Get configured networks */ 539 static final int CMD_GET_CONFIGURED_NETWORKS = BASE + 59; 540 /* Get available frequencies */ 541 static final int CMD_GET_CAPABILITY_FREQ = BASE + 60; 542 /* Get adaptors */ 543 static final int CMD_GET_SUPPORTED_FEATURES = BASE + 61; 544 /* Get configured networks with real preSharedKey */ 545 static final int CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS = BASE + 62; 546 /* Get Link Layer Stats thru HAL */ 547 static final int CMD_GET_LINK_LAYER_STATS = BASE + 63; 548 /* Supplicant commands after driver start*/ 549 /* Initiate a scan */ 550 static final int CMD_START_SCAN = BASE + 71; 551 /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */ 552 static final int CMD_SET_OPERATIONAL_MODE = BASE + 72; 553 /* Disconnect from a network */ 554 static final int CMD_DISCONNECT = BASE + 73; 555 /* Reconnect to a network */ 556 static final int CMD_RECONNECT = BASE + 74; 557 /* Reassociate to a network */ 558 static final int CMD_REASSOCIATE = BASE + 75; 559 /* Get Connection Statistis */ 560 static final int CMD_GET_CONNECTION_STATISTICS = BASE + 76; 561 562 /* Controls suspend mode optimizations 563 * 564 * When high perf mode is enabled, suspend mode optimizations are disabled 565 * 566 * When high perf mode is disabled, suspend mode optimizations are enabled 567 * 568 * Suspend mode optimizations include: 569 * - packet filtering 570 * - turn off roaming 571 * - DTIM wake up settings 572 */ 573 static final int CMD_SET_HIGH_PERF_MODE = BASE + 77; 574 /* Set the country code */ 575 static final int CMD_SET_COUNTRY_CODE = BASE + 80; 576 /* Enables RSSI poll */ 577 static final int CMD_ENABLE_RSSI_POLL = BASE + 82; 578 /* RSSI poll */ 579 static final int CMD_RSSI_POLL = BASE + 83; 580 /* Set up packet filtering */ 581 static final int CMD_START_PACKET_FILTERING = BASE + 84; 582 /* Clear packet filter */ 583 static final int CMD_STOP_PACKET_FILTERING = BASE + 85; 584 /* Enable suspend mode optimizations in the driver */ 585 static final int CMD_SET_SUSPEND_OPT_ENABLED = BASE + 86; 586 /* Delayed NETWORK_DISCONNECT */ 587 static final int CMD_DELAYED_NETWORK_DISCONNECT = BASE + 87; 588 /* When there are no saved networks, we do a periodic scan to notify user of 589 * an open network */ 590 static final int CMD_NO_NETWORKS_PERIODIC_SCAN = BASE + 88; 591 /* Test network Disconnection NETWORK_DISCONNECT */ 592 static final int CMD_TEST_NETWORK_DISCONNECT = BASE + 89; 593 private int testNetworkDisconnectCounter = 0; 594 595 /* arg1 values to CMD_STOP_PACKET_FILTERING and CMD_START_PACKET_FILTERING */ 596 static final int MULTICAST_V6 = 1; 597 static final int MULTICAST_V4 = 0; 598 599 /* Set the frequency band */ 600 static final int CMD_SET_FREQUENCY_BAND = BASE + 90; 601 /* Enable TDLS on a specific MAC address */ 602 static final int CMD_ENABLE_TDLS = BASE + 92; 603 /* DHCP/IP configuration watchdog */ 604 static final int CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER = BASE + 93; 605 606 /** 607 * Make this timer 40 seconds, which is about the normal DHCP timeout. 608 * In no valid case, the WiFiStateMachine should remain stuck in ObtainingIpAddress 609 * for more than 30 seconds. 610 */ 611 static final int OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC = 40000; 612 613 int obtainingIpWatchdogCount = 0; 614 615 /* Commands from/to the SupplicantStateTracker */ 616 /* Reset the supplicant state tracker */ 617 static final int CMD_RESET_SUPPLICANT_STATE = BASE + 111; 618 619 620 /** 621 * Watchdog for protecting against b/16823537 622 * Leave time for 4-ways handshake to succeed 623 */ 624 static final int ROAM_GUARD_TIMER_MSEC = 15000; 625 626 int roamWatchdogCount = 0; 627 /* Roam state watchdog */ 628 static final int CMD_ROAM_WATCHDOG_TIMER = BASE + 94; 629 /* Screen change intent handling */ 630 static final int CMD_SCREEN_STATE_CHANGED = BASE + 95; 631 632 int disconnectingWatchdogCount = 0; 633 static final int DISCONNECTING_GUARD_TIMER_MSEC = 5000; 634 635 /* Disconnecting state watchdog */ 636 static final int CMD_DISCONNECTING_WATCHDOG_TIMER = BASE + 96; 637 638 /* Disable an ephemeral network */ 639 static final int CMD_DISABLE_EPHEMERAL_NETWORK = BASE + 98; 640 641 /* Get matching network */ 642 static final int CMD_GET_MATCHING_CONFIG = BASE + 99; 643 644 /* P2p commands */ 645 /* We are ok with no response here since we wont do much with it anyway */ 646 public static final int CMD_ENABLE_P2P = BASE + 131; 647 /* In order to shut down supplicant cleanly, we wait till p2p has 648 * been disabled */ 649 public static final int CMD_DISABLE_P2P_REQ = BASE + 132; 650 public static final int CMD_DISABLE_P2P_RSP = BASE + 133; 651 652 public static final int CMD_BOOT_COMPLETED = BASE + 134; 653 654 /* change the batch scan settings. 655 * arg1 = responsible UID 656 * arg2 = csph (channel scans per hour) 657 * obj = bundle with the new settings and the optional worksource 658 */ 659 public static final int CMD_SET_BATCHED_SCAN = BASE + 135; 660 public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136; 661 public static final int CMD_POLL_BATCHED_SCAN = BASE + 137; 662 663 /* We now have a valid IP configuration. */ 664 static final int CMD_IP_CONFIGURATION_SUCCESSFUL = BASE + 138; 665 /* We no longer have a valid IP configuration. */ 666 static final int CMD_IP_CONFIGURATION_LOST = BASE + 139; 667 /* Link configuration (IP address, DNS, ...) changes notified via netlink */ 668 static final int CMD_UPDATE_LINKPROPERTIES = BASE + 140; 669 670 /* Supplicant is trying to associate to a given BSSID */ 671 static final int CMD_TARGET_BSSID = BASE + 141; 672 673 /* Reload all networks and reconnect */ 674 static final int CMD_RELOAD_TLS_AND_RECONNECT = BASE + 142; 675 676 static final int CMD_AUTO_CONNECT = BASE + 143; 677 678 static final int network_status_unwanted_disconnect = 0; 679 static final int network_status_unwanted_disable_autojoin = 1; 680 681 static final int CMD_UNWANTED_NETWORK = BASE + 144; 682 683 static final int CMD_AUTO_ROAM = BASE + 145; 684 685 static final int CMD_AUTO_SAVE_NETWORK = BASE + 146; 686 687 static final int CMD_ASSOCIATED_BSSID = BASE + 147; 688 689 static final int CMD_NETWORK_STATUS = BASE + 148; 690 691 static final int CMD_START_PNO = BASE + 149; /* used to restart PNO when it was 692 stopped due to association attempt */ 693 694 static final int CMD_STARTED_PNO_DBG = BASE + 150; /* used to log if PNO was started */ 695 696 static final int CMD_PNO_NETWORK_FOUND = BASE + 151; 697 698 699 /* Wifi state machine modes of operation */ 700 /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ 701 public static final int CONNECT_MODE = 1; 702 /* SCAN_ONLY_MODE - don't connect to any APs; scan, but only while apps hold lock */ 703 public static final int SCAN_ONLY_MODE = 2; 704 /* SCAN_ONLY_WITH_WIFI_OFF - scan, but don't connect to any APs */ 705 public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3; 706 707 private static final int SUCCESS = 1; 708 private static final int FAILURE = -1; 709 710 /* Tracks if suspend optimizations need to be disabled by DHCP, 711 * screen or due to high perf mode. 712 * When any of them needs to disable it, we keep the suspend optimizations 713 * disabled 714 */ 715 private int mSuspendOptNeedsDisabled = 0; 716 717 private static final int SUSPEND_DUE_TO_DHCP = 1; 718 private static final int SUSPEND_DUE_TO_HIGH_PERF = 1 << 1; 719 private static final int SUSPEND_DUE_TO_SCREEN = 1 << 2; 720 721 /* Tracks if user has enabled suspend optimizations through settings */ 722 private AtomicBoolean mUserWantsSuspendOpt = new AtomicBoolean(true); 723 724 /** 725 * Default framework scan interval in milliseconds. This is used in the scenario in which 726 * wifi chipset does not support background scanning to set up a 727 * periodic wake up scan so that the device can connect to a new access 728 * point on the move. {@link Settings.Global#WIFI_FRAMEWORK_SCAN_INTERVAL_MS} can 729 * override this. 730 */ 731 private final int mDefaultFrameworkScanIntervalMs; 732 733 /** 734 * Supplicant scan interval in milliseconds. 735 * Comes from {@link Settings.Global#WIFI_SUPPLICANT_SCAN_INTERVAL_MS} or 736 * from the default config if the setting is not set 737 */ 738 private long mSupplicantScanIntervalMs; 739 740 /** 741 * timeStamp of last full band scan we perfoemed for autojoin while connected with screen lit 742 */ 743 private long lastFullBandConnectedTimeMilli; 744 745 /** 746 * time interval to the next full band scan we will perform for 747 * autojoin while connected with screen lit 748 */ 749 private long fullBandConnectedTimeIntervalMilli; 750 751 /** 752 * max time interval to the next full band scan we will perform for 753 * autojoin while connected with screen lit 754 * Max time is 5 minutes 755 */ 756 private static final long maxFullBandConnectedTimeIntervalMilli = 1000 * 60 * 5; 757 758 /** 759 * Minimum time interval between enabling all networks. 760 * A device can end up repeatedly connecting to a bad network on screen on/off toggle 761 * due to enabling every time. We add a threshold to avoid this. 762 */ 763 private static final int MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS = 10 * 60 * 1000; /* 10 minutes */ 764 private long mLastEnableAllNetworksTime; 765 766 int mRunningBeaconCount = 0; 767 768 /** 769 * Starting and shutting down driver too quick causes problems leading to driver 770 * being in a bad state. Delay driver stop. 771 */ 772 private final int mDriverStopDelayMs; 773 private int mDelayedStopCounter; 774 private boolean mInDelayedStop = false; 775 776 // there is a delay between StateMachine change country code and Supplicant change country code 777 // here save the current WifiStateMachine set country code 778 private volatile String mSetCountryCode = null; 779 780 // Supplicant doesn't like setting the same country code multiple times (it may drop 781 // currently connected network), so we save the current device set country code here to avoid 782 // redundency 783 private String mDriverSetCountryCode = null; 784 785 /* Default parent state */ 786 private State mDefaultState = new DefaultState(); 787 /* Temporary initial state */ 788 private State mInitialState = new InitialState(); 789 /* Driver loaded, waiting for supplicant to start */ 790 private State mSupplicantStartingState = new SupplicantStartingState(); 791 /* Driver loaded and supplicant ready */ 792 private State mSupplicantStartedState = new SupplicantStartedState(); 793 /* Waiting for supplicant to stop and monitor to exit */ 794 private State mSupplicantStoppingState = new SupplicantStoppingState(); 795 /* Driver start issued, waiting for completed event */ 796 private State mDriverStartingState = new DriverStartingState(); 797 /* Driver started */ 798 private State mDriverStartedState = new DriverStartedState(); 799 /* Wait until p2p is disabled 800 * This is a special state which is entered right after we exit out of DriverStartedState 801 * before transitioning to another state. 802 */ 803 private State mWaitForP2pDisableState = new WaitForP2pDisableState(); 804 /* Driver stopping */ 805 private State mDriverStoppingState = new DriverStoppingState(); 806 /* Driver stopped */ 807 private State mDriverStoppedState = new DriverStoppedState(); 808 /* Scan for networks, no connection will be established */ 809 private State mScanModeState = new ScanModeState(); 810 /* Connecting to an access point */ 811 private State mConnectModeState = new ConnectModeState(); 812 /* Connected at 802.11 (L2) level */ 813 private State mL2ConnectedState = new L2ConnectedState(); 814 /* fetching IP after connection to access point (assoc+auth complete) */ 815 private State mObtainingIpState = new ObtainingIpState(); 816 /* Waiting for link quality verification to be complete */ 817 private State mVerifyingLinkState = new VerifyingLinkState(); 818 /* Connected with IP addr */ 819 private State mConnectedState = new ConnectedState(); 820 /* Roaming */ 821 private State mRoamingState = new RoamingState(); 822 /* disconnect issued, waiting for network disconnect confirmation */ 823 private State mDisconnectingState = new DisconnectingState(); 824 /* Network is not connected, supplicant assoc+auth is not complete */ 825 private State mDisconnectedState = new DisconnectedState(); 826 /* Waiting for WPS to be completed*/ 827 private State mWpsRunningState = new WpsRunningState(); 828 829 /* Soft ap is starting up */ 830 private State mSoftApStartingState = new SoftApStartingState(); 831 /* Soft ap is running */ 832 private State mSoftApStartedState = new SoftApStartedState(); 833 /* Soft ap is running and we are waiting for tether notification */ 834 private State mTetheringState = new TetheringState(); 835 /* Soft ap is running and we are tethered through connectivity service */ 836 private State mTetheredState = new TetheredState(); 837 /* Waiting for untether confirmation before stopping soft Ap */ 838 private State mUntetheringState = new UntetheringState(); 839 840 841 842 private class WifiScanListener implements WifiScanner.ScanListener { 843 @Override 844 public void onSuccess() { 845 Log.e(TAG, "WifiScanListener onSuccess"); 846 }; 847 @Override 848 public void onFailure(int reason, String description) { 849 Log.e(TAG, "WifiScanListener onFailure"); 850 }; 851 @Override 852 public void onPeriodChanged(int periodInMs) { 853 Log.e(TAG, "WifiScanListener onPeriodChanged period=" + periodInMs); 854 } 855 @Override 856 public void onResults(ScanResult[] results) { 857 Log.e(TAG, "WifiScanListener onResults" + results.length); 858 } 859 @Override 860 public void onResults(WifiScanner.ScanData[] results) { 861 Log.e(TAG, "WifiScanListener onResults2 " + results.length); 862 } 863 @Override 864 public void onFullResult(ScanResult fullScanResult) { 865 Log.e(TAG, "WifiScanListener onFullResult " + fullScanResult.toString()); 866 } 867 868 WifiScanListener() {} 869 } 870 871 WifiScanListener mWifiScanListener = new WifiScanListener(); 872 873 874 private class TetherStateChange { 875 ArrayList<String> available; 876 ArrayList<String> active; 877 878 TetherStateChange(ArrayList<String> av, ArrayList<String> ac) { 879 available = av; 880 active = ac; 881 } 882 } 883 884 public static class SimAuthRequestData { 885 int networkId; 886 int protocol; 887 String ssid; 888 // EAP-SIM: data[] contains the 3 rand, one for each of the 3 challenges 889 // EAP-AKA/AKA': data[] contains rand & authn couple for the single challenge 890 String[] data; 891 } 892 893 /** 894 * One of {@link WifiManager#WIFI_STATE_DISABLED}, 895 * {@link WifiManager#WIFI_STATE_DISABLING}, 896 * {@link WifiManager#WIFI_STATE_ENABLED}, 897 * {@link WifiManager#WIFI_STATE_ENABLING}, 898 * {@link WifiManager#WIFI_STATE_UNKNOWN} 899 */ 900 private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED); 901 902 /** 903 * One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 904 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 905 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 906 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 907 * {@link WifiManager#WIFI_AP_STATE_FAILED} 908 */ 909 private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED); 910 911 private static final int SCAN_REQUEST = 0; 912 private static final String ACTION_START_SCAN = 913 "com.android.server.WifiManager.action.START_SCAN"; 914 915 private static final String DELAYED_STOP_COUNTER = "DelayedStopCounter"; 916 private static final int DRIVER_STOP_REQUEST = 0; 917 private static final String ACTION_DELAYED_DRIVER_STOP = 918 "com.android.server.WifiManager.action.DELAYED_DRIVER_STOP"; 919 920 private static final String ACTION_REFRESH_BATCHED_SCAN = 921 "com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN"; 922 /** 923 * Keep track of whether WIFI is running. 924 */ 925 private boolean mIsRunning = false; 926 927 /** 928 * Keep track of whether we last told the battery stats we had started. 929 */ 930 private boolean mReportedRunning = false; 931 932 /** 933 * Most recently set source of starting WIFI. 934 */ 935 private final WorkSource mRunningWifiUids = new WorkSource(); 936 937 /** 938 * The last reported UIDs that were responsible for starting WIFI. 939 */ 940 private final WorkSource mLastRunningWifiUids = new WorkSource(); 941 942 private final IBatteryStats mBatteryStats; 943 944 private BatchedScanSettings mBatchedScanSettings = null; 945 946 /** 947 * Track the worksource/cost of the current settings and track what's been noted 948 * to the battery stats, so we can mark the end of the previous when changing. 949 */ 950 private WorkSource mBatchedScanWorkSource = null; 951 private int mBatchedScanCsph = 0; 952 private WorkSource mNotedBatchedScanWorkSource = null; 953 private int mNotedBatchedScanCsph = 0; 954 955 private String mTcpBufferSizes = null; 956 957 // Used for debug and stats gathering 958 private static int sScanAlarmIntentCount = 0; 959 960 final static int frameworkMinScanIntervalSaneValue = 10000; 961 962 public WifiStateMachine(Context context, String wlanInterface, 963 WifiTrafficPoller trafficPoller) { 964 super("WifiStateMachine"); 965 mContext = context; 966 mSetCountryCode = Settings.Global.getString( 967 mContext.getContentResolver(), Settings.Global.WIFI_COUNTRY_CODE); 968 mInterfaceName = wlanInterface; 969 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); 970 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 971 BatteryStats.SERVICE_NAME)); 972 973 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 974 mNwService = INetworkManagementService.Stub.asInterface(b); 975 976 mP2pSupported = mContext.getPackageManager().hasSystemFeature( 977 PackageManager.FEATURE_WIFI_DIRECT); 978 979 mWifiNative = new WifiNative(mInterfaceName); 980 mWifiConfigStore = new WifiConfigStore(context, mWifiNative); 981 mWifiAutoJoinController = new WifiAutoJoinController(context, this, 982 mWifiConfigStore, mWifiConnectionStatistics, mWifiNative); 983 mWifiLogger = new WifiLogger(mContext, this); 984 mWifiMonitor = new WifiMonitor(this, mWifiNative); 985 mWifiInfo = new WifiInfo(); 986 mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, 987 getHandler()); 988 mLinkProperties = new LinkProperties(); 989 990 IBinder s1 = ServiceManager.getService(Context.WIFI_P2P_SERVICE); 991 mWifiP2pServiceImpl = (WifiP2pServiceImpl) IWifiP2pManager.Stub.asInterface(s1); 992 993 mNetworkInfo.setIsAvailable(false); 994 mLastBssid = null; 995 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 996 mLastSignalLevel = -1; 997 998 mNetlinkTracker = new NetlinkTracker(mInterfaceName, new NetlinkTracker.Callback() { 999 public void update() { 1000 sendMessage(CMD_UPDATE_LINKPROPERTIES); 1001 } 1002 }); 1003 try { 1004 mNwService.registerObserver(mNetlinkTracker); 1005 } catch (RemoteException e) { 1006 loge("Couldn't register netlink tracker: " + e.toString()); 1007 } 1008 1009 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 1010 mScanIntent = getPrivateBroadcast(ACTION_START_SCAN, SCAN_REQUEST); 1011 mBatchedScanIntervalIntent = getPrivateBroadcast(ACTION_REFRESH_BATCHED_SCAN, 0); 1012 1013 // Make sure the interval is not configured less than 10 seconds 1014 int period = mContext.getResources().getInteger( 1015 R.integer.config_wifi_framework_scan_interval); 1016 if (period < frameworkMinScanIntervalSaneValue) { 1017 period = frameworkMinScanIntervalSaneValue; 1018 } 1019 mDefaultFrameworkScanIntervalMs = period; 1020 mDriverStopDelayMs = mContext.getResources().getInteger( 1021 R.integer.config_wifi_driver_stop_delay); 1022 1023 mBackgroundScanSupported = mContext.getResources().getBoolean( 1024 R.bool.config_wifi_background_scan_support); 1025 1026 mPrimaryDeviceType = mContext.getResources().getString( 1027 R.string.config_wifi_p2p_device_type); 1028 1029 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 1030 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 1031 1032 mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); 1033 mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 1034 mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 1035 mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024); 1036 mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024); 1037 // TODO - needs to be a bit more dynamic 1038 mNetworkCapabilities = new NetworkCapabilities(mNetworkCapabilitiesFilter); 1039 1040 mContext.registerReceiver( 1041 new BroadcastReceiver() { 1042 @Override 1043 public void onReceive(Context context, Intent intent) { 1044 ArrayList<String> available = intent.getStringArrayListExtra( 1045 ConnectivityManager.EXTRA_AVAILABLE_TETHER); 1046 ArrayList<String> active = intent.getStringArrayListExtra( 1047 ConnectivityManager.EXTRA_ACTIVE_TETHER); 1048 sendMessage(CMD_TETHER_STATE_CHANGE, new TetherStateChange(available, active)); 1049 } 1050 }, new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); 1051 1052 mContext.registerReceiver( 1053 new BroadcastReceiver() { 1054 @Override 1055 public void onReceive(Context context, Intent intent) { 1056 sScanAlarmIntentCount++; // Used for debug only 1057 startScan(SCAN_ALARM_SOURCE, mDelayedScanCounter.incrementAndGet(), null, null); 1058 if (VDBG) 1059 loge("WiFiStateMachine SCAN ALARM -> " + mDelayedScanCounter.get()); 1060 } 1061 }, 1062 new IntentFilter(ACTION_START_SCAN)); 1063 1064 IntentFilter filter = new IntentFilter(); 1065 filter.addAction(Intent.ACTION_SCREEN_ON); 1066 filter.addAction(Intent.ACTION_SCREEN_OFF); 1067 filter.addAction(ACTION_REFRESH_BATCHED_SCAN); 1068 mContext.registerReceiver( 1069 new BroadcastReceiver() { 1070 @Override 1071 public void onReceive(Context context, Intent intent) { 1072 String action = intent.getAction(); 1073 1074 if (action.equals(Intent.ACTION_SCREEN_ON)) { 1075 sendMessage(CMD_SCREEN_STATE_CHANGED, 1); 1076 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 1077 sendMessage(CMD_SCREEN_STATE_CHANGED, 0); 1078 } else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) { 1079 startNextBatchedScanAsync(); 1080 } 1081 } 1082 }, filter); 1083 1084 mContext.registerReceiver( 1085 new BroadcastReceiver() { 1086 @Override 1087 public void onReceive(Context context, Intent intent) { 1088 int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0); 1089 sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0); 1090 } 1091 }, 1092 new IntentFilter(ACTION_DELAYED_DRIVER_STOP)); 1093 1094 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 1095 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED), false, 1096 new ContentObserver(getHandler()) { 1097 @Override 1098 public void onChange(boolean selfChange) { 1099 mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), 1100 Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); 1101 } 1102 }); 1103 1104 mContext.registerReceiver( 1105 new BroadcastReceiver() { 1106 @Override 1107 public void onReceive(Context context, Intent intent) { 1108 sendMessage(CMD_BOOT_COMPLETED); 1109 } 1110 }, 1111 new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); 1112 1113 mScanResultCache = new LruCache<>(SCAN_RESULT_CACHE_SIZE); 1114 1115 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 1116 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getName()); 1117 1118 mSuspendWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WifiSuspend"); 1119 mSuspendWakeLock.setReferenceCounted(false); 1120 1121 mTcpBufferSizes = mContext.getResources().getString( 1122 com.android.internal.R.string.config_wifi_tcp_buffers); 1123 1124 addState(mDefaultState); 1125 addState(mInitialState, mDefaultState); 1126 addState(mSupplicantStartingState, mDefaultState); 1127 addState(mSupplicantStartedState, mDefaultState); 1128 addState(mDriverStartingState, mSupplicantStartedState); 1129 addState(mDriverStartedState, mSupplicantStartedState); 1130 addState(mScanModeState, mDriverStartedState); 1131 addState(mConnectModeState, mDriverStartedState); 1132 addState(mL2ConnectedState, mConnectModeState); 1133 addState(mObtainingIpState, mL2ConnectedState); 1134 addState(mVerifyingLinkState, mL2ConnectedState); 1135 addState(mConnectedState, mL2ConnectedState); 1136 addState(mRoamingState, mL2ConnectedState); 1137 addState(mDisconnectingState, mConnectModeState); 1138 addState(mDisconnectedState, mConnectModeState); 1139 addState(mWpsRunningState, mConnectModeState); 1140 addState(mWaitForP2pDisableState, mSupplicantStartedState); 1141 addState(mDriverStoppingState, mSupplicantStartedState); 1142 addState(mDriverStoppedState, mSupplicantStartedState); 1143 addState(mSupplicantStoppingState, mDefaultState); 1144 addState(mSoftApStartingState, mDefaultState); 1145 addState(mSoftApStartedState, mDefaultState); 1146 addState(mTetheringState, mSoftApStartedState); 1147 addState(mTetheredState, mSoftApStartedState); 1148 addState(mUntetheringState, mSoftApStartedState); 1149 1150 setInitialState(mInitialState); 1151 1152 setLogRecSize(ActivityManager.isLowRamDeviceStatic() ? 100 : 3000); 1153 setLogOnlyTransitions(false); 1154 if (VDBG) setDbg(true); 1155 1156 //start the state machine 1157 start(); 1158 1159 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 1160 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1161 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 1162 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1163 } 1164 1165 1166 PendingIntent getPrivateBroadcast(String action, int requestCode) { 1167 Intent intent = new Intent(action, null); 1168 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1169 intent.setPackage(this.getClass().getPackage().getName()); 1170 return PendingIntent.getBroadcast(mContext, requestCode, intent, 0); 1171 } 1172 1173 private int mVerboseLoggingLevel = 0; 1174 1175 int getVerboseLoggingLevel() { 1176 return mVerboseLoggingLevel; 1177 } 1178 1179 void enableVerboseLogging(int verbose) { 1180 mVerboseLoggingLevel = verbose; 1181 if (verbose > 0) { 1182 DBG = true; 1183 VDBG = true; 1184 PDBG = true; 1185 mLogMessages = true; 1186 mWifiNative.setSupplicantLogLevel("DEBUG"); 1187 } else { 1188 DBG = false; 1189 VDBG = false; 1190 PDBG = false; 1191 mLogMessages = false; 1192 mWifiNative.setSupplicantLogLevel("INFO"); 1193 } 1194 mWifiAutoJoinController.enableVerboseLogging(verbose); 1195 mWifiMonitor.enableVerboseLogging(verbose); 1196 mWifiNative.enableVerboseLogging(verbose); 1197 mWifiConfigStore.enableVerboseLogging(verbose); 1198 mSupplicantStateTracker.enableVerboseLogging(verbose); 1199 } 1200 1201 private int mAggressiveHandover = 0; 1202 1203 int getAggressiveHandover() { 1204 return mAggressiveHandover; 1205 } 1206 1207 void enableAggressiveHandover(int enabled) { 1208 mAggressiveHandover = enabled; 1209 } 1210 1211 public void setAllowScansWithTraffic(int enabled) { 1212 mWifiConfigStore.alwaysEnableScansWhileAssociated.set(enabled); 1213 } 1214 1215 public int getAllowScansWithTraffic() { 1216 return mWifiConfigStore.alwaysEnableScansWhileAssociated.get(); 1217 } 1218 1219 public void setAllowScansWhileAssociated(boolean enabled) { 1220 mWifiConfigStore.enableAutoJoinScanWhenAssociated.set(enabled); 1221 } 1222 1223 public boolean getAllowScansWhileAssociated() { 1224 return mWifiConfigStore.enableAutoJoinScanWhenAssociated.get(); 1225 } 1226 1227 /* 1228 * 1229 * Framework scan control 1230 */ 1231 1232 private boolean mAlarmEnabled = false; 1233 1234 private AtomicInteger mDelayedScanCounter = new AtomicInteger(); 1235 1236 private void setScanAlarm(boolean enabled) { 1237 if (PDBG) { 1238 loge("setScanAlarm " + enabled 1239 + " period " + mDefaultFrameworkScanIntervalMs 1240 + " mBackgroundScanSupported " + mBackgroundScanSupported); 1241 } 1242 if (mBackgroundScanSupported == false) { 1243 // Scan alarm is only used for background scans if they are not 1244 // offloaded to the wifi chipset, hence enable the scan alarm 1245 // gicing us RTC_WAKEUP of backgroundScan is NOT supported 1246 enabled = true; 1247 } 1248 1249 if (enabled == mAlarmEnabled) return; 1250 if (enabled) { 1251 /* Set RTC_WAKEUP alarms if PNO is not supported - because no one is */ 1252 /* going to wake up the host processor to look for access points */ 1253 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 1254 System.currentTimeMillis() + mDefaultFrameworkScanIntervalMs, 1255 mScanIntent); 1256 mAlarmEnabled = true; 1257 } else { 1258 mAlarmManager.cancel(mScanIntent); 1259 mAlarmEnabled = false; 1260 } 1261 } 1262 1263 private void cancelDelayedScan() { 1264 mDelayedScanCounter.incrementAndGet(); 1265 loge("cancelDelayedScan -> " + mDelayedScanCounter); 1266 } 1267 1268 private boolean checkAndRestartDelayedScan(int counter, boolean restart, int milli, 1269 ScanSettings settings, WorkSource workSource) { 1270 1271 if (counter != mDelayedScanCounter.get()) { 1272 return false; 1273 } 1274 if (restart) 1275 startDelayedScan(milli, settings, workSource); 1276 return true; 1277 } 1278 1279 private void startDelayedScan(int milli, ScanSettings settings, WorkSource workSource) { 1280 if (milli <= 0) return; 1281 /** 1282 * The cases where the scan alarm should be run are : 1283 * - DisconnectedState && screenOn => used delayed timer 1284 * - DisconnectedState && !screenOn && mBackgroundScanSupported => PNO 1285 * - DisconnectedState && !screenOn && !mBackgroundScanSupported => used RTC_WAKEUP Alarm 1286 * - ConnectedState && screenOn => used delayed timer 1287 */ 1288 1289 mDelayedScanCounter.incrementAndGet(); 1290 if (mScreenOn && 1291 (getCurrentState() == mDisconnectedState 1292 || getCurrentState() == mConnectedState)) { 1293 Bundle bundle = new Bundle(); 1294 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings); 1295 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1296 bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis()); 1297 sendMessageDelayed(CMD_START_SCAN, SCAN_ALARM_SOURCE, 1298 mDelayedScanCounter.get(), bundle, milli); 1299 if (DBG) loge("startDelayedScan send -> " + mDelayedScanCounter + " milli " + milli); 1300 } else if (mBackgroundScanSupported == false 1301 && !mScreenOn && getCurrentState() == mDisconnectedState) { 1302 setScanAlarm(true); 1303 if (DBG) loge("startDelayedScan start scan alarm -> " 1304 + mDelayedScanCounter + " milli " + milli); 1305 } else { 1306 if (DBG) loge("startDelayedScan unhandled -> " 1307 + mDelayedScanCounter + " milli " + milli); 1308 } 1309 } 1310 1311 private boolean setRandomMacOui() { 1312 String oui = mContext.getResources().getString( 1313 R.string.config_wifi_random_mac_oui, GOOGLE_OUI); 1314 String[] ouiParts = oui.split("-"); 1315 byte[] ouiBytes = new byte[3]; 1316 ouiBytes[0] = (byte) (Integer.parseInt(ouiParts[0], 16) & 0xFF); 1317 ouiBytes[1] = (byte) (Integer.parseInt(ouiParts[1], 16) & 0xFF); 1318 ouiBytes[2] = (byte) (Integer.parseInt(ouiParts[2], 16) & 0xFF); 1319 1320 logd("Setting OUI to " + oui); 1321 return mWifiNative.setScanningMacOui(ouiBytes); 1322 } 1323 1324 /** 1325 * ****************************************************** 1326 * Methods exposed for public use 1327 * ****************************************************** 1328 */ 1329 1330 public Messenger getMessenger() { 1331 return new Messenger(getHandler()); 1332 } 1333 1334 public WifiMonitor getWifiMonitor() { 1335 return mWifiMonitor; 1336 } 1337 1338 /** 1339 * TODO: doc 1340 */ 1341 public boolean syncPingSupplicant(AsyncChannel channel) { 1342 Message resultMsg = channel.sendMessageSynchronously(CMD_PING_SUPPLICANT); 1343 boolean result = (resultMsg.arg1 != FAILURE); 1344 resultMsg.recycle(); 1345 return result; 1346 } 1347 1348 public List<WifiChannel> syncGetChannelList(AsyncChannel channel) { 1349 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CAPABILITY_FREQ); 1350 List<WifiChannel> list = null; 1351 if (resultMsg.obj != null) { 1352 list = new ArrayList<WifiChannel>(); 1353 String freqs = (String) resultMsg.obj; 1354 String[] lines = freqs.split("\n"); 1355 for (String line : lines) 1356 if (line.contains("MHz")) { 1357 // line format: " 52 = 5260 MHz (NO_IBSS) (DFS)" 1358 WifiChannel c = new WifiChannel(); 1359 String[] prop = line.split(" "); 1360 if (prop.length < 5) continue; 1361 try { 1362 c.channelNum = Integer.parseInt(prop[1]); 1363 c.freqMHz = Integer.parseInt(prop[3]); 1364 } catch (NumberFormatException e) { 1365 } 1366 c.isDFS = line.contains("(DFS)"); 1367 list.add(c); 1368 } else if (line.contains("Mode[B] Channels:")) { 1369 // B channels are the same as G channels, skipped 1370 break; 1371 } 1372 } 1373 resultMsg.recycle(); 1374 return (list != null && list.size() > 0) ? list : null; 1375 } 1376 1377 /** 1378 * When settings allowing making use of untrusted networks change, trigger a scan 1379 * so as to kick of autojoin. 1380 */ 1381 public void startScanForUntrustedSettingChange() { 1382 startScan(SET_ALLOW_UNTRUSTED_SOURCE, 0, null, null); 1383 } 1384 1385 /** 1386 * Initiate a wifi scan. If workSource is not null, blame is given to it, otherwise blame is 1387 * given to callingUid. 1388 * 1389 * @param callingUid The uid initiating the wifi scan. Blame will be given here unless 1390 * workSource is specified. 1391 * @param workSource If not null, blame is given to workSource. 1392 * @param settings Scan settings, see {@link ScanSettings}. 1393 */ 1394 public void startScan(int callingUid, int scanCounter, 1395 ScanSettings settings, WorkSource workSource) { 1396 Bundle bundle = new Bundle(); 1397 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings); 1398 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 1399 bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis()); 1400 sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle); 1401 } 1402 1403 /** 1404 * start or stop batched scanning using the given settings 1405 */ 1406 public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph, 1407 WorkSource workSource) { 1408 Bundle bundle = new Bundle(); 1409 bundle.putParcelable(BATCHED_SETTING, settings); 1410 bundle.putParcelable(BATCHED_WORKSOURCE, workSource); 1411 sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle); 1412 } 1413 1414 public List<BatchedScanResult> syncGetBatchedScanResultsList() { 1415 synchronized (mBatchedScanResults) { 1416 List<BatchedScanResult> batchedScanList = 1417 new ArrayList<BatchedScanResult>(mBatchedScanResults.size()); 1418 for (BatchedScanResult result : mBatchedScanResults) { 1419 batchedScanList.add(new BatchedScanResult(result)); 1420 } 1421 return batchedScanList; 1422 } 1423 } 1424 1425 public void requestBatchedScanPoll() { 1426 sendMessage(CMD_POLL_BATCHED_SCAN); 1427 } 1428 1429 private void startBatchedScan() { 1430 if (mBatchedScanSettings == null) return; 1431 1432 if (mDhcpActive) { 1433 if (DBG) log("not starting Batched Scans due to DHCP"); 1434 return; 1435 } 1436 1437 // first grab any existing data 1438 retrieveBatchedScanData(); 1439 1440 if (PDBG) loge("try starting Batched Scans due to DHCP"); 1441 1442 1443 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1444 1445 String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings); 1446 try { 1447 mExpectedBatchedScans = Integer.parseInt(scansExpected); 1448 setNextBatchedAlarm(mExpectedBatchedScans); 1449 if (mExpectedBatchedScans > 0) noteBatchedScanStart(); 1450 } catch (NumberFormatException e) { 1451 stopBatchedScan(); 1452 loge("Exception parsing WifiNative.setBatchedScanSettings response " + e); 1453 } 1454 } 1455 1456 // called from BroadcastListener 1457 private void startNextBatchedScanAsync() { 1458 sendMessage(CMD_START_NEXT_BATCHED_SCAN); 1459 } 1460 1461 private void startNextBatchedScan() { 1462 // first grab any existing data 1463 retrieveBatchedScanData(); 1464 1465 setNextBatchedAlarm(mExpectedBatchedScans); 1466 } 1467 1468 private void handleBatchedScanPollRequest() { 1469 if (DBG) { 1470 log("handleBatchedScanPoll Request - mBatchedScanMinPollTime=" + 1471 mBatchedScanMinPollTime + " , mBatchedScanSettings=" + 1472 mBatchedScanSettings); 1473 } 1474 // if there is no appropriate PollTime that's because we either aren't 1475 // batching or we've already set a time for a poll request 1476 if (mBatchedScanMinPollTime == 0) return; 1477 if (mBatchedScanSettings == null) return; 1478 1479 long now = System.currentTimeMillis(); 1480 1481 if (now > mBatchedScanMinPollTime) { 1482 // do the poll and reset our timers 1483 startNextBatchedScan(); 1484 } else { 1485 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, mBatchedScanMinPollTime, 1486 mBatchedScanIntervalIntent); 1487 mBatchedScanMinPollTime = 0; 1488 } 1489 } 1490 1491 // return true if new/different 1492 private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) { 1493 BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING); 1494 WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE); 1495 1496 if (DBG) { 1497 log("set batched scan to " + settings + " for uid=" + responsibleUid + 1498 ", worksource=" + responsibleWorkSource); 1499 } 1500 if (settings != null) { 1501 if (settings.equals(mBatchedScanSettings)) return false; 1502 } else { 1503 if (mBatchedScanSettings == null) return false; 1504 } 1505 mBatchedScanSettings = settings; 1506 if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid); 1507 mBatchedScanWorkSource = responsibleWorkSource; 1508 mBatchedScanCsph = csph; 1509 return true; 1510 } 1511 1512 private void stopBatchedScan() { 1513 mAlarmManager.cancel(mBatchedScanIntervalIntent); 1514 retrieveBatchedScanData(); 1515 mWifiNative.setBatchedScanSettings(null); 1516 noteBatchedScanStop(); 1517 } 1518 1519 private void setNextBatchedAlarm(int scansExpected) { 1520 1521 if (mBatchedScanSettings == null || scansExpected < 1) return; 1522 1523 mBatchedScanMinPollTime = System.currentTimeMillis() + 1524 mBatchedScanSettings.scanIntervalSec * 1000; 1525 1526 if (mBatchedScanSettings.maxScansPerBatch < scansExpected) { 1527 scansExpected = mBatchedScanSettings.maxScansPerBatch; 1528 } 1529 1530 int secToFull = mBatchedScanSettings.scanIntervalSec; 1531 secToFull *= scansExpected; 1532 1533 int debugPeriod = SystemProperties.getInt("wifi.batchedScan.pollPeriod", 0); 1534 if (debugPeriod > 0) secToFull = debugPeriod; 1535 1536 // set the alarm to do the next poll. We set it a little short as we'd rather 1537 // wake up wearly than miss a scan due to buffer overflow 1538 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 1539 + ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000), 1540 mBatchedScanIntervalIntent); 1541 } 1542 1543 /** 1544 * Start reading new scan data 1545 * Data comes in as: 1546 * "scancount=5\n" 1547 * "nextcount=5\n" 1548 * "apcount=3\n" 1549 * "trunc\n" (optional) 1550 * "bssid=...\n" 1551 * "ssid=...\n" 1552 * "freq=...\n" (in Mhz) 1553 * "level=...\n" 1554 * "dist=...\n" (in cm) 1555 * "distsd=...\n" (standard deviation, in cm) 1556 * "====" 1557 * "bssid=...\n" 1558 * etc 1559 * "====" 1560 * "bssid=...\n" 1561 * etc 1562 * "%%%%" 1563 * "apcount=2\n" 1564 * "bssid=...\n" 1565 * etc 1566 * "%%%% 1567 * etc 1568 * "----" 1569 */ 1570 private final static boolean DEBUG_PARSE = false; 1571 1572 private void retrieveBatchedScanData() { 1573 String rawData = mWifiNative.getBatchedScanResults(); 1574 if (DEBUG_PARSE) log("rawData = " + rawData); 1575 mBatchedScanMinPollTime = 0; 1576 if (rawData == null || rawData.equalsIgnoreCase("OK")) { 1577 loge("Unexpected BatchedScanResults :" + rawData); 1578 return; 1579 } 1580 1581 int scanCount = 0; 1582 final String END_OF_BATCHES = "----"; 1583 final String SCANCOUNT = "scancount="; 1584 final String TRUNCATED = "trunc"; 1585 final String AGE = "age="; 1586 final String DIST = "dist="; 1587 final String DISTSD = "distSd="; 1588 1589 String splitData[] = rawData.split("\n"); 1590 int n = 0; 1591 if (splitData[n].startsWith(SCANCOUNT)) { 1592 try { 1593 scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length())); 1594 } catch (NumberFormatException e) { 1595 loge("scancount parseInt Exception from " + splitData[n]); 1596 } 1597 } else log("scancount not found"); 1598 if (scanCount == 0) { 1599 loge("scanCount==0 - aborting"); 1600 return; 1601 } 1602 1603 final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION); 1604 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1605 1606 synchronized (mBatchedScanResults) { 1607 mBatchedScanResults.clear(); 1608 BatchedScanResult batchedScanResult = new BatchedScanResult(); 1609 1610 String bssid = null; 1611 WifiSsid wifiSsid = null; 1612 int level = 0; 1613 int freq = 0; 1614 int dist, distSd; 1615 long tsf = 0; 1616 dist = distSd = ScanResult.UNSPECIFIED; 1617 final long now = SystemClock.elapsedRealtime(); 1618 final int bssidStrLen = BSSID_STR.length(); 1619 1620 while (true) { 1621 while (n < splitData.length) { 1622 if (DEBUG_PARSE) logd("parsing " + splitData[n]); 1623 if (splitData[n].equals(END_OF_BATCHES)) { 1624 if (n + 1 != splitData.length) { 1625 loge("didn't consume " + (splitData.length - n)); 1626 } 1627 if (mBatchedScanResults.size() > 0) { 1628 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1629 } 1630 logd("retrieveBatchedScanResults X"); 1631 return; 1632 } 1633 if ((splitData[n].equals(END_STR)) || splitData[n].equals(DELIMITER_STR)) { 1634 if (bssid != null) { 1635 batchedScanResult.scanResults.add(new ScanResult( 1636 wifiSsid, bssid, null, 1637 level, freq, tsf, dist, distSd)); 1638 wifiSsid = null; 1639 bssid = null; 1640 level = 0; 1641 freq = 0; 1642 tsf = 0; 1643 dist = distSd = ScanResult.UNSPECIFIED; 1644 } 1645 if (splitData[n].equals(END_STR)) { 1646 if (batchedScanResult.scanResults.size() != 0) { 1647 mBatchedScanResults.add(batchedScanResult); 1648 batchedScanResult = new BatchedScanResult(); 1649 } else { 1650 logd("Found empty batch"); 1651 } 1652 } 1653 } else if (splitData[n].equals(TRUNCATED)) { 1654 batchedScanResult.truncated = true; 1655 } else if (splitData[n].startsWith(BSSID_STR)) { 1656 bssid = new String(splitData[n].getBytes(), bssidStrLen, 1657 splitData[n].length() - bssidStrLen); 1658 } else if (splitData[n].startsWith(FREQ_STR)) { 1659 try { 1660 freq = Integer.parseInt(splitData[n].substring(FREQ_STR.length())); 1661 } catch (NumberFormatException e) { 1662 loge("Invalid freqency: " + splitData[n]); 1663 freq = 0; 1664 } 1665 } else if (splitData[n].startsWith(AGE)) { 1666 try { 1667 tsf = now - Long.parseLong(splitData[n].substring(AGE.length())); 1668 tsf *= 1000; // convert mS -> uS 1669 } catch (NumberFormatException e) { 1670 loge("Invalid timestamp: " + splitData[n]); 1671 tsf = 0; 1672 } 1673 } else if (splitData[n].startsWith(SSID_STR)) { 1674 wifiSsid = WifiSsid.createFromAsciiEncoded( 1675 splitData[n].substring(SSID_STR.length())); 1676 } else if (splitData[n].startsWith(LEVEL_STR)) { 1677 try { 1678 level = Integer.parseInt(splitData[n].substring(LEVEL_STR.length())); 1679 if (level > 0) level -= 256; 1680 } catch (NumberFormatException e) { 1681 loge("Invalid level: " + splitData[n]); 1682 level = 0; 1683 } 1684 } else if (splitData[n].startsWith(DIST)) { 1685 try { 1686 dist = Integer.parseInt(splitData[n].substring(DIST.length())); 1687 } catch (NumberFormatException e) { 1688 loge("Invalid distance: " + splitData[n]); 1689 dist = ScanResult.UNSPECIFIED; 1690 } 1691 } else if (splitData[n].startsWith(DISTSD)) { 1692 try { 1693 distSd = Integer.parseInt(splitData[n].substring(DISTSD.length())); 1694 } catch (NumberFormatException e) { 1695 loge("Invalid distanceSd: " + splitData[n]); 1696 distSd = ScanResult.UNSPECIFIED; 1697 } 1698 } else { 1699 loge("Unable to parse batched scan result line: " + splitData[n]); 1700 } 1701 n++; 1702 } 1703 rawData = mWifiNative.getBatchedScanResults(); 1704 if (DEBUG_PARSE) log("reading more data:\n" + rawData); 1705 if (rawData == null) { 1706 loge("Unexpected null BatchedScanResults"); 1707 return; 1708 } 1709 splitData = rawData.split("\n"); 1710 if (splitData.length == 0 || splitData[0].equals("ok")) { 1711 loge("batch scan results just ended!"); 1712 if (mBatchedScanResults.size() > 0) { 1713 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1714 } 1715 return; 1716 } 1717 n = 0; 1718 } 1719 } 1720 } 1721 1722 private long mDisconnectedTimeStamp = 0; 1723 1724 public long getDisconnectedTimeMilli() { 1725 if (getCurrentState() == mDisconnectedState 1726 && mDisconnectedTimeStamp != 0) { 1727 long now_ms = System.currentTimeMillis(); 1728 return now_ms - mDisconnectedTimeStamp; 1729 } 1730 return 0; 1731 } 1732 1733 // Keeping track of scan requests 1734 private long lastStartScanTimeStamp = 0; 1735 private long lastScanDuration = 0; 1736 // Last connect attempt is used to prevent scan requests: 1737 // - for a period of 10 seconds after attempting to connect 1738 private long lastConnectAttempt = 0; 1739 private String lastScanFreqs = null; 1740 1741 // For debugging, keep track of last message status handling 1742 // TODO, find an equivalent mechanism as part of parent class 1743 private static int MESSAGE_HANDLING_STATUS_PROCESSED = 2; 1744 private static int MESSAGE_HANDLING_STATUS_OK = 1; 1745 private static int MESSAGE_HANDLING_STATUS_UNKNOWN = 0; 1746 private static int MESSAGE_HANDLING_STATUS_REFUSED = -1; 1747 private static int MESSAGE_HANDLING_STATUS_FAIL = -2; 1748 private static int MESSAGE_HANDLING_STATUS_OBSOLETE = -3; 1749 private static int MESSAGE_HANDLING_STATUS_DEFERRED = -4; 1750 private static int MESSAGE_HANDLING_STATUS_DISCARD = -5; 1751 private static int MESSAGE_HANDLING_STATUS_LOOPED = -6; 1752 private static int MESSAGE_HANDLING_STATUS_HANDLING_ERROR = -7; 1753 1754 private int messageHandlingStatus = 0; 1755 1756 //TODO: this is used only to track connection attempts, however the link state and packet per 1757 //TODO: second logic should be folded into that 1758 private boolean checkOrDeferScanAllowed(Message msg) { 1759 long now = System.currentTimeMillis(); 1760 if (lastConnectAttempt != 0 && (now - lastConnectAttempt) < 10000) { 1761 Message dmsg = Message.obtain(msg); 1762 sendMessageDelayed(dmsg, 11000 - (now - lastConnectAttempt)); 1763 return false; 1764 } 1765 return true; 1766 } 1767 1768 private int mOnTime = 0; 1769 private int mTxTime = 0; 1770 private int mRxTime = 0; 1771 private int mOnTimeStartScan = 0; 1772 private int mTxTimeStartScan = 0; 1773 private int mRxTimeStartScan = 0; 1774 private int mOnTimeScan = 0; 1775 private int mTxTimeScan = 0; 1776 private int mRxTimeScan = 0; 1777 private int mOnTimeThisScan = 0; 1778 private int mTxTimeThisScan = 0; 1779 private int mRxTimeThisScan = 0; 1780 1781 private int mOnTimeScreenStateChange = 0; 1782 private int mOnTimeAtLastReport = 0; 1783 private long lastOntimeReportTimeStamp = 0; 1784 private long lastScreenStateChangeTimeStamp = 0; 1785 private int mOnTimeLastReport = 0; 1786 private int mTxTimeLastReport = 0; 1787 private int mRxTimeLastReport = 0; 1788 1789 private long lastLinkLayerStatsUpdate = 0; 1790 1791 String reportOnTime() { 1792 long now = System.currentTimeMillis(); 1793 StringBuilder sb = new StringBuilder(); 1794 // Report stats since last report 1795 int on = mOnTime - mOnTimeLastReport; 1796 mOnTimeLastReport = mOnTime; 1797 int tx = mTxTime - mTxTimeLastReport; 1798 mTxTimeLastReport = mTxTime; 1799 int rx = mRxTime - mRxTimeLastReport; 1800 mRxTimeLastReport = mRxTime; 1801 int period = (int) (now - lastOntimeReportTimeStamp); 1802 lastOntimeReportTimeStamp = now; 1803 sb.append(String.format("[on:%d tx:%d rx:%d period:%d]", on, tx, rx, period)); 1804 // Report stats since Screen State Changed 1805 on = mOnTime - mOnTimeScreenStateChange; 1806 period = (int) (now - lastScreenStateChangeTimeStamp); 1807 sb.append(String.format(" from screen [on:%d period:%d]", on, period)); 1808 return sb.toString(); 1809 } 1810 1811 WifiLinkLayerStats getWifiLinkLayerStats(boolean dbg) { 1812 WifiLinkLayerStats stats = null; 1813 if (mWifiLinkLayerStatsSupported > 0) { 1814 String name = "wlan0"; 1815 stats = mWifiNative.getWifiLinkLayerStats(name); 1816 if (name != null && stats == null && mWifiLinkLayerStatsSupported > 0) { 1817 mWifiLinkLayerStatsSupported -= 1; 1818 } else if (stats != null) { 1819 lastLinkLayerStatsUpdate = System.currentTimeMillis(); 1820 mOnTime = stats.on_time; 1821 mTxTime = stats.tx_time; 1822 mRxTime = stats.rx_time; 1823 mRunningBeaconCount = stats.beacon_rx; 1824 if (dbg) { 1825 loge(stats.toString()); 1826 } 1827 } 1828 } 1829 if (stats == null || mWifiLinkLayerStatsSupported <= 0) { 1830 long mTxPkts = TrafficStats.getTxPackets(mInterfaceName); 1831 long mRxPkts = TrafficStats.getRxPackets(mInterfaceName); 1832 mWifiInfo.updatePacketRates(mTxPkts, mRxPkts); 1833 } else { 1834 mWifiInfo.updatePacketRates(stats); 1835 } 1836 return stats; 1837 } 1838 1839 void startRadioScanStats() { 1840 WifiLinkLayerStats stats = getWifiLinkLayerStats(false); 1841 if (stats != null) { 1842 mOnTimeStartScan = stats.on_time; 1843 mTxTimeStartScan = stats.tx_time; 1844 mRxTimeStartScan = stats.rx_time; 1845 mOnTime = stats.on_time; 1846 mTxTime = stats.tx_time; 1847 mRxTime = stats.rx_time; 1848 } 1849 } 1850 1851 void closeRadioScanStats() { 1852 WifiLinkLayerStats stats = getWifiLinkLayerStats(false); 1853 if (stats != null) { 1854 mOnTimeThisScan = stats.on_time - mOnTimeStartScan; 1855 mTxTimeThisScan = stats.tx_time - mTxTimeStartScan; 1856 mRxTimeThisScan = stats.rx_time - mRxTimeStartScan; 1857 mOnTimeScan += mOnTimeThisScan; 1858 mTxTimeScan += mTxTimeThisScan; 1859 mRxTimeScan += mRxTimeThisScan; 1860 } 1861 } 1862 1863 // If workSource is not null, blame is given to it, otherwise blame is given to callingUid. 1864 private void noteScanStart(int callingUid, WorkSource workSource) { 1865 long now = System.currentTimeMillis(); 1866 lastStartScanTimeStamp = now; 1867 lastScanDuration = 0; 1868 if (DBG) { 1869 String ts = String.format("[%,d ms]", now); 1870 if (workSource != null) { 1871 loge(ts + " noteScanStart" + workSource.toString() 1872 + " uid " + Integer.toString(callingUid)); 1873 } else { 1874 loge(ts + " noteScanstart no scan source" 1875 + " uid " + Integer.toString(callingUid)); 1876 } 1877 } 1878 startRadioScanStats(); 1879 if (mScanWorkSource == null && ((callingUid != UNKNOWN_SCAN_SOURCE 1880 && callingUid != SCAN_ALARM_SOURCE) 1881 || workSource != null)) { 1882 mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid); 1883 try { 1884 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource); 1885 } catch (RemoteException e) { 1886 log(e.toString()); 1887 } 1888 } 1889 } 1890 1891 private void noteScanEnd() { 1892 long now = System.currentTimeMillis(); 1893 if (lastStartScanTimeStamp != 0) { 1894 lastScanDuration = now - lastStartScanTimeStamp; 1895 } 1896 lastStartScanTimeStamp = 0; 1897 if (DBG) { 1898 String ts = String.format("[%,d ms]", now); 1899 if (mScanWorkSource != null) 1900 loge(ts + " noteScanEnd " + mScanWorkSource.toString() 1901 + " onTime=" + mOnTimeThisScan); 1902 else 1903 loge(ts + " noteScanEnd no scan source" 1904 + " onTime=" + mOnTimeThisScan); 1905 } 1906 if (mScanWorkSource != null) { 1907 try { 1908 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource); 1909 } catch (RemoteException e) { 1910 log(e.toString()); 1911 } finally { 1912 mScanWorkSource = null; 1913 } 1914 } 1915 } 1916 1917 private void noteBatchedScanStart() { 1918 if (PDBG) loge("noteBatchedScanstart()"); 1919 // note the end of a previous scan set 1920 if (mNotedBatchedScanWorkSource != null && 1921 (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false || 1922 mNotedBatchedScanCsph != mBatchedScanCsph)) { 1923 try { 1924 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1925 } catch (RemoteException e) { 1926 log(e.toString()); 1927 } finally { 1928 mNotedBatchedScanWorkSource = null; 1929 mNotedBatchedScanCsph = 0; 1930 } 1931 } 1932 // note the start of the new 1933 try { 1934 mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource, 1935 mBatchedScanCsph); 1936 mNotedBatchedScanWorkSource = mBatchedScanWorkSource; 1937 mNotedBatchedScanCsph = mBatchedScanCsph; 1938 } catch (RemoteException e) { 1939 log(e.toString()); 1940 } 1941 } 1942 1943 private void noteBatchedScanStop() { 1944 if (PDBG) loge("noteBatchedScanstop()"); 1945 1946 if (mNotedBatchedScanWorkSource != null) { 1947 try { 1948 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource); 1949 } catch (RemoteException e) { 1950 log(e.toString()); 1951 } finally { 1952 mNotedBatchedScanWorkSource = null; 1953 mNotedBatchedScanCsph = 0; 1954 } 1955 } 1956 } 1957 1958 private void handleScanRequest(int type, Message message) { 1959 ScanSettings settings = null; 1960 WorkSource workSource = null; 1961 1962 // unbundle parameters 1963 Bundle bundle = (Bundle) message.obj; 1964 1965 if (bundle != null) { 1966 settings = bundle.getParcelable(CUSTOMIZED_SCAN_SETTING); 1967 workSource = bundle.getParcelable(CUSTOMIZED_SCAN_WORKSOURCE); 1968 } 1969 1970 // parse scan settings 1971 String freqs = null; 1972 if (settings != null && settings.channelSet != null) { 1973 StringBuilder sb = new StringBuilder(); 1974 boolean first = true; 1975 for (WifiChannel channel : settings.channelSet) { 1976 if (!first) sb.append(','); 1977 else first = false; 1978 sb.append(channel.freqMHz); 1979 } 1980 freqs = sb.toString(); 1981 } 1982 1983 // call wifi native to start the scan 1984 if (startScanNative(type, freqs)) { 1985 // only count battery consumption if scan request is accepted 1986 noteScanStart(message.arg1, workSource); 1987 // a full scan covers everything, clearing scan request buffer 1988 if (freqs == null) 1989 mBufferedScanMsg.clear(); 1990 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK; 1991 if (workSource != null) { 1992 // External worksource was passed along the scan request, 1993 // hence always send a broadcast 1994 mSendScanResultsBroadcast = true; 1995 } 1996 return; 1997 } 1998 1999 // if reach here, scan request is rejected 2000 2001 if (!mIsScanOngoing) { 2002 // if rejection is NOT due to ongoing scan (e.g. bad scan parameters), 2003 2004 // discard this request and pop up the next one 2005 if (mBufferedScanMsg.size() > 0) { 2006 sendMessage(mBufferedScanMsg.remove()); 2007 } 2008 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 2009 } else if (!mIsFullScanOngoing) { 2010 // if rejection is due to an ongoing scan, and the ongoing one is NOT a full scan, 2011 // buffer the scan request to make sure specified channels will be scanned eventually 2012 if (freqs == null) 2013 mBufferedScanMsg.clear(); 2014 if (mBufferedScanMsg.size() < SCAN_REQUEST_BUFFER_MAX_SIZE) { 2015 Message msg = obtainMessage(CMD_START_SCAN, 2016 message.arg1, message.arg2, bundle); 2017 mBufferedScanMsg.add(msg); 2018 } else { 2019 // if too many requests in buffer, combine them into a single full scan 2020 bundle = new Bundle(); 2021 bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, null); 2022 bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource); 2023 Message msg = obtainMessage(CMD_START_SCAN, message.arg1, message.arg2, bundle); 2024 mBufferedScanMsg.clear(); 2025 mBufferedScanMsg.add(msg); 2026 } 2027 messageHandlingStatus = MESSAGE_HANDLING_STATUS_LOOPED; 2028 } else { 2029 // mIsScanOngoing and mIsFullScanOngoing 2030 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 2031 } 2032 } 2033 2034 2035 /** 2036 * return true iff scan request is accepted 2037 */ 2038 private boolean startScanNative(int type, String freqs) { 2039 if (mWifiNative.scan(type, freqs)) { 2040 mIsScanOngoing = true; 2041 mIsFullScanOngoing = (freqs == null); 2042 lastScanFreqs = freqs; 2043 return true; 2044 } 2045 return false; 2046 } 2047 2048 /** 2049 * TODO: doc 2050 */ 2051 public void setSupplicantRunning(boolean enable) { 2052 if (enable) { 2053 sendMessage(CMD_START_SUPPLICANT); 2054 } else { 2055 sendMessage(CMD_STOP_SUPPLICANT); 2056 } 2057 } 2058 2059 /** 2060 * TODO: doc 2061 */ 2062 public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) { 2063 if (enable) { 2064 sendMessage(CMD_START_AP, wifiConfig); 2065 } else { 2066 sendMessage(CMD_STOP_AP); 2067 } 2068 } 2069 2070 public void setWifiApConfiguration(WifiConfiguration config) { 2071 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 2072 } 2073 2074 public WifiConfiguration syncGetWifiApConfiguration() { 2075 Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG); 2076 WifiConfiguration ret = (WifiConfiguration) resultMsg.obj; 2077 resultMsg.recycle(); 2078 return ret; 2079 } 2080 2081 /** 2082 * TODO: doc 2083 */ 2084 public int syncGetWifiState() { 2085 return mWifiState.get(); 2086 } 2087 2088 /** 2089 * TODO: doc 2090 */ 2091 public String syncGetWifiStateByName() { 2092 switch (mWifiState.get()) { 2093 case WIFI_STATE_DISABLING: 2094 return "disabling"; 2095 case WIFI_STATE_DISABLED: 2096 return "disabled"; 2097 case WIFI_STATE_ENABLING: 2098 return "enabling"; 2099 case WIFI_STATE_ENABLED: 2100 return "enabled"; 2101 case WIFI_STATE_UNKNOWN: 2102 return "unknown state"; 2103 default: 2104 return "[invalid state]"; 2105 } 2106 } 2107 2108 /** 2109 * TODO: doc 2110 */ 2111 public int syncGetWifiApState() { 2112 return mWifiApState.get(); 2113 } 2114 2115 /** 2116 * TODO: doc 2117 */ 2118 public String syncGetWifiApStateByName() { 2119 switch (mWifiApState.get()) { 2120 case WIFI_AP_STATE_DISABLING: 2121 return "disabling"; 2122 case WIFI_AP_STATE_DISABLED: 2123 return "disabled"; 2124 case WIFI_AP_STATE_ENABLING: 2125 return "enabling"; 2126 case WIFI_AP_STATE_ENABLED: 2127 return "enabled"; 2128 case WIFI_AP_STATE_FAILED: 2129 return "failed"; 2130 default: 2131 return "[invalid state]"; 2132 } 2133 } 2134 2135 /** 2136 * Get status information for the current connection, if any. 2137 * 2138 * @return a {@link WifiInfo} object containing information about the current connection 2139 */ 2140 public WifiInfo syncRequestConnectionInfo() { 2141 return mWifiInfo; 2142 } 2143 2144 public DhcpResults syncGetDhcpResults() { 2145 synchronized (mDhcpResultsLock) { 2146 return new DhcpResults(mDhcpResults); 2147 } 2148 } 2149 2150 /** 2151 * TODO: doc 2152 */ 2153 public void setDriverStart(boolean enable) { 2154 if (enable) { 2155 sendMessage(CMD_START_DRIVER); 2156 } else { 2157 sendMessage(CMD_STOP_DRIVER); 2158 } 2159 } 2160 2161 /** 2162 * TODO: doc 2163 */ 2164 public void setOperationalMode(int mode) { 2165 if (DBG) log("setting operational mode to " + String.valueOf(mode)); 2166 sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0); 2167 } 2168 2169 /** 2170 * TODO: doc 2171 */ 2172 public List<ScanResult> syncGetScanResultsList() { 2173 synchronized (mScanResultCache) { 2174 List<ScanResult> scanList = new ArrayList<ScanResult>(); 2175 for (ScanDetail result : mScanResults) { 2176 scanList.add(new ScanResult(result.getScanResult())); 2177 } 2178 return scanList; 2179 } 2180 } 2181 2182 public void disableEphemeralNetwork(String SSID) { 2183 if (SSID != null) { 2184 sendMessage(CMD_DISABLE_EPHEMERAL_NETWORK, SSID); 2185 } 2186 } 2187 2188 /** 2189 * Get unsynchronized pointer to scan result list 2190 * Can be called only from AutoJoinController which runs in the WifiStateMachine context 2191 */ 2192 public List<ScanDetail> getScanResultsListNoCopyUnsync() { 2193 return mScanResults; 2194 } 2195 2196 /** 2197 * Disconnect from Access Point 2198 */ 2199 public void disconnectCommand() { 2200 sendMessage(CMD_DISCONNECT); 2201 } 2202 2203 public void disconnectCommand(int uid, int reason) { 2204 sendMessage(CMD_DISCONNECT, uid, reason); 2205 } 2206 2207 /** 2208 * Initiate a reconnection to AP 2209 */ 2210 public void reconnectCommand() { 2211 sendMessage(CMD_RECONNECT); 2212 } 2213 2214 /** 2215 * Initiate a re-association to AP 2216 */ 2217 public void reassociateCommand() { 2218 sendMessage(CMD_REASSOCIATE); 2219 } 2220 2221 /** 2222 * Reload networks and then reconnect; helps load correct data for TLS networks 2223 */ 2224 2225 public void reloadTlsNetworksAndReconnect() { 2226 sendMessage(CMD_RELOAD_TLS_AND_RECONNECT); 2227 } 2228 2229 /** 2230 * Add a network synchronously 2231 * 2232 * @return network id of the new network 2233 */ 2234 public int syncAddOrUpdateNetwork(AsyncChannel channel, WifiConfiguration config) { 2235 Message resultMsg = channel.sendMessageSynchronously(CMD_ADD_OR_UPDATE_NETWORK, config); 2236 int result = resultMsg.arg1; 2237 resultMsg.recycle(); 2238 return result; 2239 } 2240 2241 /** 2242 * Get configured networks synchronously 2243 * 2244 * @param channel 2245 * @return 2246 */ 2247 2248 public List<WifiConfiguration> syncGetConfiguredNetworks(int uuid, AsyncChannel channel) { 2249 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS, uuid); 2250 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 2251 resultMsg.recycle(); 2252 return result; 2253 } 2254 2255 public List<WifiConfiguration> syncGetPrivilegedConfiguredNetwork(AsyncChannel channel) { 2256 Message resultMsg = channel.sendMessageSynchronously( 2257 CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS); 2258 List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj; 2259 resultMsg.recycle(); 2260 return result; 2261 } 2262 2263 public WifiConfiguration syncGetMatchingWifiConfig(ScanResult scanResult, AsyncChannel channel) { 2264 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_MATCHING_CONFIG, scanResult); 2265 return (WifiConfiguration) resultMsg.obj; 2266 } 2267 2268 /** 2269 * Get connection statistics synchronously 2270 * 2271 * @param channel 2272 * @return 2273 */ 2274 2275 public WifiConnectionStatistics syncGetConnectionStatistics(AsyncChannel channel) { 2276 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONNECTION_STATISTICS); 2277 WifiConnectionStatistics result = (WifiConnectionStatistics) resultMsg.obj; 2278 resultMsg.recycle(); 2279 return result; 2280 } 2281 2282 /** 2283 * Get adaptors synchronously 2284 */ 2285 2286 public int syncGetSupportedFeatures(AsyncChannel channel) { 2287 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_SUPPORTED_FEATURES); 2288 int supportedFeatureSet = resultMsg.arg1; 2289 resultMsg.recycle(); 2290 return supportedFeatureSet; 2291 } 2292 2293 /** 2294 * Get link layers stats for adapter synchronously 2295 */ 2296 public WifiLinkLayerStats syncGetLinkLayerStats(AsyncChannel channel) { 2297 Message resultMsg = channel.sendMessageSynchronously(CMD_GET_LINK_LAYER_STATS); 2298 WifiLinkLayerStats result = (WifiLinkLayerStats) resultMsg.obj; 2299 resultMsg.recycle(); 2300 return result; 2301 } 2302 2303 /** 2304 * Delete a network 2305 * 2306 * @param networkId id of the network to be removed 2307 */ 2308 public boolean syncRemoveNetwork(AsyncChannel channel, int networkId) { 2309 Message resultMsg = channel.sendMessageSynchronously(CMD_REMOVE_NETWORK, networkId); 2310 boolean result = (resultMsg.arg1 != FAILURE); 2311 resultMsg.recycle(); 2312 return result; 2313 } 2314 2315 /** 2316 * Enable a network 2317 * 2318 * @param netId network id of the network 2319 * @param disableOthers true, if all other networks have to be disabled 2320 * @return {@code true} if the operation succeeds, {@code false} otherwise 2321 */ 2322 public boolean syncEnableNetwork(AsyncChannel channel, int netId, boolean disableOthers) { 2323 Message resultMsg = channel.sendMessageSynchronously(CMD_ENABLE_NETWORK, netId, 2324 disableOthers ? 1 : 0); 2325 boolean result = (resultMsg.arg1 != FAILURE); 2326 resultMsg.recycle(); 2327 return result; 2328 } 2329 2330 /** 2331 * Disable a network 2332 * 2333 * @param netId network id of the network 2334 * @return {@code true} if the operation succeeds, {@code false} otherwise 2335 */ 2336 public boolean syncDisableNetwork(AsyncChannel channel, int netId) { 2337 Message resultMsg = channel.sendMessageSynchronously(WifiManager.DISABLE_NETWORK, netId); 2338 boolean result = (resultMsg.arg1 != WifiManager.DISABLE_NETWORK_FAILED); 2339 resultMsg.recycle(); 2340 return result; 2341 } 2342 2343 /** 2344 * Retrieves a WPS-NFC configuration token for the specified network 2345 * 2346 * @return a hex string representation of the WPS-NFC configuration token 2347 */ 2348 public String syncGetWpsNfcConfigurationToken(int netId) { 2349 return mWifiNative.getNfcWpsConfigurationToken(netId); 2350 } 2351 2352 void enableBackgroundScan(boolean enable) { 2353 if (enable) { 2354 mWifiConfigStore.enableAllNetworks(); 2355 } 2356 mWifiNative.enableBackgroundScan(enable); 2357 } 2358 2359 /** 2360 * Blacklist a BSSID. This will avoid the AP if there are 2361 * alternate APs to connect 2362 * 2363 * @param bssid BSSID of the network 2364 */ 2365 public void addToBlacklist(String bssid) { 2366 sendMessage(CMD_BLACKLIST_NETWORK, bssid); 2367 } 2368 2369 /** 2370 * Clear the blacklist list 2371 */ 2372 public void clearBlacklist() { 2373 sendMessage(CMD_CLEAR_BLACKLIST); 2374 } 2375 2376 public void enableRssiPolling(boolean enabled) { 2377 sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0); 2378 } 2379 2380 public void enableAllNetworks() { 2381 sendMessage(CMD_ENABLE_ALL_NETWORKS); 2382 } 2383 2384 /** 2385 * Start filtering Multicast v4 packets 2386 */ 2387 public void startFilteringMulticastV4Packets() { 2388 mFilteringMulticastV4Packets.set(true); 2389 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0); 2390 } 2391 2392 /** 2393 * Stop filtering Multicast v4 packets 2394 */ 2395 public void stopFilteringMulticastV4Packets() { 2396 mFilteringMulticastV4Packets.set(false); 2397 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0); 2398 } 2399 2400 /** 2401 * Start filtering Multicast v4 packets 2402 */ 2403 public void startFilteringMulticastV6Packets() { 2404 sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0); 2405 } 2406 2407 /** 2408 * Stop filtering Multicast v4 packets 2409 */ 2410 public void stopFilteringMulticastV6Packets() { 2411 sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0); 2412 } 2413 2414 /** 2415 * Set high performance mode of operation. 2416 * Enabling would set active power mode and disable suspend optimizations; 2417 * disabling would set auto power mode and enable suspend optimizations 2418 * 2419 * @param enable true if enable, false otherwise 2420 */ 2421 public void setHighPerfModeEnabled(boolean enable) { 2422 sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0); 2423 } 2424 2425 /** 2426 * Set the country code 2427 * 2428 * @param countryCode following ISO 3166 format 2429 * @param persist {@code true} if the setting should be remembered. 2430 */ 2431 public synchronized void setCountryCode(String countryCode, boolean persist) { 2432 // If it's a good country code, apply after the current 2433 // wifi connection is terminated; ignore resetting of code 2434 // for now (it is unclear what the chipset should do when 2435 // country code is reset) 2436 2437 if (TextUtils.isEmpty(countryCode)) { 2438 log("Ignoring resetting of country code"); 2439 } else { 2440 // if mCountryCodeSequence == 0, it is the first time to set country code, always set 2441 // else only when the new country code is different from the current one to set 2442 int countryCodeSequence = mCountryCodeSequence.get(); 2443 if (countryCodeSequence == 0 || countryCode.equals(mSetCountryCode) == false) { 2444 2445 countryCodeSequence = mCountryCodeSequence.incrementAndGet(); 2446 mSetCountryCode = countryCode; 2447 sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, 2448 countryCode); 2449 } 2450 2451 if (persist) { 2452 Settings.Global.putString(mContext.getContentResolver(), 2453 Settings.Global.WIFI_COUNTRY_CODE, 2454 countryCode); 2455 } 2456 } 2457 } 2458 2459 /** 2460 * Get the country code 2461 * 2462 * @param countryCode following ISO 3166 format 2463 */ 2464 public String getCountryCode() { 2465 return mSetCountryCode; 2466 } 2467 2468 2469 /** 2470 * Set the operational frequency band 2471 * 2472 * @param band 2473 * @param persist {@code true} if the setting should be remembered. 2474 */ 2475 public void setFrequencyBand(int band, boolean persist) { 2476 if (persist) { 2477 Settings.Global.putInt(mContext.getContentResolver(), 2478 Settings.Global.WIFI_FREQUENCY_BAND, 2479 band); 2480 } 2481 sendMessage(CMD_SET_FREQUENCY_BAND, band, 0); 2482 } 2483 2484 /** 2485 * Enable TDLS for a specific MAC address 2486 */ 2487 public void enableTdls(String remoteMacAddress, boolean enable) { 2488 int enabler = enable ? 1 : 0; 2489 sendMessage(CMD_ENABLE_TDLS, enabler, 0, remoteMacAddress); 2490 } 2491 2492 /** 2493 * Returns the operational frequency band 2494 */ 2495 public int getFrequencyBand() { 2496 return mFrequencyBand.get(); 2497 } 2498 2499 /** 2500 * Returns the wifi configuration file 2501 */ 2502 public String getConfigFile() { 2503 return mWifiConfigStore.getConfigFile(); 2504 } 2505 2506 /** 2507 * Send a message indicating bluetooth adapter connection state changed 2508 */ 2509 public void sendBluetoothAdapterStateChange(int state) { 2510 sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0); 2511 } 2512 2513 /** 2514 * Save configuration on supplicant 2515 * 2516 * @return {@code true} if the operation succeeds, {@code false} otherwise 2517 * <p/> 2518 * TODO: deprecate this 2519 */ 2520 public boolean syncSaveConfig(AsyncChannel channel) { 2521 Message resultMsg = channel.sendMessageSynchronously(CMD_SAVE_CONFIG); 2522 boolean result = (resultMsg.arg1 != FAILURE); 2523 resultMsg.recycle(); 2524 return result; 2525 } 2526 2527 public void updateBatteryWorkSource(WorkSource newSource) { 2528 synchronized (mRunningWifiUids) { 2529 try { 2530 if (newSource != null) { 2531 mRunningWifiUids.set(newSource); 2532 } 2533 if (mIsRunning) { 2534 if (mReportedRunning) { 2535 // If the work source has changed since last time, need 2536 // to remove old work from battery stats. 2537 if (mLastRunningWifiUids.diff(mRunningWifiUids)) { 2538 mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids, 2539 mRunningWifiUids); 2540 mLastRunningWifiUids.set(mRunningWifiUids); 2541 } 2542 } else { 2543 // Now being started, report it. 2544 mBatteryStats.noteWifiRunning(mRunningWifiUids); 2545 mLastRunningWifiUids.set(mRunningWifiUids); 2546 mReportedRunning = true; 2547 } 2548 } else { 2549 if (mReportedRunning) { 2550 // Last reported we were running, time to stop. 2551 mBatteryStats.noteWifiStopped(mLastRunningWifiUids); 2552 mLastRunningWifiUids.clear(); 2553 mReportedRunning = false; 2554 } 2555 } 2556 mWakeLock.setWorkSource(newSource); 2557 } catch (RemoteException ignore) { 2558 } 2559 } 2560 } 2561 2562 @Override 2563 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2564 super.dump(fd, pw, args); 2565 mSupplicantStateTracker.dump(fd, pw, args); 2566 pw.println("mLinkProperties " + mLinkProperties); 2567 pw.println("mWifiInfo " + mWifiInfo); 2568 pw.println("mDhcpResults " + mDhcpResults); 2569 pw.println("mNetworkInfo " + mNetworkInfo); 2570 pw.println("mLastSignalLevel " + mLastSignalLevel); 2571 pw.println("mLastBssid " + mLastBssid); 2572 pw.println("mLastNetworkId " + mLastNetworkId); 2573 pw.println("mOperationalMode " + mOperationalMode); 2574 pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt); 2575 pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 2576 pw.println("Supplicant status " + mWifiNative.status(true)); 2577 pw.println("mEnableBackgroundScan " + mEnableBackgroundScan); 2578 pw.println("mSetCountryCode " + mSetCountryCode); 2579 pw.println("mDriverSetCountryCode " + mDriverSetCountryCode); 2580 mNetworkFactory.dump(fd, pw, args); 2581 mUntrustedNetworkFactory.dump(fd, pw, args); 2582 pw.println(); 2583 mWifiConfigStore.dump(fd, pw, args); 2584 } 2585 2586 /** 2587 * ****************************************************** 2588 * Internal private functions 2589 * ****************************************************** 2590 */ 2591 2592 private void logStateAndMessage(Message message, String state) { 2593 messageHandlingStatus = 0; 2594 if (mLogMessages) { 2595 //long now = SystemClock.elapsedRealtimeNanos(); 2596 //String ts = String.format("[%,d us]", now/1000); 2597 2598 loge(" " + state + " " + getLogRecString(message)); 2599 } 2600 } 2601 2602 /** 2603 * helper, prints the milli time since boot wi and w/o suspended time 2604 */ 2605 String printTime() { 2606 StringBuilder sb = new StringBuilder(); 2607 sb.append(" rt=").append(SystemClock.uptimeMillis()); 2608 sb.append("/").append(SystemClock.elapsedRealtime()); 2609 return sb.toString(); 2610 } 2611 2612 /** 2613 * Return the additional string to be logged by LogRec, default 2614 * 2615 * @param msg that was processed 2616 * @return information to be logged as a String 2617 */ 2618 protected String getLogRecString(Message msg) { 2619 WifiConfiguration config; 2620 Long now; 2621 String report; 2622 String key; 2623 StringBuilder sb = new StringBuilder(); 2624 if (mScreenOn) { 2625 sb.append("!"); 2626 } 2627 if (messageHandlingStatus != MESSAGE_HANDLING_STATUS_UNKNOWN) { 2628 sb.append("(").append(messageHandlingStatus).append(")"); 2629 } 2630 sb.append(smToString(msg)); 2631 if (msg.sendingUid > 0 && msg.sendingUid != Process.WIFI_UID) { 2632 sb.append(" uid=" + msg.sendingUid); 2633 } 2634 switch (msg.what) { 2635 case CMD_STARTED_PNO_DBG: 2636 sb.append(" "); 2637 sb.append(Integer.toString(msg.arg1)); 2638 sb.append(" "); 2639 sb.append(Integer.toString(msg.arg2)); 2640 if (msg.obj != null) { 2641 sb.append((String)msg.obj); 2642 } 2643 break; 2644 case CMD_PNO_NETWORK_FOUND: 2645 sb.append(" "); 2646 sb.append(Integer.toString(msg.arg1)); 2647 sb.append(" "); 2648 sb.append(Integer.toString(msg.arg2)); 2649 if (msg.obj != null) { 2650 ScanResult[] results = (ScanResult[])msg.obj; 2651 for (int i = 0; i < results.length; i++) { 2652 sb.append(" ").append(results[i].SSID).append(" "); 2653 sb.append(results[i].frequency); 2654 sb.append(" ").append(results[i].level); 2655 } 2656 } 2657 break; 2658 case CMD_START_SCAN: 2659 now = System.currentTimeMillis(); 2660 sb.append(" "); 2661 sb.append(Integer.toString(msg.arg1)); 2662 sb.append(" "); 2663 sb.append(Integer.toString(msg.arg2)); 2664 sb.append(" ic="); 2665 sb.append(Integer.toString(sScanAlarmIntentCount)); 2666 if (msg.obj != null) { 2667 Bundle bundle = (Bundle) msg.obj; 2668 Long request = bundle.getLong(SCAN_REQUEST_TIME, 0); 2669 if (request != 0) { 2670 sb.append(" proc(ms):").append(now - request); 2671 } 2672 } 2673 if (mIsScanOngoing) sb.append(" onGoing"); 2674 if (mIsFullScanOngoing) sb.append(" full"); 2675 if (lastStartScanTimeStamp != 0) { 2676 sb.append(" started:").append(lastStartScanTimeStamp); 2677 sb.append(",").append(now - lastStartScanTimeStamp); 2678 } 2679 if (lastScanDuration != 0) { 2680 sb.append(" dur:").append(lastScanDuration); 2681 } 2682 sb.append(" cnt=").append(mDelayedScanCounter); 2683 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2684 sb.append(" f=").append(mWifiInfo.getFrequency()); 2685 sb.append(" sc=").append(mWifiInfo.score); 2686 sb.append(" link=").append(mWifiInfo.getLinkSpeed()); 2687 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate)); 2688 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate)); 2689 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate)); 2690 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate)); 2691 if (lastScanFreqs != null) { 2692 sb.append(" list=").append(lastScanFreqs); 2693 } else { 2694 sb.append(" fiv=").append(fullBandConnectedTimeIntervalMilli); 2695 } 2696 report = reportOnTime(); 2697 if (report != null) { 2698 sb.append(" ").append(report); 2699 } 2700 break; 2701 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 2702 sb.append(" "); 2703 sb.append(Integer.toString(msg.arg1)); 2704 sb.append(" "); 2705 sb.append(Integer.toString(msg.arg2)); 2706 sb.append(printTime()); 2707 StateChangeResult stateChangeResult = (StateChangeResult) msg.obj; 2708 if (stateChangeResult != null) { 2709 sb.append(stateChangeResult.toString()); 2710 } 2711 break; 2712 case WifiManager.SAVE_NETWORK: 2713 case WifiStateMachine.CMD_AUTO_SAVE_NETWORK: 2714 sb.append(" "); 2715 sb.append(Integer.toString(msg.arg1)); 2716 sb.append(" "); 2717 sb.append(Integer.toString(msg.arg2)); 2718 if (lastSavedConfigurationAttempt != null) { 2719 sb.append(" ").append(lastSavedConfigurationAttempt.configKey()); 2720 sb.append(" nid=").append(lastSavedConfigurationAttempt.networkId); 2721 if (lastSavedConfigurationAttempt.hiddenSSID) { 2722 sb.append(" hidden"); 2723 } 2724 if (lastSavedConfigurationAttempt.preSharedKey != null 2725 && !lastSavedConfigurationAttempt.preSharedKey.equals("*")) { 2726 sb.append(" hasPSK"); 2727 } 2728 if (lastSavedConfigurationAttempt.ephemeral) { 2729 sb.append(" ephemeral"); 2730 } 2731 if (lastSavedConfigurationAttempt.selfAdded) { 2732 sb.append(" selfAdded"); 2733 } 2734 sb.append(" cuid=").append(lastSavedConfigurationAttempt.creatorUid); 2735 sb.append(" suid=").append(lastSavedConfigurationAttempt.lastUpdateUid); 2736 } 2737 break; 2738 case WifiManager.FORGET_NETWORK: 2739 sb.append(" "); 2740 sb.append(Integer.toString(msg.arg1)); 2741 sb.append(" "); 2742 sb.append(Integer.toString(msg.arg2)); 2743 if (lastForgetConfigurationAttempt != null) { 2744 sb.append(" ").append(lastForgetConfigurationAttempt.configKey()); 2745 sb.append(" nid=").append(lastForgetConfigurationAttempt.networkId); 2746 if (lastForgetConfigurationAttempt.hiddenSSID) { 2747 sb.append(" hidden"); 2748 } 2749 if (lastForgetConfigurationAttempt.preSharedKey != null) { 2750 sb.append(" hasPSK"); 2751 } 2752 if (lastForgetConfigurationAttempt.ephemeral) { 2753 sb.append(" ephemeral"); 2754 } 2755 if (lastForgetConfigurationAttempt.selfAdded) { 2756 sb.append(" selfAdded"); 2757 } 2758 sb.append(" cuid=").append(lastForgetConfigurationAttempt.creatorUid); 2759 sb.append(" suid=").append(lastForgetConfigurationAttempt.lastUpdateUid); 2760 sb.append(" ajst=").append(lastForgetConfigurationAttempt.autoJoinStatus); 2761 } 2762 break; 2763 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 2764 sb.append(" "); 2765 sb.append(Integer.toString(msg.arg1)); 2766 sb.append(" "); 2767 sb.append(Integer.toString(msg.arg2)); 2768 String bssid = (String) msg.obj; 2769 if (bssid != null && bssid.length() > 0) { 2770 sb.append(" "); 2771 sb.append(bssid); 2772 } 2773 sb.append(" blacklist=" + Boolean.toString(didBlackListBSSID)); 2774 sb.append(printTime()); 2775 break; 2776 case WifiMonitor.SCAN_RESULTS_EVENT: 2777 sb.append(" "); 2778 sb.append(Integer.toString(msg.arg1)); 2779 sb.append(" "); 2780 sb.append(Integer.toString(msg.arg2)); 2781 if (mScanResults != null) { 2782 sb.append(" found="); 2783 sb.append(mScanResults.size()); 2784 } 2785 sb.append(" known=").append(mNumScanResultsKnown); 2786 sb.append(" got=").append(mNumScanResultsReturned); 2787 if (lastScanDuration != 0) { 2788 sb.append(" dur:").append(lastScanDuration); 2789 } 2790 if (mOnTime != 0) { 2791 sb.append(" on:").append(mOnTimeThisScan).append(",").append(mOnTimeScan); 2792 sb.append(",").append(mOnTime); 2793 } 2794 if (mTxTime != 0) { 2795 sb.append(" tx:").append(mTxTimeThisScan).append(",").append(mTxTimeScan); 2796 sb.append(",").append(mTxTime); 2797 } 2798 if (mRxTime != 0) { 2799 sb.append(" rx:").append(mRxTimeThisScan).append(",").append(mRxTimeScan); 2800 sb.append(",").append(mRxTime); 2801 } 2802 sb.append(String.format(" bcn=%d", mRunningBeaconCount)); 2803 sb.append(String.format(" con=%d", mConnectionRequests)); 2804 key = mWifiConfigStore.getLastSelectedConfiguration(); 2805 if (key != null) { 2806 sb.append(" last=").append(key); 2807 } 2808 break; 2809 case WifiMonitor.NETWORK_CONNECTION_EVENT: 2810 sb.append(" "); 2811 sb.append(Integer.toString(msg.arg1)); 2812 sb.append(" "); 2813 sb.append(Integer.toString(msg.arg2)); 2814 sb.append(" ").append(mLastBssid); 2815 sb.append(" nid=").append(mLastNetworkId); 2816 config = getCurrentWifiConfiguration(); 2817 if (config != null) { 2818 sb.append(" ").append(config.configKey()); 2819 } 2820 sb.append(printTime()); 2821 key = mWifiConfigStore.getLastSelectedConfiguration(); 2822 if (key != null) { 2823 sb.append(" last=").append(key); 2824 } 2825 break; 2826 case CMD_TARGET_BSSID: 2827 case CMD_ASSOCIATED_BSSID: 2828 sb.append(" "); 2829 sb.append(Integer.toString(msg.arg1)); 2830 sb.append(" "); 2831 sb.append(Integer.toString(msg.arg2)); 2832 if (msg.obj != null) { 2833 sb.append(" BSSID=").append((String) msg.obj); 2834 } 2835 if (mTargetRoamBSSID != null) { 2836 sb.append(" Target=").append(mTargetRoamBSSID); 2837 } 2838 sb.append(" roam=").append(Integer.toString(mAutoRoaming)); 2839 sb.append(printTime()); 2840 break; 2841 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 2842 if (msg.obj != null) { 2843 sb.append(" ").append((String) msg.obj); 2844 } 2845 sb.append(" nid=").append(msg.arg1); 2846 sb.append(" reason=").append(msg.arg2); 2847 if (mLastBssid != null) { 2848 sb.append(" lastbssid=").append(mLastBssid); 2849 } 2850 if (mWifiInfo.getFrequency() != -1) { 2851 sb.append(" freq=").append(mWifiInfo.getFrequency()); 2852 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2853 } 2854 if (linkDebouncing) { 2855 sb.append(" debounce"); 2856 } 2857 sb.append(printTime()); 2858 break; 2859 case WifiMonitor.SSID_TEMP_DISABLED: 2860 case WifiMonitor.SSID_REENABLED: 2861 sb.append(" nid=").append(msg.arg1); 2862 if (msg.obj != null) { 2863 sb.append(" ").append((String) msg.obj); 2864 } 2865 config = getCurrentWifiConfiguration(); 2866 if (config != null) { 2867 sb.append(" cur=").append(config.configKey()); 2868 sb.append(" ajst=").append(config.autoJoinStatus); 2869 if (config.selfAdded) { 2870 sb.append(" selfAdded"); 2871 } 2872 if (config.status != 0) { 2873 sb.append(" st=").append(config.status); 2874 sb.append(" rs=").append(config.disableReason); 2875 } 2876 if (config.lastConnected != 0) { 2877 now = System.currentTimeMillis(); 2878 sb.append(" lastconn=").append(now - config.lastConnected).append("(ms)"); 2879 } 2880 if (mLastBssid != null) { 2881 sb.append(" lastbssid=").append(mLastBssid); 2882 } 2883 if (mWifiInfo.getFrequency() != -1) { 2884 sb.append(" freq=").append(mWifiInfo.getFrequency()); 2885 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2886 sb.append(" bssid=").append(mWifiInfo.getBSSID()); 2887 } 2888 } 2889 sb.append(printTime()); 2890 break; 2891 case CMD_RSSI_POLL: 2892 case CMD_UNWANTED_NETWORK: 2893 case WifiManager.RSSI_PKTCNT_FETCH: 2894 sb.append(" "); 2895 sb.append(Integer.toString(msg.arg1)); 2896 sb.append(" "); 2897 sb.append(Integer.toString(msg.arg2)); 2898 if (mWifiInfo.getSSID() != null) 2899 if (mWifiInfo.getSSID() != null) 2900 sb.append(" ").append(mWifiInfo.getSSID()); 2901 if (mWifiInfo.getBSSID() != null) 2902 sb.append(" ").append(mWifiInfo.getBSSID()); 2903 sb.append(" rssi=").append(mWifiInfo.getRssi()); 2904 sb.append(" f=").append(mWifiInfo.getFrequency()); 2905 sb.append(" sc=").append(mWifiInfo.score); 2906 sb.append(" link=").append(mWifiInfo.getLinkSpeed()); 2907 sb.append(String.format(" tx=%.1f,", mWifiInfo.txSuccessRate)); 2908 sb.append(String.format(" %.1f,", mWifiInfo.txRetriesRate)); 2909 sb.append(String.format(" %.1f ", mWifiInfo.txBadRate)); 2910 sb.append(String.format(" rx=%.1f", mWifiInfo.rxSuccessRate)); 2911 sb.append(String.format(" bcn=%d", mRunningBeaconCount)); 2912 report = reportOnTime(); 2913 if (report != null) { 2914 sb.append(" ").append(report); 2915 } 2916 if (wifiScoringReport != null) { 2917 sb.append(wifiScoringReport); 2918 } 2919 break; 2920 case CMD_AUTO_CONNECT: 2921 case WifiManager.CONNECT_NETWORK: 2922 sb.append(" "); 2923 sb.append(Integer.toString(msg.arg1)); 2924 sb.append(" "); 2925 sb.append(Integer.toString(msg.arg2)); 2926 config = (WifiConfiguration) msg.obj; 2927 if (config != null) { 2928 sb.append(" ").append(config.configKey()); 2929 if (config.visibility != null) { 2930 sb.append(" ").append(config.visibility.toString()); 2931 } 2932 } 2933 if (mTargetRoamBSSID != null) { 2934 sb.append(" ").append(mTargetRoamBSSID); 2935 } 2936 sb.append(" roam=").append(Integer.toString(mAutoRoaming)); 2937 sb.append(printTime()); 2938 config = getCurrentWifiConfiguration(); 2939 if (config != null) { 2940 sb.append(config.configKey()); 2941 if (config.visibility != null) { 2942 sb.append(" ").append(config.visibility.toString()); 2943 } 2944 } 2945 break; 2946 case CMD_AUTO_ROAM: 2947 sb.append(" "); 2948 sb.append(Integer.toString(msg.arg1)); 2949 sb.append(" "); 2950 sb.append(Integer.toString(msg.arg2)); 2951 ScanResult result = (ScanResult) msg.obj; 2952 if (result != null) { 2953 now = System.currentTimeMillis(); 2954 sb.append(" bssid=").append(result.BSSID); 2955 sb.append(" rssi=").append(result.level); 2956 sb.append(" freq=").append(result.frequency); 2957 if (result.seen > 0 && result.seen < now) { 2958 sb.append(" seen=").append(now - result.seen); 2959 } else { 2960 // Somehow the timestamp for this scan result is inconsistent 2961 sb.append(" !seen=").append(result.seen); 2962 } 2963 } 2964 if (mTargetRoamBSSID != null) { 2965 sb.append(" ").append(mTargetRoamBSSID); 2966 } 2967 sb.append(" roam=").append(Integer.toString(mAutoRoaming)); 2968 sb.append(" fail count=").append(Integer.toString(mRoamFailCount)); 2969 sb.append(printTime()); 2970 break; 2971 case CMD_ADD_OR_UPDATE_NETWORK: 2972 sb.append(" "); 2973 sb.append(Integer.toString(msg.arg1)); 2974 sb.append(" "); 2975 sb.append(Integer.toString(msg.arg2)); 2976 if (msg.obj != null) { 2977 config = (WifiConfiguration) msg.obj; 2978 sb.append(" ").append(config.configKey()); 2979 sb.append(" prio=").append(config.priority); 2980 sb.append(" status=").append(config.status); 2981 if (config.BSSID != null) { 2982 sb.append(" ").append(config.BSSID); 2983 } 2984 WifiConfiguration curConfig = getCurrentWifiConfiguration(); 2985 if (curConfig != null) { 2986 if (curConfig.configKey().equals(config.configKey())) { 2987 sb.append(" is current"); 2988 } else { 2989 sb.append(" current=").append(curConfig.configKey()); 2990 sb.append(" prio=").append(curConfig.priority); 2991 sb.append(" status=").append(curConfig.status); 2992 } 2993 } 2994 } 2995 break; 2996 case WifiManager.DISABLE_NETWORK: 2997 case CMD_ENABLE_NETWORK: 2998 sb.append(" "); 2999 sb.append(Integer.toString(msg.arg1)); 3000 sb.append(" "); 3001 sb.append(Integer.toString(msg.arg2)); 3002 key = mWifiConfigStore.getLastSelectedConfiguration(); 3003 if (key != null) { 3004 sb.append(" last=").append(key); 3005 } 3006 config = mWifiConfigStore.getWifiConfiguration(msg.arg1); 3007 if (config != null && (key == null || !config.configKey().equals(key))) { 3008 sb.append(" target=").append(key); 3009 } 3010 break; 3011 case CMD_GET_CONFIGURED_NETWORKS: 3012 sb.append(" "); 3013 sb.append(Integer.toString(msg.arg1)); 3014 sb.append(" "); 3015 sb.append(Integer.toString(msg.arg2)); 3016 sb.append(" num=").append(mWifiConfigStore.getConfiguredNetworksSize()); 3017 break; 3018 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 3019 sb.append(" "); 3020 sb.append(Integer.toString(msg.arg1)); 3021 sb.append(" "); 3022 sb.append(Integer.toString(msg.arg2)); 3023 sb.append(" txpkts=").append(mWifiInfo.txSuccess); 3024 sb.append(",").append(mWifiInfo.txBad); 3025 sb.append(",").append(mWifiInfo.txRetries); 3026 break; 3027 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 3028 sb.append(" "); 3029 sb.append(Integer.toString(msg.arg1)); 3030 sb.append(" "); 3031 sb.append(Integer.toString(msg.arg2)); 3032 if (msg.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 3033 sb.append(" OK "); 3034 } else if (msg.arg1 == DhcpStateMachine.DHCP_FAILURE) { 3035 sb.append(" FAIL "); 3036 } 3037 if (mLinkProperties != null) { 3038 if (mLinkProperties.hasIPv4Address()) { 3039 sb.append(" v4"); 3040 } 3041 if (mLinkProperties.hasGlobalIPv6Address()) { 3042 sb.append(" v6"); 3043 } 3044 if (mLinkProperties.hasIPv4DefaultRoute()) { 3045 sb.append(" v4r"); 3046 } 3047 if (mLinkProperties.hasIPv6DefaultRoute()) { 3048 sb.append(" v6r"); 3049 } 3050 if (mLinkProperties.hasIPv4DnsServer()) { 3051 sb.append(" v4dns"); 3052 } 3053 if (mLinkProperties.hasIPv6DnsServer()) { 3054 sb.append(" v6dns"); 3055 } 3056 } 3057 break; 3058 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 3059 sb.append(" "); 3060 sb.append(Integer.toString(msg.arg1)); 3061 sb.append(" "); 3062 sb.append(Integer.toString(msg.arg2)); 3063 if (msg.obj != null) { 3064 NetworkInfo info = (NetworkInfo) msg.obj; 3065 NetworkInfo.State state = info.getState(); 3066 NetworkInfo.DetailedState detailedState = info.getDetailedState(); 3067 if (state != null) { 3068 sb.append(" st=").append(state); 3069 } 3070 if (detailedState != null) { 3071 sb.append("/").append(detailedState); 3072 } 3073 } 3074 break; 3075 case CMD_IP_CONFIGURATION_LOST: 3076 int count = -1; 3077 WifiConfiguration c = getCurrentWifiConfiguration(); 3078 if (c != null) count = c.numIpConfigFailures; 3079 sb.append(" "); 3080 sb.append(Integer.toString(msg.arg1)); 3081 sb.append(" "); 3082 sb.append(Integer.toString(msg.arg2)); 3083 sb.append(" failures: "); 3084 sb.append(Integer.toString(count)); 3085 sb.append("/"); 3086 sb.append(Integer.toString(mWifiConfigStore.getMaxDhcpRetries())); 3087 if (mWifiInfo.getBSSID() != null) { 3088 sb.append(" ").append(mWifiInfo.getBSSID()); 3089 } 3090 if (c != null) { 3091 ScanDetailCache scanDetailCache = 3092 mWifiConfigStore.getScanDetailCache(c); 3093 if (scanDetailCache != null) { 3094 for (ScanDetail sd : scanDetailCache.values()) { 3095 ScanResult r = sd.getScanResult(); 3096 if (r.BSSID.equals(mWifiInfo.getBSSID())) { 3097 sb.append(" ipfail=").append(r.numIpConfigFailures); 3098 sb.append(",st=").append(r.autoJoinStatus); 3099 } 3100 } 3101 } 3102 sb.append(" -> ajst=").append(c.autoJoinStatus); 3103 sb.append(" ").append(c.disableReason); 3104 sb.append(" txpkts=").append(mWifiInfo.txSuccess); 3105 sb.append(",").append(mWifiInfo.txBad); 3106 sb.append(",").append(mWifiInfo.txRetries); 3107 } 3108 sb.append(printTime()); 3109 sb.append(String.format(" bcn=%d", mRunningBeaconCount)); 3110 break; 3111 case CMD_UPDATE_LINKPROPERTIES: 3112 sb.append(" "); 3113 sb.append(Integer.toString(msg.arg1)); 3114 sb.append(" "); 3115 sb.append(Integer.toString(msg.arg2)); 3116 if (mLinkProperties != null) { 3117 if (mLinkProperties.hasIPv4Address()) { 3118 sb.append(" v4"); 3119 } 3120 if (mLinkProperties.hasGlobalIPv6Address()) { 3121 sb.append(" v6"); 3122 } 3123 if (mLinkProperties.hasIPv4DefaultRoute()) { 3124 sb.append(" v4r"); 3125 } 3126 if (mLinkProperties.hasIPv6DefaultRoute()) { 3127 sb.append(" v6r"); 3128 } 3129 if (mLinkProperties.hasIPv4DnsServer()) { 3130 sb.append(" v4dns"); 3131 } 3132 if (mLinkProperties.hasIPv6DnsServer()) { 3133 sb.append(" v6dns"); 3134 } 3135 } 3136 break; 3137 case CMD_SET_COUNTRY_CODE: 3138 sb.append(" "); 3139 sb.append(Integer.toString(msg.arg1)); 3140 sb.append(" "); 3141 sb.append(Integer.toString(msg.arg2)); 3142 if (msg.obj != null) { 3143 sb.append(" ").append((String) msg.obj); 3144 } 3145 break; 3146 case CMD_ROAM_WATCHDOG_TIMER: 3147 sb.append(" "); 3148 sb.append(Integer.toString(msg.arg1)); 3149 sb.append(" "); 3150 sb.append(Integer.toString(msg.arg2)); 3151 sb.append(" cur=").append(roamWatchdogCount); 3152 break; 3153 case CMD_DISCONNECTING_WATCHDOG_TIMER: 3154 sb.append(" "); 3155 sb.append(Integer.toString(msg.arg1)); 3156 sb.append(" "); 3157 sb.append(Integer.toString(msg.arg2)); 3158 sb.append(" cur=").append(disconnectingWatchdogCount); 3159 break; 3160 default: 3161 sb.append(" "); 3162 sb.append(Integer.toString(msg.arg1)); 3163 sb.append(" "); 3164 sb.append(Integer.toString(msg.arg2)); 3165 break; 3166 } 3167 3168 return sb.toString(); 3169 } 3170 3171 private void stopPno() { 3172 3173 // Stop PNO scans while we are trying to associate 3174 mWifiScanner.stopBackgroundScan(mWifiScanListener); 3175 3176 // clear the PNO list 3177 if (!WifiNative.setPnoList(null, WifiStateMachine.this)) { 3178 Log.e(TAG, "Failed to stop pno"); 3179 } 3180 3181 } 3182 3183 private boolean startPno() { 3184 if (!mAlwaysOnPnoSupported || (!mWifiConfigStore.enableHalBasedPno.get())) return false; 3185 3186 /* 3187 if (mWifiScannerChannel == null) { 3188 log("startPno: mWifiScannerChannel is null "); 3189 return false; 3190 }*/ 3191 if (mWifiScanner == null) { 3192 log("startPno: mWifiScanner is null "); 3193 return true; 3194 } 3195 3196 List<WifiNative.WifiPnoNetwork> llist 3197 = mWifiAutoJoinController.getPnoList(getCurrentWifiConfiguration()); 3198 if (llist != null) { 3199 log("startPno: got llist size " + llist.size()); 3200 3201 // first program the network we want to look for thru the pno API 3202 WifiNative.WifiPnoNetwork list[] 3203 = (WifiNative.WifiPnoNetwork[]) llist.toArray(new WifiNative.WifiPnoNetwork[0]); 3204 3205 if (!WifiNative.setPnoList(list, WifiStateMachine.this)) { 3206 Log.e(TAG, "Failed to set pno, length = " + list.length); 3207 } 3208 3209 // then send a scan background request so as firmware 3210 // starts looking for our networks 3211 WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings(); 3212 settings.band = WifiScanner.WIFI_BAND_BOTH; 3213 3214 // TODO, fix the scan interval logic 3215 if (mScreenOn) 3216 settings.periodInMs = mDefaultFrameworkScanIntervalMs; 3217 else 3218 settings.periodInMs = mWifiConfigStore.wifiDisconnectedScanIntervalMs.get(); 3219 3220 settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL; 3221 log("startPno: settings BOTH_BANDS, length = " + list.length); 3222 3223 mWifiScanner.startBackgroundScan(settings, mWifiScanListener); 3224// mWifiScannerChannel.sendMessage 3225// (WifiScanner.CMD_START_BACKGROUND_SCAN, settings); 3226 if (DBG) { 3227 StringBuilder sb = new StringBuilder(); 3228 sb.append(" list: "); 3229 for (WifiNative.WifiPnoNetwork net : llist) { 3230 sb.append(" ").append(net.SSID).append(" auth ").append(net.auth); 3231 } 3232 sendMessage(CMD_STARTED_PNO_DBG, 1, 0, sb.toString()); 3233 } 3234 return true; 3235 } 3236 log("startPno: couldnt get PNO list "); 3237 return false; 3238 } 3239 3240 private void handleScreenStateChanged(boolean screenOn, boolean startBackgroundScanIfNeeded) { 3241 mScreenOn = screenOn; 3242 if (PDBG) { 3243 loge(" handleScreenStateChanged Enter: screenOn=" + screenOn 3244 + " mUserWantsSuspendOpt=" + mUserWantsSuspendOpt 3245 + " state " + getCurrentState().getName() 3246 + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); 3247 } 3248 enableRssiPolling(screenOn); 3249 if (screenOn) enableAllNetworks(); 3250 if (mUserWantsSuspendOpt.get()) { 3251 if (screenOn) { 3252 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0); 3253 } else { 3254 // Allow 2s for suspend optimizations to be set 3255 mSuspendWakeLock.acquire(2000); 3256 sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0); 3257 } 3258 } 3259 mScreenBroadcastReceived.set(true); 3260 3261 getWifiLinkLayerStats(false); 3262 mOnTimeScreenStateChange = mOnTime; 3263 lastScreenStateChangeTimeStamp = lastLinkLayerStatsUpdate; 3264 mEnableBackgroundScan = false; 3265 cancelDelayedScan(); 3266 3267 if (screenOn) { 3268 setScanAlarm(false); 3269 clearBlacklist(); 3270 3271 fullBandConnectedTimeIntervalMilli = mWifiConfigStore.associatedPartialScanPeriodMilli.get(); 3272 // In either Disconnectedstate or ConnectedState, 3273 // start the scan alarm so as to enable autojoin 3274 if (getCurrentState() == mConnectedState 3275 && mWifiConfigStore.enableAutoJoinScanWhenAssociated.get()) { 3276 if (!startPno()) { 3277 // Scan after 500ms 3278 startDelayedScan(500, null, null); 3279 } 3280 } else if (getCurrentState() == mDisconnectedState) { 3281 if (!startPno()) { 3282 // Scan after 500ms 3283 startDelayedScan(500, null, null); 3284 } 3285 } 3286 } else if (startBackgroundScanIfNeeded) { 3287 // Screen Off and Disconnected and chipset doesn't support scan offload 3288 // => start scan alarm 3289 // Screen Off and Disconnected and chipset does support scan offload 3290 // => will use scan offload (i.e. background scan) 3291 if (!mAlwaysOnPnoSupported) { 3292 if (!mBackgroundScanSupported) { 3293 setScanAlarm(true); 3294 } else { 3295 mEnableBackgroundScan = true; 3296 } 3297 } 3298 } 3299 if (DBG) logd("backgroundScan enabled=" + mEnableBackgroundScan 3300 + " startBackgroundScanIfNeeded:" + startBackgroundScanIfNeeded); 3301 if (startBackgroundScanIfNeeded) { 3302 if (!startPno()) { 3303 // to scan for them in background, we need all networks enabled 3304 enableBackgroundScan(mEnableBackgroundScan); 3305 } 3306 } 3307 if (DBG) log("handleScreenStateChanged Exit: " + screenOn); 3308 } 3309 3310 private void checkAndSetConnectivityInstance() { 3311 if (mCm == null) { 3312 mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 3313 } 3314 } 3315 3316 private boolean startTethering(ArrayList<String> available) { 3317 3318 boolean wifiAvailable = false; 3319 3320 checkAndSetConnectivityInstance(); 3321 3322 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 3323 3324 for (String intf : available) { 3325 for (String regex : wifiRegexs) { 3326 if (intf.matches(regex)) { 3327 3328 InterfaceConfiguration ifcg = null; 3329 try { 3330 ifcg = mNwService.getInterfaceConfig(intf); 3331 if (ifcg != null) { 3332 /* IP/netmask: 192.168.43.1/255.255.255.0 */ 3333 ifcg.setLinkAddress(new LinkAddress( 3334 NetworkUtils.numericToInetAddress("192.168.43.1"), 24)); 3335 ifcg.setInterfaceUp(); 3336 3337 mNwService.setInterfaceConfig(intf, ifcg); 3338 } 3339 } catch (Exception e) { 3340 loge("Error configuring interface " + intf + ", :" + e); 3341 return false; 3342 } 3343 3344 if (mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 3345 loge("Error tethering on " + intf); 3346 return false; 3347 } 3348 mTetherInterfaceName = intf; 3349 return true; 3350 } 3351 } 3352 } 3353 // We found no interfaces to tether 3354 return false; 3355 } 3356 3357 private void stopTethering() { 3358 3359 checkAndSetConnectivityInstance(); 3360 3361 /* Clear the interface config to allow dhcp correctly configure new 3362 ip settings */ 3363 InterfaceConfiguration ifcg = null; 3364 try { 3365 ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName); 3366 if (ifcg != null) { 3367 ifcg.setLinkAddress( 3368 new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0)); 3369 mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg); 3370 } 3371 } catch (Exception e) { 3372 loge("Error resetting interface " + mTetherInterfaceName + ", :" + e); 3373 } 3374 3375 if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 3376 loge("Untether initiate failed!"); 3377 } 3378 } 3379 3380 private boolean isWifiTethered(ArrayList<String> active) { 3381 3382 checkAndSetConnectivityInstance(); 3383 3384 String[] wifiRegexs = mCm.getTetherableWifiRegexs(); 3385 for (String intf : active) { 3386 for (String regex : wifiRegexs) { 3387 if (intf.matches(regex)) { 3388 return true; 3389 } 3390 } 3391 } 3392 // We found no interfaces that are tethered 3393 return false; 3394 } 3395 3396 /** 3397 * Set the country code from the system setting value, if any. 3398 */ 3399 private void setCountryCode() { 3400 String countryCode = Settings.Global.getString(mContext.getContentResolver(), 3401 Settings.Global.WIFI_COUNTRY_CODE); 3402 if (countryCode != null && !countryCode.isEmpty()) { 3403 setCountryCode(countryCode, false); 3404 } else { 3405 //use driver default 3406 } 3407 } 3408 3409 /** 3410 * Set the frequency band from the system setting value, if any. 3411 */ 3412 private void setFrequencyBand() { 3413 int band = Settings.Global.getInt(mContext.getContentResolver(), 3414 Settings.Global.WIFI_FREQUENCY_BAND, WifiManager.WIFI_FREQUENCY_BAND_AUTO); 3415 setFrequencyBand(band, false); 3416 } 3417 3418 private void setSuspendOptimizationsNative(int reason, boolean enabled) { 3419 if (DBG) { 3420 log("setSuspendOptimizationsNative: " + reason + " " + enabled 3421 + " -want " + mUserWantsSuspendOpt.get() 3422 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 3423 + " - " + Thread.currentThread().getStackTrace()[3].getMethodName() 3424 + " - " + Thread.currentThread().getStackTrace()[4].getMethodName() 3425 + " - " + Thread.currentThread().getStackTrace()[5].getMethodName()); 3426 } 3427 //mWifiNative.setSuspendOptimizations(enabled); 3428 3429 if (enabled) { 3430 mSuspendOptNeedsDisabled &= ~reason; 3431 /* None of dhcp, screen or highperf need it disabled and user wants it enabled */ 3432 if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) { 3433 if (DBG) { 3434 log("setSuspendOptimizationsNative do it " + reason + " " + enabled 3435 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 3436 + " - " + Thread.currentThread().getStackTrace()[3].getMethodName() 3437 + " - " + Thread.currentThread().getStackTrace()[4].getMethodName() 3438 + " - " + Thread.currentThread().getStackTrace()[5].getMethodName()); 3439 } 3440 mWifiNative.setSuspendOptimizations(true); 3441 } 3442 } else { 3443 mSuspendOptNeedsDisabled |= reason; 3444 mWifiNative.setSuspendOptimizations(false); 3445 } 3446 } 3447 3448 private void setSuspendOptimizations(int reason, boolean enabled) { 3449 if (DBG) log("setSuspendOptimizations: " + reason + " " + enabled); 3450 if (enabled) { 3451 mSuspendOptNeedsDisabled &= ~reason; 3452 } else { 3453 mSuspendOptNeedsDisabled |= reason; 3454 } 3455 if (DBG) log("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); 3456 } 3457 3458 private void setWifiState(int wifiState) { 3459 final int previousWifiState = mWifiState.get(); 3460 3461 try { 3462 if (wifiState == WIFI_STATE_ENABLED) { 3463 mBatteryStats.noteWifiOn(); 3464 } else if (wifiState == WIFI_STATE_DISABLED) { 3465 mBatteryStats.noteWifiOff(); 3466 } 3467 } catch (RemoteException e) { 3468 loge("Failed to note battery stats in wifi"); 3469 } 3470 3471 mWifiState.set(wifiState); 3472 3473 if (DBG) log("setWifiState: " + syncGetWifiStateByName()); 3474 3475 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 3476 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3477 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 3478 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 3479 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3480 } 3481 3482 private void setWifiApState(int wifiApState) { 3483 final int previousWifiApState = mWifiApState.get(); 3484 3485 try { 3486 if (wifiApState == WIFI_AP_STATE_ENABLED) { 3487 mBatteryStats.noteWifiOn(); 3488 } else if (wifiApState == WIFI_AP_STATE_DISABLED) { 3489 mBatteryStats.noteWifiOff(); 3490 } 3491 } catch (RemoteException e) { 3492 loge("Failed to note battery stats in wifi"); 3493 } 3494 3495 // Update state 3496 mWifiApState.set(wifiApState); 3497 3498 if (DBG) log("setWifiApState: " + syncGetWifiApStateByName()); 3499 3500 final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); 3501 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 3502 intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState); 3503 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState); 3504 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 3505 } 3506 3507 /* 3508 void ageOutScanResults(int age) { 3509 synchronized(mScanResultCache) { 3510 // Trim mScanResults, which prevent WifiStateMachine to return 3511 // obsolete scan results to queriers 3512 long now = System.CurrentTimeMillis(); 3513 for (int i = 0; i < mScanResults.size(); i++) { 3514 ScanResult result = mScanResults.get(i); 3515 if ((result.seen > now || (now - result.seen) > age)) { 3516 mScanResults.remove(i); 3517 } 3518 } 3519 } 3520 }*/ 3521 3522 private static final String IE_STR = "ie="; 3523 private static final String ID_STR = "id="; 3524 private static final String BSSID_STR = "bssid="; 3525 private static final String FREQ_STR = "freq="; 3526 private static final String LEVEL_STR = "level="; 3527 private static final String TSF_STR = "tsf="; 3528 private static final String FLAGS_STR = "flags="; 3529 private static final String SSID_STR = "ssid="; 3530 private static final String DELIMITER_STR = "===="; 3531 private static final String END_STR = "####"; 3532 3533 int emptyScanResultCount = 0; 3534 3535 // Used for matching BSSID strings, at least one characteer must be a non-zero number 3536 private static Pattern mNotZero = Pattern.compile("[1-9a-fA-F]"); 3537 3538 /** 3539 * Format: 3540 * <p/> 3541 * id=1 3542 * bssid=68:7f:76:d7:1a:6e 3543 * freq=2412 3544 * level=-44 3545 * tsf=1344626243700342 3546 * flags=[WPA2-PSK-CCMP][WPS][ESS] 3547 * ssid=zfdy 3548 * ==== 3549 * id=2 3550 * bssid=68:5f:74:d7:1a:6f 3551 * freq=5180 3552 * level=-73 3553 * tsf=1344626243700373 3554 * flags=[WPA2-PSK-CCMP][WPS][ESS] 3555 * ssid=zuby 3556 * ==== 3557 */ 3558 private void setScanResults() { 3559 mNumScanResultsKnown = 0; 3560 mNumScanResultsReturned = 0; 3561 String bssid = ""; 3562 int level = 0; 3563 int freq = 0; 3564 long tsf = 0; 3565 String flags = ""; 3566 WifiSsid wifiSsid = null; 3567 String scanResults; 3568 String tmpResults; 3569 StringBuffer scanResultsBuf = new StringBuffer(); 3570 int sid = 0; 3571 3572 while (true) { 3573 tmpResults = mWifiNative.scanResults(sid); 3574 if (TextUtils.isEmpty(tmpResults)) break; 3575 scanResultsBuf.append(tmpResults); 3576 scanResultsBuf.append("\n"); 3577 String[] lines = tmpResults.split("\n"); 3578 sid = -1; 3579 for (int i = lines.length - 1; i >= 0; i--) { 3580 if (lines[i].startsWith(END_STR)) { 3581 break; 3582 } else if (lines[i].startsWith(ID_STR)) { 3583 try { 3584 sid = Integer.parseInt(lines[i].substring(ID_STR.length())) + 1; 3585 } catch (NumberFormatException e) { 3586 // Nothing to do 3587 } 3588 break; 3589 } 3590 } 3591 if (sid == -1) break; 3592 } 3593 3594 // Age out scan results, we return all scan results found in the last 12 seconds, 3595 // and NOT all scan results since last scan. 3596 // ageOutScanResults(12000); 3597 3598 scanResults = scanResultsBuf.toString(); 3599 if (TextUtils.isEmpty(scanResults)) { 3600 emptyScanResultCount++; 3601 if (emptyScanResultCount > 10) { 3602 // If we got too many empty scan results, the current scan cache is stale, 3603 // hence clear it. 3604 mScanResults = new ArrayList<>(); 3605 } 3606 return; 3607 } 3608 3609 emptyScanResultCount = 0; 3610 3611 // note that all these splits and substrings keep references to the original 3612 // huge string buffer while the amount we really want is generally pretty small 3613 // so make copies instead (one example b/11087956 wasted 400k of heap here). 3614 synchronized (mScanResultCache) { 3615 mScanResults = new ArrayList<>(); 3616 String[] lines = scanResults.split("\n"); 3617 final int bssidStrLen = BSSID_STR.length(); 3618 final int flagLen = FLAGS_STR.length(); 3619 String infoElements = null; 3620 List<String> anqpLines = null; 3621 3622 for (String line : lines) { 3623 if (line.startsWith(BSSID_STR)) { 3624 bssid = new String(line.getBytes(), bssidStrLen, line.length() - bssidStrLen); 3625 } else if (line.startsWith(FREQ_STR)) { 3626 try { 3627 freq = Integer.parseInt(line.substring(FREQ_STR.length())); 3628 } catch (NumberFormatException e) { 3629 freq = 0; 3630 } 3631 } else if (line.startsWith(LEVEL_STR)) { 3632 try { 3633 level = Integer.parseInt(line.substring(LEVEL_STR.length())); 3634 /* some implementations avoid negative values by adding 256 3635 * so we need to adjust for that here. 3636 */ 3637 if (level > 0) level -= 256; 3638 } catch (NumberFormatException e) { 3639 level = 0; 3640 } 3641 } else if (line.startsWith(TSF_STR)) { 3642 try { 3643 tsf = Long.parseLong(line.substring(TSF_STR.length())); 3644 } catch (NumberFormatException e) { 3645 tsf = 0; 3646 } 3647 } else if (line.startsWith(FLAGS_STR)) { 3648 flags = new String(line.getBytes(), flagLen, line.length() - flagLen); 3649 } else if (line.startsWith(SSID_STR)) { 3650 wifiSsid = WifiSsid.createFromAsciiEncoded( 3651 line.substring(SSID_STR.length())); 3652 } else if (line.startsWith(IE_STR)) { 3653 infoElements = line; 3654 } else if (SupplicantBridge.isAnqpAttribute(line)) { 3655 if (anqpLines == null) { 3656 anqpLines = new ArrayList<>(); 3657 } 3658 anqpLines.add(line); 3659 } else if (line.startsWith(DELIMITER_STR) || line.startsWith(END_STR)) { 3660 if (bssid != null) { 3661 try { 3662 NetworkDetail networkDetail = 3663 new NetworkDetail(bssid, infoElements, anqpLines, freq); 3664 3665 String xssid = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 3666 if (!xssid.equals(networkDetail.getSSID())) { 3667 Log.d("HS2J", "Inconsistency: SSID: '" + xssid + 3668 "' vs '" + networkDetail.getSSID() + "': " + infoElements); 3669 } 3670 3671 if (networkDetail.hasInterworking()) { 3672 Log.d("HS2J", "HSNwk: '" + networkDetail); 3673 } 3674 3675 ScanDetail scanDetail = mScanResultCache.get(networkDetail); 3676 if (scanDetail != null) { 3677 scanDetail.updateResults(networkDetail, level, wifiSsid, xssid, 3678 flags, freq, tsf); 3679 } else { 3680 scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, 3681 flags, level, freq, tsf); 3682 mScanResultCache.put(networkDetail, scanDetail); 3683 } 3684 3685 mNumScanResultsReturned++; // Keep track of how many scan results we got 3686 // as part of this scan's processing 3687 mScanResults.add(scanDetail); 3688 } catch (IllegalArgumentException iae) { 3689 Log.d("HS2J", "Failed to parse information elements: " + iae); 3690 } 3691 } 3692 bssid = null; 3693 level = 0; 3694 freq = 0; 3695 tsf = 0; 3696 flags = ""; 3697 wifiSsid = null; 3698 infoElements = null; 3699 anqpLines = null; 3700 } 3701 } 3702 } 3703 3704 boolean attemptAutoJoin = true; 3705 SupplicantState state = mWifiInfo.getSupplicantState(); 3706 String selection = mWifiConfigStore.getLastSelectedConfiguration(); 3707 if (getCurrentState() == mRoamingState 3708 || getCurrentState() == mObtainingIpState 3709 || getCurrentState() == mScanModeState 3710 || getCurrentState() == mDisconnectingState 3711 || (getCurrentState() == mConnectedState 3712 && !mWifiConfigStore.enableAutoJoinWhenAssociated.get()) 3713 || linkDebouncing 3714 || state == SupplicantState.ASSOCIATING 3715 || state == SupplicantState.AUTHENTICATING 3716 || state == SupplicantState.FOUR_WAY_HANDSHAKE 3717 || state == SupplicantState.GROUP_HANDSHAKE 3718 || (/* keep autojoin enabled if user has manually selected a wifi network, 3719 so as to make sure we reliably remain connected to this network */ 3720 mConnectionRequests == 0 && selection == null)) { 3721 // Dont attempt auto-joining again while we are already attempting to join 3722 // and/or obtaining Ip address 3723 attemptAutoJoin = false; 3724 } 3725 if (DBG) { 3726 if (selection == null) { 3727 selection = "<none>"; 3728 } 3729 loge("wifi setScanResults state" + getCurrentState() 3730 + " sup_state=" + state 3731 + " debouncing=" + linkDebouncing 3732 + " mConnectionRequests=" + mConnectionRequests 3733 + " selection=" + selection); 3734 } 3735 if (attemptAutoJoin) { 3736 messageHandlingStatus = MESSAGE_HANDLING_STATUS_PROCESSED; 3737 } 3738 // Loose last selected configuration if we have been disconnected for 5 minutes 3739 if (getDisconnectedTimeMilli() > mWifiConfigStore.wifiConfigLastSelectionHysteresis) { 3740 mWifiConfigStore.setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 3741 } 3742 3743 if (mWifiConfigStore.enableAutoJoinWhenAssociated.get()) { 3744 synchronized (mScanResultCache) { 3745 // AutoJoincontroller will directly acces the scan result list and update it with 3746 // ScanResult status 3747 mNumScanResultsKnown = mWifiAutoJoinController.newSupplicantResults(attemptAutoJoin); 3748 } 3749 } 3750 if (linkDebouncing) { 3751 // If debouncing, we dont re-select a SSID or BSSID hence 3752 // there is no need to call the network selection code 3753 // in WifiAutoJoinController, instead, 3754 // just try to reconnect to the same SSID by triggering a roam 3755 sendMessage(CMD_AUTO_ROAM, mLastNetworkId, 1, null); 3756 } 3757 } 3758 3759 /* 3760 * Fetch RSSI, linkspeed, and frequency on current connection 3761 */ 3762 private void fetchRssiLinkSpeedAndFrequencyNative() { 3763 int newRssi = -1; 3764 int newLinkSpeed = -1; 3765 int newFrequency = -1; 3766 3767 String signalPoll = mWifiNative.signalPoll(); 3768 3769 if (signalPoll != null) { 3770 String[] lines = signalPoll.split("\n"); 3771 for (String line : lines) { 3772 String[] prop = line.split("="); 3773 if (prop.length < 2) continue; 3774 try { 3775 if (prop[0].equals("RSSI")) { 3776 newRssi = Integer.parseInt(prop[1]); 3777 } else if (prop[0].equals("LINKSPEED")) { 3778 newLinkSpeed = Integer.parseInt(prop[1]); 3779 } else if (prop[0].equals("FREQUENCY")) { 3780 newFrequency = Integer.parseInt(prop[1]); 3781 } 3782 } catch (NumberFormatException e) { 3783 //Ignore, defaults on rssi and linkspeed are assigned 3784 } 3785 } 3786 } 3787 3788 if (PDBG) { 3789 loge("fetchRssiLinkSpeedAndFrequencyNative rssi=" 3790 + Integer.toString(newRssi) + " linkspeed=" 3791 + Integer.toString(newLinkSpeed)); 3792 } 3793 3794 if (newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) { 3795 // screen out invalid values 3796 /* some implementations avoid negative values by adding 256 3797 * so we need to adjust for that here. 3798 */ 3799 if (newRssi > 0) newRssi -= 256; 3800 mWifiInfo.setRssi(newRssi); 3801 /* 3802 * Rather then sending the raw RSSI out every time it 3803 * changes, we precalculate the signal level that would 3804 * be displayed in the status bar, and only send the 3805 * broadcast if that much more coarse-grained number 3806 * changes. This cuts down greatly on the number of 3807 * broadcasts, at the cost of not informing others 3808 * interested in RSSI of all the changes in signal 3809 * level. 3810 */ 3811 int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); 3812 if (newSignalLevel != mLastSignalLevel) { 3813 sendRssiChangeBroadcast(newRssi); 3814 } 3815 mLastSignalLevel = newSignalLevel; 3816 } else { 3817 mWifiInfo.setRssi(WifiInfo.INVALID_RSSI); 3818 } 3819 3820 if (newLinkSpeed != -1) { 3821 mWifiInfo.setLinkSpeed(newLinkSpeed); 3822 } 3823 if (newFrequency > 0) { 3824 if (ScanResult.is5GHz(newFrequency)) { 3825 mWifiConnectionStatistics.num5GhzConnected++; 3826 } 3827 if (ScanResult.is24GHz(newFrequency)) { 3828 mWifiConnectionStatistics.num24GhzConnected++; 3829 } 3830 mWifiInfo.setFrequency(newFrequency); 3831 } 3832 mWifiConfigStore.updateConfiguration(mWifiInfo); 3833 } 3834 3835 /** 3836 * Determine if we need to switch network: 3837 * - the delta determine the urgency to switch and/or or the expected evilness of the disruption 3838 * - match the uregncy of the switch versus the packet usage at the interface 3839 */ 3840 boolean shouldSwitchNetwork(int networkDelta) { 3841 int delta; 3842 if (networkDelta <= 0) { 3843 return false; 3844 } 3845 delta = networkDelta; 3846 if (mWifiInfo != null) { 3847 if (!mWifiConfigStore.enableAutoJoinWhenAssociated.get() 3848 && mWifiInfo.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 3849 // If AutoJoin while associated is not enabled, 3850 // we should never switch network when already associated 3851 delta = -1000; 3852 } else { 3853 // TODO: Look at per AC packet count, do not switch if VO/VI traffic is present 3854 // TODO: at the interface. We should also discriminate between ucast and mcast, 3855 // TODO: since the rxSuccessRate include all the bonjour and Ipv6 3856 // TODO: broadcasts 3857 if ((mWifiInfo.txSuccessRate > 20) || (mWifiInfo.rxSuccessRate > 80)) { 3858 delta -= 999; 3859 } else if ((mWifiInfo.txSuccessRate > 5) || (mWifiInfo.rxSuccessRate > 30)) { 3860 delta -= 6; 3861 } 3862 loge("WifiStateMachine shouldSwitchNetwork " 3863 + " txSuccessRate=" + String.format("%.2f", mWifiInfo.txSuccessRate) 3864 + " rxSuccessRate=" + String.format("%.2f", mWifiInfo.rxSuccessRate) 3865 + " delta " + networkDelta + " -> " + delta); 3866 } 3867 } else { 3868 loge("WifiStateMachine shouldSwitchNetwork " 3869 + " delta " + networkDelta + " -> " + delta); 3870 } 3871 if (delta > 0) { 3872 return true; 3873 } 3874 return false; 3875 } 3876 3877 // Polling has completed, hence we wont have a score anymore 3878 private void cleanWifiScore() { 3879 mWifiInfo.txBadRate = 0; 3880 mWifiInfo.txSuccessRate = 0; 3881 mWifiInfo.txRetriesRate = 0; 3882 mWifiInfo.rxSuccessRate = 0; 3883 } 3884 3885 int mBadLinkspeedcount = 0; 3886 3887 // For debug, provide information about the last scoring operation 3888 String wifiScoringReport = null; 3889 3890 private void calculateWifiScore(WifiLinkLayerStats stats) { 3891 StringBuilder sb = new StringBuilder(); 3892 3893 int score = 56; // Starting score, temporarily hardcoded in between 50 and 60 3894 boolean isBadLinkspeed = (mWifiInfo.is24GHz() 3895 && mWifiInfo.getLinkSpeed() < mWifiConfigStore.badLinkSpeed24) 3896 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed() 3897 < mWifiConfigStore.badLinkSpeed5); 3898 boolean isGoodLinkspeed = (mWifiInfo.is24GHz() 3899 && mWifiInfo.getLinkSpeed() >= mWifiConfigStore.goodLinkSpeed24) 3900 || (mWifiInfo.is5GHz() && mWifiInfo.getLinkSpeed() 3901 >= mWifiConfigStore.goodLinkSpeed5); 3902 3903 if (isBadLinkspeed) { 3904 if (mBadLinkspeedcount < 6) 3905 mBadLinkspeedcount++; 3906 } else { 3907 if (mBadLinkspeedcount > 0) 3908 mBadLinkspeedcount--; 3909 } 3910 3911 if (isBadLinkspeed) sb.append(" bl(").append(mBadLinkspeedcount).append(")"); 3912 if (isGoodLinkspeed) sb.append(" gl"); 3913 3914 /** 3915 * We want to make sure that we use the 24GHz RSSI thresholds if 3916 * there are 2.4GHz scan results 3917 * otherwise we end up lowering the score based on 5GHz values 3918 * which may cause a switch to LTE before roaming has a chance to try 2.4GHz 3919 * We also might unblacklist the configuation based on 2.4GHz 3920 * thresholds but joining 5GHz anyhow, and failing over to 2.4GHz because 5GHz is not good 3921 */ 3922 boolean use24Thresholds = false; 3923 boolean homeNetworkBoost = false; 3924 WifiConfiguration currentConfiguration = getCurrentWifiConfiguration(); 3925 ScanDetailCache scanDetailCache = 3926 mWifiConfigStore.getScanDetailCache(currentConfiguration); 3927 if (currentConfiguration != null && scanDetailCache != null) { 3928 currentConfiguration.setVisibility(scanDetailCache.getVisibility(12000)); 3929 if (currentConfiguration.visibility != null) { 3930 if (currentConfiguration.visibility.rssi24 != WifiConfiguration.INVALID_RSSI 3931 && currentConfiguration.visibility.rssi24 3932 >= (currentConfiguration.visibility.rssi5 - 2)) { 3933 use24Thresholds = true; 3934 } 3935 } 3936 if (scanDetailCache.size() <= 6 3937 && currentConfiguration.allowedKeyManagement.cardinality() == 1 3938 && currentConfiguration.allowedKeyManagement. 3939 get(WifiConfiguration.KeyMgmt.WPA_PSK) == true) { 3940 // A PSK network with less than 6 known BSSIDs 3941 // This is most likely a home network and thus we want to stick to wifi more 3942 homeNetworkBoost = true; 3943 } 3944 } 3945 if (homeNetworkBoost) sb.append(" hn"); 3946 if (use24Thresholds) sb.append(" u24"); 3947 3948 int rssi = mWifiInfo.getRssi() - 6 * mAggressiveHandover 3949 + (homeNetworkBoost ? WifiConfiguration.HOME_NETWORK_RSSI_BOOST : 0); 3950 sb.append(String.format(" rssi=%d ag=%d", rssi, mAggressiveHandover)); 3951 3952 boolean is24GHz = use24Thresholds || mWifiInfo.is24GHz(); 3953 3954 boolean isBadRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdBadRssi24.get()) 3955 || (!is24GHz && rssi < mWifiConfigStore.thresholdBadRssi5.get()); 3956 boolean isLowRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdLowRssi24.get()) 3957 || (!is24GHz && mWifiInfo.getRssi() < mWifiConfigStore.thresholdLowRssi5.get()); 3958 boolean isHighRSSI = (is24GHz && rssi >= mWifiConfigStore.thresholdGoodRssi24.get()) 3959 || (!is24GHz && mWifiInfo.getRssi() >= mWifiConfigStore.thresholdGoodRssi5.get()); 3960 3961 if (isBadRSSI) sb.append(" br"); 3962 if (isLowRSSI) sb.append(" lr"); 3963 if (isHighRSSI) sb.append(" hr"); 3964 3965 int penalizedDueToUserTriggeredDisconnect = 0; // For debug information 3966 if (currentConfiguration != null && 3967 (mWifiInfo.txSuccessRate > 5 || mWifiInfo.rxSuccessRate > 5)) { 3968 if (isBadRSSI) { 3969 currentConfiguration.numTicksAtBadRSSI++; 3970 if (currentConfiguration.numTicksAtBadRSSI > 1000) { 3971 // We remained associated for a compound amount of time while passing 3972 // traffic, hence loose the corresponding user triggered disabled stats 3973 if (currentConfiguration.numUserTriggeredWifiDisableBadRSSI > 0) { 3974 currentConfiguration.numUserTriggeredWifiDisableBadRSSI--; 3975 } 3976 if (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0) { 3977 currentConfiguration.numUserTriggeredWifiDisableLowRSSI--; 3978 } 3979 if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) { 3980 currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--; 3981 } 3982 currentConfiguration.numTicksAtBadRSSI = 0; 3983 } 3984 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment && 3985 (currentConfiguration.numUserTriggeredWifiDisableBadRSSI > 0 3986 || currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0 3987 || currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0)) { 3988 score = score - 5; 3989 penalizedDueToUserTriggeredDisconnect = 1; 3990 sb.append(" p1"); 3991 } 3992 } else if (isLowRSSI) { 3993 currentConfiguration.numTicksAtLowRSSI++; 3994 if (currentConfiguration.numTicksAtLowRSSI > 1000) { 3995 // We remained associated for a compound amount of time while passing 3996 // traffic, hence loose the corresponding user triggered disabled stats 3997 if (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0) { 3998 currentConfiguration.numUserTriggeredWifiDisableLowRSSI--; 3999 } 4000 if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) { 4001 currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--; 4002 } 4003 currentConfiguration.numTicksAtLowRSSI = 0; 4004 } 4005 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment && 4006 (currentConfiguration.numUserTriggeredWifiDisableLowRSSI > 0 4007 || currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0)) { 4008 score = score - 5; 4009 penalizedDueToUserTriggeredDisconnect = 2; 4010 sb.append(" p2"); 4011 } 4012 } else if (!isHighRSSI) { 4013 currentConfiguration.numTicksAtNotHighRSSI++; 4014 if (currentConfiguration.numTicksAtNotHighRSSI > 1000) { 4015 // We remained associated for a compound amount of time while passing 4016 // traffic, hence loose the corresponding user triggered disabled stats 4017 if (currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) { 4018 currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI--; 4019 } 4020 currentConfiguration.numTicksAtNotHighRSSI = 0; 4021 } 4022 if (mWifiConfigStore.enableWifiCellularHandoverUserTriggeredAdjustment && 4023 currentConfiguration.numUserTriggeredWifiDisableNotHighRSSI > 0) { 4024 score = score - 5; 4025 penalizedDueToUserTriggeredDisconnect = 3; 4026 sb.append(" p3"); 4027 } 4028 } 4029 sb.append(String.format(" ticks %d,%d,%d", currentConfiguration.numTicksAtBadRSSI, 4030 currentConfiguration.numTicksAtLowRSSI, 4031 currentConfiguration.numTicksAtNotHighRSSI)); 4032 } 4033 4034 if (PDBG) { 4035 String rssiStatus = ""; 4036 if (isBadRSSI) rssiStatus += " badRSSI "; 4037 else if (isHighRSSI) rssiStatus += " highRSSI "; 4038 else if (isLowRSSI) rssiStatus += " lowRSSI "; 4039 if (isBadLinkspeed) rssiStatus += " lowSpeed "; 4040 loge("calculateWifiScore freq=" + Integer.toString(mWifiInfo.getFrequency()) 4041 + " speed=" + Integer.toString(mWifiInfo.getLinkSpeed()) 4042 + " score=" + Integer.toString(mWifiInfo.score) 4043 + rssiStatus 4044 + " -> txbadrate=" + String.format("%.2f", mWifiInfo.txBadRate) 4045 + " txgoodrate=" + String.format("%.2f", mWifiInfo.txSuccessRate) 4046 + " txretriesrate=" + String.format("%.2f", mWifiInfo.txRetriesRate) 4047 + " rxrate=" + String.format("%.2f", mWifiInfo.rxSuccessRate) 4048 + " userTriggerdPenalty" + penalizedDueToUserTriggeredDisconnect); 4049 } 4050 4051 if ((mWifiInfo.txBadRate >= 1) && (mWifiInfo.txSuccessRate < 3) 4052 && (isBadRSSI || isLowRSSI)) { 4053 // Link is stuck 4054 if (mWifiInfo.linkStuckCount < 5) 4055 mWifiInfo.linkStuckCount += 1; 4056 sb.append(String.format(" ls+=%d", mWifiInfo.linkStuckCount)); 4057 if (PDBG) loge(" bad link -> stuck count =" 4058 + Integer.toString(mWifiInfo.linkStuckCount)); 4059 } else if (mWifiInfo.txSuccessRate > 2 || mWifiInfo.txBadRate < 0.1) { 4060 if (mWifiInfo.linkStuckCount > 0) 4061 mWifiInfo.linkStuckCount -= 1; 4062 sb.append(String.format(" ls-=%d", mWifiInfo.linkStuckCount)); 4063 if (PDBG) loge(" good link -> stuck count =" 4064 + Integer.toString(mWifiInfo.linkStuckCount)); 4065 } 4066 4067 sb.append(String.format(" [%d", score)); 4068 4069 if (mWifiInfo.linkStuckCount > 1) { 4070 // Once link gets stuck for more than 3 seconds, start reducing the score 4071 score = score - 2 * (mWifiInfo.linkStuckCount - 1); 4072 } 4073 sb.append(String.format(",%d", score)); 4074 4075 if (isBadLinkspeed) { 4076 score -= 4; 4077 if (PDBG) { 4078 loge(" isBadLinkspeed ---> count=" + mBadLinkspeedcount 4079 + " score=" + Integer.toString(score)); 4080 } 4081 } else if ((isGoodLinkspeed) && (mWifiInfo.txSuccessRate > 5)) { 4082 score += 4; // So as bad rssi alone dont kill us 4083 } 4084 sb.append(String.format(",%d", score)); 4085 4086 if (isBadRSSI) { 4087 if (mWifiInfo.badRssiCount < 7) 4088 mWifiInfo.badRssiCount += 1; 4089 } else if (isLowRSSI) { 4090 mWifiInfo.lowRssiCount = 1; // Dont increment the lowRssi count above 1 4091 if (mWifiInfo.badRssiCount > 0) { 4092 // Decrement bad Rssi count 4093 mWifiInfo.badRssiCount -= 1; 4094 } 4095 } else { 4096 mWifiInfo.badRssiCount = 0; 4097 mWifiInfo.lowRssiCount = 0; 4098 } 4099 4100 score -= mWifiInfo.badRssiCount * 2 + mWifiInfo.lowRssiCount; 4101 sb.append(String.format(",%d", score)); 4102 4103 if (PDBG) loge(" badRSSI count" + Integer.toString(mWifiInfo.badRssiCount) 4104 + " lowRSSI count" + Integer.toString(mWifiInfo.lowRssiCount) 4105 + " --> score " + Integer.toString(score)); 4106 4107 4108 if (isHighRSSI) { 4109 score += 5; 4110 if (PDBG) loge(" isHighRSSI ---> score=" + Integer.toString(score)); 4111 } 4112 sb.append(String.format(",%d]", score)); 4113 4114 sb.append(String.format(" brc=%d lrc=%d", mWifiInfo.badRssiCount, mWifiInfo.lowRssiCount)); 4115 4116 //sanitize boundaries 4117 if (score > NetworkAgent.WIFI_BASE_SCORE) 4118 score = NetworkAgent.WIFI_BASE_SCORE; 4119 if (score < 0) 4120 score = 0; 4121 4122 //report score 4123 if (score != mWifiInfo.score) { 4124 if (DBG) { 4125 loge("calculateWifiScore() report new score " + Integer.toString(score)); 4126 } 4127 mWifiInfo.score = score; 4128 if (mNetworkAgent != null) { 4129 mNetworkAgent.sendNetworkScore(score); 4130 } 4131 } 4132 wifiScoringReport = sb.toString(); 4133 } 4134 4135 public double getTxPacketRate() { 4136 if (mWifiInfo != null) { 4137 return mWifiInfo.txSuccessRate; 4138 } 4139 return -1; 4140 } 4141 4142 public double getRxPacketRate() { 4143 if (mWifiInfo != null) { 4144 return mWifiInfo.rxSuccessRate; 4145 } 4146 return -1; 4147 } 4148 4149 /** 4150 * Fetch TX packet counters on current connection 4151 */ 4152 private void fetchPktcntNative(RssiPacketCountInfo info) { 4153 String pktcntPoll = mWifiNative.pktcntPoll(); 4154 4155 if (pktcntPoll != null) { 4156 String[] lines = pktcntPoll.split("\n"); 4157 for (String line : lines) { 4158 String[] prop = line.split("="); 4159 if (prop.length < 2) continue; 4160 try { 4161 if (prop[0].equals("TXGOOD")) { 4162 info.txgood = Integer.parseInt(prop[1]); 4163 } else if (prop[0].equals("TXBAD")) { 4164 info.txbad = Integer.parseInt(prop[1]); 4165 } 4166 } catch (NumberFormatException e) { 4167 // Ignore 4168 } 4169 } 4170 } 4171 } 4172 4173 private boolean clearIPv4Address(String iface) { 4174 try { 4175 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 4176 ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0")); 4177 mNwService.setInterfaceConfig(iface, ifcg); 4178 return true; 4179 } catch (RemoteException e) { 4180 return false; 4181 } 4182 } 4183 4184 private boolean isProvisioned(LinkProperties lp) { 4185 return lp.isProvisioned() || 4186 (mWifiConfigStore.isUsingStaticIp(mLastNetworkId) && lp.hasIPv4Address()); 4187 } 4188 4189 /** 4190 * Updates mLinkProperties by merging information from various sources. 4191 * <p/> 4192 * This is needed because the information in mLinkProperties comes from multiple sources (DHCP, 4193 * netlink, static configuration, ...). When one of these sources of information has updated 4194 * link properties, we can't just assign them to mLinkProperties or we'd lose track of the 4195 * information that came from other sources. Instead, when one of those sources has new 4196 * information, we update the object that tracks the information from that source and then 4197 * call this method to apply the change to mLinkProperties. 4198 * <p/> 4199 * The information in mLinkProperties is currently obtained as follows: 4200 * - Interface name: set in the constructor. 4201 * - IPv4 and IPv6 addresses: netlink, passed in by mNetlinkTracker. 4202 * - IPv4 routes, DNS servers, and domains: DHCP. 4203 * - IPv6 routes and DNS servers: netlink, passed in by mNetlinkTracker. 4204 * - HTTP proxy: the wifi config store. 4205 */ 4206 private void updateLinkProperties(int reason) { 4207 LinkProperties newLp = new LinkProperties(); 4208 4209 // Interface name and proxy are locally configured. 4210 newLp.setInterfaceName(mInterfaceName); 4211 newLp.setHttpProxy(mWifiConfigStore.getProxyProperties(mLastNetworkId)); 4212 4213 // IPv4/v6 addresses, IPv6 routes and IPv6 DNS servers come from netlink. 4214 LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties(); 4215 newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses()); 4216 for (RouteInfo route : netlinkLinkProperties.getRoutes()) { 4217 newLp.addRoute(route); 4218 } 4219 for (InetAddress dns : netlinkLinkProperties.getDnsServers()) { 4220 newLp.addDnsServer(dns); 4221 } 4222 4223 // IPv4 routes, DNS servers and domains come from mDhcpResults. 4224 synchronized (mDhcpResultsLock) { 4225 // Even when we're using static configuration, we don't need to look at the config 4226 // store, because static IP configuration also populates mDhcpResults. 4227 if ((mDhcpResults != null)) { 4228 for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) { 4229 newLp.addRoute(route); 4230 } 4231 for (InetAddress dns : mDhcpResults.dnsServers) { 4232 newLp.addDnsServer(dns); 4233 } 4234 newLp.setDomains(mDhcpResults.domains); 4235 } 4236 } 4237 4238 final boolean linkChanged = !newLp.equals(mLinkProperties); 4239 final boolean wasProvisioned = isProvisioned(mLinkProperties); 4240 final boolean isProvisioned = isProvisioned(newLp); 4241 final boolean lostIPv4Provisioning = 4242 mLinkProperties.hasIPv4Address() && !newLp.hasIPv4Address(); 4243 final DetailedState detailedState = getNetworkDetailedState(); 4244 4245 if (linkChanged) { 4246 if (DBG) { 4247 log("Link configuration changed for netId: " + mLastNetworkId 4248 + " old: " + mLinkProperties + " new: " + newLp); 4249 } 4250 mLinkProperties = newLp; 4251 if (TextUtils.isEmpty(mTcpBufferSizes) == false) { 4252 mLinkProperties.setTcpBufferSizes(mTcpBufferSizes); 4253 } 4254 if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); 4255 } 4256 4257 if (DBG) { 4258 StringBuilder sb = new StringBuilder(); 4259 sb.append("updateLinkProperties nid: " + mLastNetworkId); 4260 sb.append(" state: " + detailedState); 4261 sb.append(" reason: " + smToString(reason)); 4262 4263 if (mLinkProperties != null) { 4264 if (mLinkProperties.hasIPv4Address()) { 4265 sb.append(" v4"); 4266 } 4267 if (mLinkProperties.hasGlobalIPv6Address()) { 4268 sb.append(" v6"); 4269 } 4270 if (mLinkProperties.hasIPv4DefaultRoute()) { 4271 sb.append(" v4r"); 4272 } 4273 if (mLinkProperties.hasIPv6DefaultRoute()) { 4274 sb.append(" v6r"); 4275 } 4276 if (mLinkProperties.hasIPv4DnsServer()) { 4277 sb.append(" v4dns"); 4278 } 4279 if (mLinkProperties.hasIPv6DnsServer()) { 4280 sb.append(" v6dns"); 4281 } 4282 if (isProvisioned) { 4283 sb.append(" isprov"); 4284 } 4285 } 4286 loge(sb.toString()); 4287 } 4288 4289 // If we just configured or lost IP configuration, do the needful. 4290 // We don't just call handleSuccessfulIpConfiguration() or handleIpConfigurationLost() 4291 // here because those should only be called if we're attempting to connect or already 4292 // connected, whereas updateLinkProperties can be called at any time. 4293 switch (reason) { 4294 case DhcpStateMachine.DHCP_SUCCESS: 4295 case CMD_STATIC_IP_SUCCESS: 4296 // IPv4 provisioning succeded. Advance to connected state. 4297 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 4298 if (!isProvisioned) { 4299 // Can never happen unless DHCP reports success but isProvisioned thinks the 4300 // resulting configuration is invalid (e.g., no IPv4 address, or the state in 4301 // mLinkProperties is out of sync with reality, or there's a bug in this code). 4302 // TODO: disconnect here instead. If our configuration is not usable, there's no 4303 // point in staying connected, and if mLinkProperties is out of sync with 4304 // reality, that will cause problems in the future. 4305 loge("IPv4 config succeeded, but not provisioned"); 4306 } 4307 break; 4308 4309 case DhcpStateMachine.DHCP_FAILURE: 4310 // DHCP failed. If we're not already provisioned, or we had IPv4 and now lost it, 4311 // give up and disconnect. 4312 // If we're already provisioned (e.g., IPv6-only network), stay connected. 4313 if (!isProvisioned || lostIPv4Provisioning) { 4314 sendMessage(CMD_IP_CONFIGURATION_LOST); 4315 } else { 4316 // DHCP failed, but we're provisioned (e.g., if we're on an IPv6-only network). 4317 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 4318 4319 // To be sure we don't get stuck with a non-working network if all we had is 4320 // IPv4, remove the IPv4 address from the interface (since we're using DHCP, 4321 // and DHCP failed). If we had an IPv4 address before, the deletion of the 4322 // address will cause a CMD_UPDATE_LINKPROPERTIES. If the IPv4 address was 4323 // necessary for provisioning, its deletion will cause us to disconnect. 4324 // 4325 // This shouldn't be needed, because on an IPv4-only network a DHCP failure will 4326 // have empty DhcpResults and thus empty LinkProperties, and isProvisioned will 4327 // not return true if we're using DHCP and don't have an IPv4 default route. So 4328 // for now it's only here for extra redundancy. However, it will increase 4329 // robustness if we move to getting IPv4 routes from netlink as well. 4330 loge("DHCP failure: provisioned, clearing IPv4 address."); 4331 if (!clearIPv4Address(mInterfaceName)) { 4332 sendMessage(CMD_IP_CONFIGURATION_LOST); 4333 } 4334 } 4335 break; 4336 4337 case CMD_STATIC_IP_FAILURE: 4338 // Static configuration was invalid, or an error occurred in applying it. Give up. 4339 sendMessage(CMD_IP_CONFIGURATION_LOST); 4340 break; 4341 4342 case CMD_UPDATE_LINKPROPERTIES: 4343 // IP addresses, DNS servers, etc. changed. Act accordingly. 4344 if (wasProvisioned && !isProvisioned) { 4345 // We no longer have a usable network configuration. Disconnect. 4346 sendMessage(CMD_IP_CONFIGURATION_LOST); 4347 } else if (!wasProvisioned && isProvisioned) { 4348 // We have a usable IPv6-only config. Advance to connected state. 4349 sendMessage(CMD_IP_CONFIGURATION_SUCCESSFUL); 4350 } 4351 if (linkChanged && getNetworkDetailedState() == DetailedState.CONNECTED) { 4352 // If anything has changed and we're already connected, send out a notification. 4353 sendLinkConfigurationChangedBroadcast(); 4354 } 4355 break; 4356 } 4357 } 4358 4359 /** 4360 * Clears all our link properties. 4361 */ 4362 private void clearLinkProperties() { 4363 // Clear the link properties obtained from DHCP and netlink. 4364 synchronized (mDhcpResultsLock) { 4365 if (mDhcpResults != null) { 4366 mDhcpResults.clear(); 4367 } 4368 } 4369 mNetlinkTracker.clearLinkProperties(); 4370 4371 // Now clear the merged link properties. 4372 mLinkProperties.clear(); 4373 if (mNetworkAgent != null) mNetworkAgent.sendLinkProperties(mLinkProperties); 4374 } 4375 4376 /** 4377 * try to update default route MAC address. 4378 */ 4379 private String updateDefaultRouteMacAddress(int timeout) { 4380 String address = null; 4381 for (RouteInfo route : mLinkProperties.getRoutes()) { 4382 if (route.isDefaultRoute() && route.hasGateway()) { 4383 InetAddress gateway = route.getGateway(); 4384 if (gateway instanceof Inet4Address) { 4385 if (PDBG) { 4386 loge("updateDefaultRouteMacAddress found Ipv4 default :" 4387 + gateway.getHostAddress()); 4388 } 4389 address = macAddressFromRoute(gateway.getHostAddress()); 4390 /* The gateway's MAC address is known */ 4391 if ((address == null) && (timeout > 0)) { 4392 boolean reachable = false; 4393 try { 4394 reachable = gateway.isReachable(timeout); 4395 } catch (Exception e) { 4396 loge("updateDefaultRouteMacAddress exception reaching :" 4397 + gateway.getHostAddress()); 4398 4399 } finally { 4400 if (reachable == true) { 4401 4402 address = macAddressFromRoute(gateway.getHostAddress()); 4403 if (PDBG) { 4404 loge("updateDefaultRouteMacAddress reachable (tried again) :" 4405 + gateway.getHostAddress() + " found " + address); 4406 } 4407 } 4408 } 4409 } 4410 if (address != null) { 4411 mWifiConfigStore.setDefaultGwMacAddress(mLastNetworkId, address); 4412 } 4413 } 4414 } 4415 } 4416 return address; 4417 } 4418 4419 private void sendScanResultsAvailableBroadcast() { 4420 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 4421 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4422 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 4423 } 4424 4425 private void sendRssiChangeBroadcast(final int newRssi) { 4426 try { 4427 mBatteryStats.noteWifiRssiChanged(newRssi); 4428 } catch (RemoteException e) { 4429 // Won't happen. 4430 } 4431 Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION); 4432 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4433 intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi); 4434 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 4435 } 4436 4437 private void sendNetworkStateChangeBroadcast(String bssid) { 4438 Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION); 4439 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4440 intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 4441 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); 4442 if (bssid != null) 4443 intent.putExtra(WifiManager.EXTRA_BSSID, bssid); 4444 if (mNetworkInfo.getDetailedState() == DetailedState.VERIFYING_POOR_LINK || 4445 mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { 4446 intent.putExtra(WifiManager.EXTRA_WIFI_INFO, new WifiInfo(mWifiInfo)); 4447 } 4448 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 4449 } 4450 4451 private void sendLinkConfigurationChangedBroadcast() { 4452 Intent intent = new Intent(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); 4453 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4454 intent.putExtra(WifiManager.EXTRA_LINK_PROPERTIES, new LinkProperties(mLinkProperties)); 4455 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 4456 } 4457 4458 private void sendSupplicantConnectionChangedBroadcast(boolean connected) { 4459 Intent intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION); 4460 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 4461 intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, connected); 4462 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 4463 } 4464 4465 /** 4466 * Record the detailed state of a network. 4467 * 4468 * @param state the new {@code DetailedState} 4469 */ 4470 private boolean setNetworkDetailedState(NetworkInfo.DetailedState state) { 4471 boolean hidden = false; 4472 4473 if (linkDebouncing || isRoaming()) { 4474 // There is generally a confusion in the system about colluding 4475 // WiFi Layer 2 state (as reported by supplicant) and the Network state 4476 // which leads to multiple confusion. 4477 // 4478 // If link is de-bouncing or roaming, we already have an IP address 4479 // as well we were connected and are doing L2 cycles of 4480 // reconnecting or renewing IP address to check that we still have it 4481 // This L2 link flapping should ne be reflected into the Network state 4482 // which is the state of the WiFi Network visible to Layer 3 and applications 4483 // Note that once debouncing and roaming are completed, we will 4484 // set the Network state to where it should be, or leave it as unchanged 4485 // 4486 hidden = true; 4487 } 4488 if (DBG) { 4489 log("setDetailed state, old =" 4490 + mNetworkInfo.getDetailedState() + " and new state=" + state 4491 + " hidden=" + hidden); 4492 } 4493 if (mNetworkInfo.getExtraInfo() != null && mWifiInfo.getSSID() != null) { 4494 // Always indicate that SSID has changed 4495 if (!mNetworkInfo.getExtraInfo().equals(mWifiInfo.getSSID())) { 4496 if (DBG) { 4497 log("setDetailed state send new extra info" + mWifiInfo.getSSID()); 4498 } 4499 mNetworkInfo.setExtraInfo(mWifiInfo.getSSID()); 4500 sendNetworkStateChangeBroadcast(null); 4501 } 4502 } 4503 if (hidden == true) { 4504 return false; 4505 } 4506 4507 if (state != mNetworkInfo.getDetailedState()) { 4508 mNetworkInfo.setDetailedState(state, null, mWifiInfo.getSSID()); 4509 if (mNetworkAgent != null) { 4510 mNetworkAgent.sendNetworkInfo(mNetworkInfo); 4511 } 4512 sendNetworkStateChangeBroadcast(null); 4513 return true; 4514 } 4515 return false; 4516 } 4517 4518 private DetailedState getNetworkDetailedState() { 4519 return mNetworkInfo.getDetailedState(); 4520 } 4521 4522 4523 private SupplicantState handleSupplicantStateChange(Message message) { 4524 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 4525 SupplicantState state = stateChangeResult.state; 4526 // Supplicant state change 4527 // [31-13] Reserved for future use 4528 // [8 - 0] Supplicant state (as defined in SupplicantState.java) 4529 // 50023 supplicant_state_changed (custom|1|5) 4530 mWifiInfo.setSupplicantState(state); 4531 // Network id is only valid when we start connecting 4532 if (SupplicantState.isConnecting(state)) { 4533 mWifiInfo.setNetworkId(stateChangeResult.networkId); 4534 } else { 4535 mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 4536 } 4537 4538 mWifiInfo.setBSSID(stateChangeResult.BSSID); 4539 mWifiInfo.setSSID(stateChangeResult.wifiSsid); 4540 4541 mSupplicantStateTracker.sendMessage(Message.obtain(message)); 4542 4543 return state; 4544 } 4545 4546 /** 4547 * Resets the Wi-Fi Connections by clearing any state, resetting any sockets 4548 * using the interface, stopping DHCP & disabling interface 4549 */ 4550 private void handleNetworkDisconnect() { 4551 if (DBG) log("handleNetworkDisconnect: Stopping DHCP and clearing IP" 4552 + " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName() 4553 + " - " + Thread.currentThread().getStackTrace()[3].getMethodName() 4554 + " - " + Thread.currentThread().getStackTrace()[4].getMethodName() 4555 + " - " + Thread.currentThread().getStackTrace()[5].getMethodName()); 4556 4557 4558 clearCurrentConfigBSSID("handleNetworkDisconnect"); 4559 4560 stopDhcp(); 4561 4562 try { 4563 mNwService.clearInterfaceAddresses(mInterfaceName); 4564 mNwService.disableIpv6(mInterfaceName); 4565 } catch (Exception e) { 4566 loge("Failed to clear addresses or disable ipv6" + e); 4567 } 4568 4569 /* Reset data structures */ 4570 mBadLinkspeedcount = 0; 4571 mWifiInfo.reset(); 4572 linkDebouncing = false; 4573 /* Reset roaming parameters */ 4574 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 4575 4576 /** 4577 * fullBandConnectedTimeIntervalMilli: 4578 * - start scans at mWifiConfigStore.associatedPartialScanPeriodMilli seconds interval 4579 * - exponentially increase to mWifiConfigStore.associatedFullScanMaxIntervalMilli 4580 * Initialize to sane value = 20 seconds 4581 */ 4582 fullBandConnectedTimeIntervalMilli = 20 * 1000; 4583 4584 setNetworkDetailedState(DetailedState.DISCONNECTED); 4585 if (mNetworkAgent != null) { 4586 mNetworkAgent.sendNetworkInfo(mNetworkInfo); 4587 mNetworkAgent = null; 4588 } 4589 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED); 4590 4591 /* Clear network properties */ 4592 clearLinkProperties(); 4593 4594 /* Cend event to CM & network change broadcast */ 4595 sendNetworkStateChangeBroadcast(mLastBssid); 4596 4597 /* Cancel auto roam requests */ 4598 autoRoamSetBSSID(mLastNetworkId, "any"); 4599 4600 mLastBssid = null; 4601 registerDisconnected(); 4602 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 4603 } 4604 4605 private void handleSupplicantConnectionLoss() { 4606 /* Socket connection can be lost when we do a graceful shutdown 4607 * or when the driver is hung. Ensure supplicant is stopped here. 4608 */ 4609 mWifiMonitor.killSupplicant(mP2pSupported); 4610 mWifiNative.closeSupplicantConnection(); 4611 sendSupplicantConnectionChangedBroadcast(false); 4612 setWifiState(WIFI_STATE_DISABLED); 4613 } 4614 4615 void handlePreDhcpSetup() { 4616 mDhcpActive = true; 4617 if (!mBluetoothConnectionActive) { 4618 /* 4619 * There are problems setting the Wi-Fi driver's power 4620 * mode to active when bluetooth coexistence mode is 4621 * enabled or sense. 4622 * <p> 4623 * We set Wi-Fi to active mode when 4624 * obtaining an IP address because we've found 4625 * compatibility issues with some routers with low power 4626 * mode. 4627 * <p> 4628 * In order for this active power mode to properly be set, 4629 * we disable coexistence mode until we're done with 4630 * obtaining an IP address. One exception is if we 4631 * are currently connected to a headset, since disabling 4632 * coexistence would interrupt that connection. 4633 */ 4634 // Disable the coexistence mode 4635 mWifiNative.setBluetoothCoexistenceMode( 4636 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); 4637 } 4638 4639 // Disable power save and suspend optimizations during DHCP 4640 // Note: The order here is important for now. Brcm driver changes 4641 // power settings when we control suspend mode optimizations. 4642 // TODO: Remove this comment when the driver is fixed. 4643 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, false); 4644 mWifiNative.setPowerSave(false); 4645 4646 // stopBatchedScan(); 4647 WifiNative.pauseScan(); 4648 4649 // Update link layer stats 4650 getWifiLinkLayerStats(false); 4651 4652 /* P2p discovery breaks dhcp, shut it down in order to get through this */ 4653 Message msg = new Message(); 4654 msg.what = WifiP2pServiceImpl.BLOCK_DISCOVERY; 4655 msg.arg1 = WifiP2pServiceImpl.ENABLED; 4656 msg.arg2 = DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE; 4657 msg.obj = mDhcpStateMachine; 4658 mWifiP2pChannel.sendMessage(msg); 4659 } 4660 4661 4662 private boolean useLegacyDhcpClient() { 4663 return Settings.Global.getInt( 4664 mContext.getContentResolver(), 4665 Settings.Global.LEGACY_DHCP_CLIENT, 0) == 1; 4666 } 4667 4668 private void maybeInitDhcpStateMachine() { 4669 if (mDhcpStateMachine == null) { 4670 if (useLegacyDhcpClient()) { 4671 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine( 4672 mContext, WifiStateMachine.this, mInterfaceName); 4673 } else { 4674 mDhcpStateMachine = DhcpClient.makeDhcpStateMachine( 4675 mContext, WifiStateMachine.this, mInterfaceName); 4676 } 4677 } 4678 } 4679 4680 void startDhcp() { 4681 maybeInitDhcpStateMachine(); 4682 mDhcpStateMachine.registerForPreDhcpNotification(); 4683 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); 4684 } 4685 4686 void renewDhcp() { 4687 maybeInitDhcpStateMachine(); 4688 mDhcpStateMachine.registerForPreDhcpNotification(); 4689 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_RENEW_DHCP); 4690 } 4691 4692 void stopDhcp() { 4693 if (mDhcpStateMachine != null) { 4694 /* In case we were in middle of DHCP operation restore back powermode */ 4695 handlePostDhcpSetup(); 4696 mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); 4697 } 4698 } 4699 4700 void handlePostDhcpSetup() { 4701 /* Restore power save and suspend optimizations */ 4702 setSuspendOptimizationsNative(SUSPEND_DUE_TO_DHCP, true); 4703 mWifiNative.setPowerSave(true); 4704 4705 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.BLOCK_DISCOVERY, WifiP2pServiceImpl.DISABLED); 4706 4707 // Set the coexistence mode back to its default value 4708 mWifiNative.setBluetoothCoexistenceMode( 4709 mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE); 4710 4711 mDhcpActive = false; 4712 4713 // startBatchedScan(); 4714 WifiNative.restartScan(); 4715 } 4716 4717 void connectScanningService() { 4718 4719 if (mWifiScanner == null) 4720 mWifiScanner = (WifiScanner) mContext.getSystemService(Context.WIFI_SCANNING_SERVICE); 4721 4722 } 4723 4724 private void handleIPv4Success(DhcpResults dhcpResults, int reason) { 4725 4726 if (PDBG) { 4727 loge("wifistatemachine handleIPv4Success <" + dhcpResults.toString() + ">"); 4728 loge("link address " + dhcpResults.ipAddress); 4729 } 4730 4731 synchronized (mDhcpResultsLock) { 4732 mDhcpResults = dhcpResults; 4733 } 4734 4735 Inet4Address addr = (Inet4Address) dhcpResults.ipAddress.getAddress(); 4736 if (isRoaming()) { 4737 if (addr instanceof Inet4Address) { 4738 int previousAddress = mWifiInfo.getIpAddress(); 4739 int newAddress = NetworkUtils.inetAddressToInt(addr); 4740 if (previousAddress != newAddress) { 4741 loge("handleIPv4Success, roaming and address changed" + 4742 mWifiInfo + " got: " + addr); 4743 } else { 4744 4745 } 4746 } else { 4747 loge("handleIPv4Success, roaming and didnt get an IPv4 address" + 4748 addr.toString()); 4749 } 4750 } 4751 mWifiInfo.setInetAddress(addr); 4752 mWifiInfo.setMeteredHint(dhcpResults.hasMeteredHint()); 4753 updateLinkProperties(reason); 4754 } 4755 4756 private void handleSuccessfulIpConfiguration() { 4757 mLastSignalLevel = -1; // Force update of signal strength 4758 WifiConfiguration c = getCurrentWifiConfiguration(); 4759 if (c != null) { 4760 // Reset IP failure tracking 4761 c.numConnectionFailures = 0; 4762 4763 // Tell the framework whether the newly connected network is trusted or untrusted. 4764 updateCapabilities(c); 4765 } 4766 if (c != null) { 4767 ScanResult result = getCurrentScanResult(); 4768 if (result == null) { 4769 loge("WifiStateMachine: handleSuccessfulIpConfiguration and no scan results" + 4770 c.configKey()); 4771 } else { 4772 // Clear the per BSSID failure count 4773 result.numIpConfigFailures = 0; 4774 // Clear the WHOLE BSSID blacklist, which means supplicant is free to retry 4775 // any BSSID, even though it may already have a non zero ip failure count, 4776 // this will typically happen if the user walks away and come back to his arrea 4777 // TODO: implement blacklisting based on a timer, i.e. keep BSSID blacklisted 4778 // in supplicant for a couple of hours or a day 4779 mWifiNative.clearBlacklist(); 4780 } 4781 } 4782 } 4783 4784 private void handleIPv4Failure(int reason) { 4785 synchronized(mDhcpResultsLock) { 4786 if (mDhcpResults != null) { 4787 mDhcpResults.clear(); 4788 } 4789 } 4790 if (PDBG) { 4791 loge("wifistatemachine handleIPv4Failure"); 4792 } 4793 updateLinkProperties(reason); 4794 } 4795 4796 private void handleIpConfigurationLost() { 4797 mWifiInfo.setInetAddress(null); 4798 mWifiInfo.setMeteredHint(false); 4799 4800 mWifiConfigStore.handleSSIDStateChange(mLastNetworkId, false, 4801 "DHCP FAILURE", mWifiInfo.getBSSID()); 4802 4803 /* DHCP times out after about 30 seconds, we do a 4804 * disconnect thru supplicant, we will let autojoin retry connecting to the network 4805 */ 4806 mWifiNative.disconnect(); 4807 } 4808 4809 private int convertFrequencyToChannelNumber(int frequency) { 4810 if (frequency >= 2412 && frequency <= 2484) { 4811 return (frequency -2412) / 5 + 1; 4812 } else if (frequency >= 5170 && frequency <=5825) { 4813 //DFS is included 4814 return (frequency -5170) / 5 + 34; 4815 } else { 4816 return 0; 4817 } 4818 } 4819 4820 private int chooseApChannel(int apBand) { 4821 int apChannel; 4822 int[] channel; 4823 4824 if (apBand == 0) { 4825 //for 2.4GHz, we only set the AP at channel 1,6,11 4826 apChannel = 5 * mRandom.nextInt(3) + 1; 4827 } else { 4828 //5G without DFS 4829 channel = mWifiNative.getChannelsForBand(2); 4830 if (channel != null && channel.length > 0) { 4831 apChannel = channel[mRandom.nextInt(channel.length)]; 4832 apChannel = convertFrequencyToChannelNumber(apChannel); 4833 } else { 4834 Log.e(TAG, "SoftAp do not get available channel list"); 4835 apChannel = 0; 4836 } 4837 } 4838 4839 if(DBG) { 4840 Log.d(TAG, "SoftAp set on channel " + apChannel); 4841 } 4842 4843 return apChannel; 4844 } 4845 4846 4847 /* Current design is to not set the config on a running hostapd but instead 4848 * stop and start tethering when user changes config on a running access point 4849 * 4850 * TODO: Add control channel setup through hostapd that allows changing config 4851 * on a running daemon 4852 */ 4853 private void startSoftApWithConfig(final WifiConfiguration configuration) { 4854 // set channel 4855 final WifiConfiguration config = new WifiConfiguration(configuration); 4856 4857 if (DBG) { 4858 Log.d(TAG, "SoftAp config channel is: " + config.apChannel); 4859 } 4860 //set country code through HAL Here 4861 if (mSetCountryCode != null) { 4862 if(!mWifiNative.setCountryCodeHal(mSetCountryCode.toUpperCase(Locale.ROOT))) { 4863 if (config.apBand != 0) { 4864 Log.e(TAG, "Fail to set country code. Can not setup Softap on 5GHz"); 4865 //countrycode is mandatory for 5GHz 4866 sendMessage(CMD_START_AP_FAILURE); 4867 return; 4868 } 4869 } 4870 } else { 4871 if (config.apBand != 0) { 4872 //countrycode is mandatory for 5GHz 4873 Log.e(TAG, "Can not setup softAp on 5GHz without country code!"); 4874 sendMessage(CMD_START_AP_FAILURE); 4875 return; 4876 } 4877 } 4878 4879 if (config.apChannel == 0) { 4880 config.apChannel = chooseApChannel(config.apBand); 4881 if (config.apChannel == 0) { 4882 //fail to get available channel 4883 sendMessage(CMD_START_AP_FAILURE); 4884 return; 4885 } 4886 } 4887 //turn off interface 4888 if (!mWifiNative.toggleInterface(0)) { 4889 sendMessage(CMD_START_AP_FAILURE); 4890 return; 4891 } 4892 // Start hostapd on a separate thread 4893 new Thread(new Runnable() { 4894 public void run() { 4895 try { 4896 mNwService.startAccessPoint(config, mInterfaceName); 4897 } catch (Exception e) { 4898 loge("Exception in softap start " + e); 4899 try { 4900 mNwService.stopAccessPoint(mInterfaceName); 4901 mNwService.startAccessPoint(config, mInterfaceName); 4902 } catch (Exception e1) { 4903 loge("Exception in softap re-start " + e1); 4904 sendMessage(CMD_START_AP_FAILURE); 4905 return; 4906 } 4907 } 4908 if (DBG) log("Soft AP start successful"); 4909 sendMessage(CMD_START_AP_SUCCESS); 4910 } 4911 }).start(); 4912 } 4913 4914 /* 4915 * Read a MAC address in /proc/arp/table, used by WifistateMachine 4916 * so as to record MAC address of default gateway. 4917 **/ 4918 private String macAddressFromRoute(String ipAddress) { 4919 String macAddress = null; 4920 BufferedReader reader = null; 4921 try { 4922 reader = new BufferedReader(new FileReader("/proc/net/arp")); 4923 4924 // Skip over the line bearing colum titles 4925 String line = reader.readLine(); 4926 4927 while ((line = reader.readLine()) != null) { 4928 String[] tokens = line.split("[ ]+"); 4929 if (tokens.length < 6) { 4930 continue; 4931 } 4932 4933 // ARP column format is 4934 // Address HWType HWAddress Flags Mask IFace 4935 String ip = tokens[0]; 4936 String mac = tokens[3]; 4937 4938 if (ipAddress.equals(ip)) { 4939 macAddress = mac; 4940 break; 4941 } 4942 } 4943 4944 if (macAddress == null) { 4945 loge("Did not find remoteAddress {" + ipAddress + "} in " + 4946 "/proc/net/arp"); 4947 } 4948 4949 } catch (FileNotFoundException e) { 4950 loge("Could not open /proc/net/arp to lookup mac address"); 4951 } catch (IOException e) { 4952 loge("Could not read /proc/net/arp to lookup mac address"); 4953 } finally { 4954 try { 4955 if (reader != null) { 4956 reader.close(); 4957 } 4958 } catch (IOException e) { 4959 // Do nothing 4960 } 4961 } 4962 return macAddress; 4963 4964 } 4965 4966 private class WifiNetworkFactory extends NetworkFactory { 4967 public WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f) { 4968 super(l, c, TAG, f); 4969 } 4970 4971 @Override 4972 protected void needNetworkFor(NetworkRequest networkRequest, int score) { 4973 ++mConnectionRequests; 4974 } 4975 4976 @Override 4977 protected void releaseNetworkFor(NetworkRequest networkRequest) { 4978 --mConnectionRequests; 4979 } 4980 4981 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 4982 pw.println("mConnectionRequests " + mConnectionRequests); 4983 } 4984 4985 } 4986 4987 private class UntrustedWifiNetworkFactory extends NetworkFactory { 4988 private int mUntrustedReqCount; 4989 4990 public UntrustedWifiNetworkFactory(Looper l, Context c, String tag, NetworkCapabilities f) { 4991 super(l, c, tag, f); 4992 } 4993 4994 @Override 4995 protected void needNetworkFor(NetworkRequest networkRequest, int score) { 4996 if (!networkRequest.networkCapabilities.hasCapability( 4997 NetworkCapabilities.NET_CAPABILITY_TRUSTED)) { 4998 if (++mUntrustedReqCount == 1) { 4999 mWifiAutoJoinController.setAllowUntrustedConnections(true); 5000 } 5001 } 5002 } 5003 5004 @Override 5005 protected void releaseNetworkFor(NetworkRequest networkRequest) { 5006 if (!networkRequest.networkCapabilities.hasCapability( 5007 NetworkCapabilities.NET_CAPABILITY_TRUSTED)) { 5008 if (--mUntrustedReqCount == 0) { 5009 mWifiAutoJoinController.setAllowUntrustedConnections(false); 5010 } 5011 } 5012 } 5013 5014 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 5015 pw.println("mUntrustedReqCount " + mUntrustedReqCount); 5016 } 5017 } 5018 5019 void maybeRegisterNetworkFactory() { 5020 if (mNetworkFactory == null) { 5021 checkAndSetConnectivityInstance(); 5022 if (mCm != null) { 5023 mNetworkFactory = new WifiNetworkFactory(getHandler().getLooper(), mContext, 5024 NETWORKTYPE, mNetworkCapabilitiesFilter); 5025 mNetworkFactory.setScoreFilter(60); 5026 mNetworkFactory.register(); 5027 5028 // We can't filter untrusted network in the capabilities filter because a trusted 5029 // network would still satisfy a request that accepts untrusted ones. 5030 mUntrustedNetworkFactory = new UntrustedWifiNetworkFactory(getHandler().getLooper(), 5031 mContext, NETWORKTYPE_UNTRUSTED, mNetworkCapabilitiesFilter); 5032 mUntrustedNetworkFactory.setScoreFilter(Integer.MAX_VALUE); 5033 mUntrustedNetworkFactory.register(); 5034 } 5035 } 5036 } 5037 5038 /******************************************************** 5039 * HSM states 5040 *******************************************************/ 5041 5042 class DefaultState extends State { 5043 @Override 5044 public boolean processMessage(Message message) { 5045 logStateAndMessage(message, getClass().getSimpleName()); 5046 5047 switch (message.what) { 5048 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 5049 AsyncChannel ac = (AsyncChannel) message.obj; 5050 if (ac == mWifiP2pChannel) { 5051 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 5052 mWifiP2pChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); 5053 } else { 5054 loge("WifiP2pService connection failure, error=" + message.arg1); 5055 } 5056 } else { 5057 loge("got HALF_CONNECTED for unknown channel"); 5058 } 5059 break; 5060 } 5061 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 5062 AsyncChannel ac = (AsyncChannel) message.obj; 5063 if (ac == mWifiP2pChannel) { 5064 loge("WifiP2pService channel lost, message.arg1 =" + message.arg1); 5065 //TODO: Re-establish connection to state machine after a delay 5066 // mWifiP2pChannel.connect(mContext, getHandler(), 5067 // mWifiP2pManager.getMessenger()); 5068 } 5069 break; 5070 } 5071 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 5072 mBluetoothConnectionActive = (message.arg1 != 5073 BluetoothAdapter.STATE_DISCONNECTED); 5074 break; 5075 /* Synchronous call returns */ 5076 case CMD_PING_SUPPLICANT: 5077 case CMD_ENABLE_NETWORK: 5078 case CMD_ADD_OR_UPDATE_NETWORK: 5079 case CMD_REMOVE_NETWORK: 5080 case CMD_SAVE_CONFIG: 5081 replyToMessage(message, message.what, FAILURE); 5082 break; 5083 case CMD_GET_CAPABILITY_FREQ: 5084 replyToMessage(message, message.what, null); 5085 break; 5086 case CMD_GET_CONFIGURED_NETWORKS: 5087 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 5088 break; 5089 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS: 5090 replyToMessage(message, message.what, (List<WifiConfiguration>) null); 5091 break; 5092 case CMD_ENABLE_RSSI_POLL: 5093 mEnableRssiPolling = (message.arg1 == 1); 5094 break; 5095 case CMD_SET_HIGH_PERF_MODE: 5096 if (message.arg1 == 1) { 5097 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false); 5098 } else { 5099 setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true); 5100 } 5101 break; 5102 case CMD_BOOT_COMPLETED: 5103 maybeRegisterNetworkFactory(); 5104 break; 5105 case CMD_SET_BATCHED_SCAN: 5106 recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj); 5107 break; 5108 case CMD_POLL_BATCHED_SCAN: 5109 handleBatchedScanPollRequest(); 5110 break; 5111 case CMD_START_NEXT_BATCHED_SCAN: 5112 startNextBatchedScan(); 5113 break; 5114 case CMD_SCREEN_STATE_CHANGED: 5115 handleScreenStateChanged(message.arg1 != 0, 5116 /* startBackgroundScanIfNeeded = */ false); 5117 break; 5118 /* Discard */ 5119 case CMD_START_SCAN: 5120 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 5121 break; 5122 case CMD_START_SUPPLICANT: 5123 case CMD_STOP_SUPPLICANT: 5124 case CMD_STOP_SUPPLICANT_FAILED: 5125 case CMD_START_DRIVER: 5126 case CMD_STOP_DRIVER: 5127 case CMD_DELAYED_STOP_DRIVER: 5128 case CMD_DRIVER_START_TIMED_OUT: 5129 case CMD_START_AP: 5130 case CMD_START_AP_SUCCESS: 5131 case CMD_START_AP_FAILURE: 5132 case CMD_STOP_AP: 5133 case CMD_TETHER_STATE_CHANGE: 5134 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 5135 case CMD_DISCONNECT: 5136 case CMD_RECONNECT: 5137 case CMD_REASSOCIATE: 5138 case CMD_RELOAD_TLS_AND_RECONNECT: 5139 case WifiMonitor.SUP_CONNECTION_EVENT: 5140 case WifiMonitor.SUP_DISCONNECTION_EVENT: 5141 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5142 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 5143 case WifiMonitor.SCAN_RESULTS_EVENT: 5144 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5145 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 5146 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 5147 case WifiMonitor.WPS_OVERLAP_EVENT: 5148 case CMD_BLACKLIST_NETWORK: 5149 case CMD_CLEAR_BLACKLIST: 5150 case CMD_SET_OPERATIONAL_MODE: 5151 case CMD_SET_COUNTRY_CODE: 5152 case CMD_SET_FREQUENCY_BAND: 5153 case CMD_RSSI_POLL: 5154 case CMD_ENABLE_ALL_NETWORKS: 5155 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 5156 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 5157 /* Handled by WifiApConfigStore */ 5158 case CMD_SET_AP_CONFIG: 5159 case CMD_SET_AP_CONFIG_COMPLETED: 5160 case CMD_REQUEST_AP_CONFIG: 5161 case CMD_RESPONSE_AP_CONFIG: 5162 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 5163 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 5164 case CMD_NO_NETWORKS_PERIODIC_SCAN: 5165 case CMD_DISABLE_P2P_RSP: 5166 case WifiMonitor.SUP_REQUEST_IDENTITY: 5167 case CMD_TEST_NETWORK_DISCONNECT: 5168 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: 5169 case WifiMonitor.SUP_REQUEST_SIM_AUTH: 5170 case CMD_TARGET_BSSID: 5171 case CMD_AUTO_CONNECT: 5172 case CMD_AUTO_ROAM: 5173 case CMD_AUTO_SAVE_NETWORK: 5174 case CMD_ASSOCIATED_BSSID: 5175 case CMD_UNWANTED_NETWORK: 5176 case CMD_DISCONNECTING_WATCHDOG_TIMER: 5177 case CMD_ROAM_WATCHDOG_TIMER: 5178 case CMD_DISABLE_EPHEMERAL_NETWORK: 5179 case CMD_GET_MATCHING_CONFIG: 5180 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 5181 break; 5182 case DhcpStateMachine.CMD_ON_QUIT: 5183 mDhcpStateMachine = null; 5184 break; 5185 case CMD_SET_SUSPEND_OPT_ENABLED: 5186 if (message.arg1 == 1) { 5187 mSuspendWakeLock.release(); 5188 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, true); 5189 } else { 5190 setSuspendOptimizations(SUSPEND_DUE_TO_SCREEN, false); 5191 } 5192 break; 5193 case WifiMonitor.DRIVER_HUNG_EVENT: 5194 setSupplicantRunning(false); 5195 setSupplicantRunning(true); 5196 break; 5197 case WifiManager.CONNECT_NETWORK: 5198 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 5199 WifiManager.BUSY); 5200 break; 5201 case WifiManager.FORGET_NETWORK: 5202 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 5203 WifiManager.BUSY); 5204 break; 5205 case WifiManager.SAVE_NETWORK: 5206 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 5207 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 5208 WifiManager.BUSY); 5209 break; 5210 case WifiManager.START_WPS: 5211 replyToMessage(message, WifiManager.WPS_FAILED, 5212 WifiManager.BUSY); 5213 break; 5214 case WifiManager.CANCEL_WPS: 5215 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, 5216 WifiManager.BUSY); 5217 break; 5218 case WifiManager.DISABLE_NETWORK: 5219 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 5220 WifiManager.BUSY); 5221 break; 5222 case WifiManager.RSSI_PKTCNT_FETCH: 5223 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED, 5224 WifiManager.BUSY); 5225 break; 5226 case CMD_GET_SUPPORTED_FEATURES: 5227 if (WifiNative.startHal()) { 5228 int featureSet = WifiNative.getSupportedFeatureSet(); 5229 replyToMessage(message, message.what, featureSet); 5230 } else { 5231 replyToMessage(message, message.what, 0); 5232 } 5233 break; 5234 case CMD_GET_LINK_LAYER_STATS: 5235 // Not supported hence reply with error message 5236 replyToMessage(message, message.what, null); 5237 break; 5238 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 5239 NetworkInfo info = (NetworkInfo) message.obj; 5240 mP2pConnected.set(info.isConnected()); 5241 break; 5242 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 5243 mTemporarilyDisconnectWifi = (message.arg1 == 1); 5244 replyToMessage(message, WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 5245 break; 5246 /* Link configuration (IP address, DNS, ...) changes notified via netlink */ 5247 case CMD_UPDATE_LINKPROPERTIES: 5248 updateLinkProperties(CMD_UPDATE_LINKPROPERTIES); 5249 break; 5250 case CMD_IP_CONFIGURATION_SUCCESSFUL: 5251 case CMD_IP_CONFIGURATION_LOST: 5252 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 5253 break; 5254 case CMD_GET_CONNECTION_STATISTICS: 5255 replyToMessage(message, message.what, mWifiConnectionStatistics); 5256 break; 5257 default: 5258 loge("Error! unhandled message" + message); 5259 break; 5260 } 5261 return HANDLED; 5262 } 5263 } 5264 5265 class InitialState extends State { 5266 @Override 5267 public void enter() { 5268 mWifiNative.unloadDriver(); 5269 5270 if (mWifiP2pChannel == null) { 5271 mWifiP2pChannel = new AsyncChannel(); 5272 mWifiP2pChannel.connect(mContext, getHandler(), 5273 mWifiP2pServiceImpl.getP2pStateMachineMessenger()); 5274 } 5275 5276 if (mWifiApConfigChannel == null) { 5277 mWifiApConfigChannel = new AsyncChannel(); 5278 WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore( 5279 mContext, getHandler()); 5280 wifiApConfigStore.loadApConfiguration(); 5281 mWifiApConfigChannel.connectSync(mContext, getHandler(), 5282 wifiApConfigStore.getMessenger()); 5283 } 5284 } 5285 @Override 5286 public boolean processMessage(Message message) { 5287 logStateAndMessage(message, getClass().getSimpleName()); 5288 switch (message.what) { 5289 case CMD_START_SUPPLICANT: 5290 if (mWifiNative.loadDriver()) { 5291 try { 5292 mNwService.wifiFirmwareReload(mInterfaceName, "STA"); 5293 } catch (Exception e) { 5294 loge("Failed to reload STA firmware " + e); 5295 // Continue 5296 } 5297 5298 try { 5299 // A runtime crash can leave the interface up and 5300 // IP addresses configured, and this affects 5301 // connectivity when supplicant starts up. 5302 // Ensure interface is down and we have no IP 5303 // addresses before a supplicant start. 5304 mNwService.setInterfaceDown(mInterfaceName); 5305 mNwService.clearInterfaceAddresses(mInterfaceName); 5306 5307 // Set privacy extensions 5308 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); 5309 5310 // IPv6 is enabled only as long as access point is connected since: 5311 // - IPv6 addresses and routes stick around after disconnection 5312 // - kernel is unaware when connected and fails to start IPv6 negotiation 5313 // - kernel can start autoconfiguration when 802.1x is not complete 5314 mNwService.disableIpv6(mInterfaceName); 5315 } catch (RemoteException re) { 5316 loge("Unable to change interface settings: " + re); 5317 } catch (IllegalStateException ie) { 5318 loge("Unable to change interface settings: " + ie); 5319 } 5320 5321 /* Stop a running supplicant after a runtime restart 5322 * Avoids issues with drivers that do not handle interface down 5323 * on a running supplicant properly. 5324 */ 5325 mWifiMonitor.killSupplicant(mP2pSupported); 5326 if(mWifiNative.startSupplicant(mP2pSupported)) { 5327 setWifiState(WIFI_STATE_ENABLING); 5328 if (DBG) log("Supplicant start successful"); 5329 mWifiMonitor.startMonitoring(); 5330 transitionTo(mSupplicantStartingState); 5331 } else { 5332 loge("Failed to start supplicant!"); 5333 } 5334 } else { 5335 loge("Failed to load driver"); 5336 } 5337 break; 5338 case CMD_START_AP: 5339 if (mWifiNative.loadDriver()) { 5340 setWifiApState(WIFI_AP_STATE_ENABLING); 5341 transitionTo(mSoftApStartingState); 5342 } else { 5343 loge("Failed to load driver for softap"); 5344 } 5345 break; 5346 default: 5347 return NOT_HANDLED; 5348 } 5349 return HANDLED; 5350 } 5351 } 5352 5353 class SupplicantStartingState extends State { 5354 private void initializeWpsDetails() { 5355 String detail; 5356 detail = SystemProperties.get("ro.product.name", ""); 5357 if (!mWifiNative.setDeviceName(detail)) { 5358 loge("Failed to set device name " + detail); 5359 } 5360 detail = SystemProperties.get("ro.product.manufacturer", ""); 5361 if (!mWifiNative.setManufacturer(detail)) { 5362 loge("Failed to set manufacturer " + detail); 5363 } 5364 detail = SystemProperties.get("ro.product.model", ""); 5365 if (!mWifiNative.setModelName(detail)) { 5366 loge("Failed to set model name " + detail); 5367 } 5368 detail = SystemProperties.get("ro.product.model", ""); 5369 if (!mWifiNative.setModelNumber(detail)) { 5370 loge("Failed to set model number " + detail); 5371 } 5372 detail = SystemProperties.get("ro.serialno", ""); 5373 if (!mWifiNative.setSerialNumber(detail)) { 5374 loge("Failed to set serial number " + detail); 5375 } 5376 if (!mWifiNative.setConfigMethods("physical_display virtual_push_button")) { 5377 loge("Failed to set WPS config methods"); 5378 } 5379 if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) { 5380 loge("Failed to set primary device type " + mPrimaryDeviceType); 5381 } 5382 } 5383 5384 @Override 5385 public boolean processMessage(Message message) { 5386 logStateAndMessage(message, getClass().getSimpleName()); 5387 5388 switch(message.what) { 5389 case WifiMonitor.SUP_CONNECTION_EVENT: 5390 if (DBG) log("Supplicant connection established"); 5391 setWifiState(WIFI_STATE_ENABLED); 5392 mSupplicantRestartCount = 0; 5393 /* Reset the supplicant state to indicate the supplicant 5394 * state is not known at this time */ 5395 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 5396 /* Initialize data structures */ 5397 mLastBssid = null; 5398 mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID; 5399 mLastSignalLevel = -1; 5400 5401 mWifiInfo.setMacAddress(mWifiNative.getMacAddress()); 5402 mWifiNative.enableSaveConfig(); 5403 mWifiConfigStore.loadAndEnableAllNetworks(); 5404 if (mWifiConfigStore.enableVerboseLogging.get() > 0) { 5405 enableVerboseLogging(mWifiConfigStore.enableVerboseLogging.get()); 5406 } 5407 if (mWifiConfigStore.associatedPartialScanPeriodMilli.get() < 0) { 5408 mWifiConfigStore.associatedPartialScanPeriodMilli.set(0); 5409 } 5410 initializeWpsDetails(); 5411 5412 sendSupplicantConnectionChangedBroadcast(true); 5413 transitionTo(mDriverStartedState); 5414 break; 5415 case WifiMonitor.SUP_DISCONNECTION_EVENT: 5416 if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) { 5417 loge("Failed to setup control channel, restart supplicant"); 5418 mWifiMonitor.killSupplicant(mP2pSupported); 5419 transitionTo(mInitialState); 5420 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 5421 } else { 5422 loge("Failed " + mSupplicantRestartCount + 5423 " times to start supplicant, unload driver"); 5424 mSupplicantRestartCount = 0; 5425 setWifiState(WIFI_STATE_UNKNOWN); 5426 transitionTo(mInitialState); 5427 } 5428 break; 5429 case CMD_START_SUPPLICANT: 5430 case CMD_STOP_SUPPLICANT: 5431 case CMD_START_AP: 5432 case CMD_STOP_AP: 5433 case CMD_START_DRIVER: 5434 case CMD_STOP_DRIVER: 5435 case CMD_SET_OPERATIONAL_MODE: 5436 case CMD_SET_COUNTRY_CODE: 5437 case CMD_SET_FREQUENCY_BAND: 5438 case CMD_START_PACKET_FILTERING: 5439 case CMD_STOP_PACKET_FILTERING: 5440 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 5441 deferMessage(message); 5442 break; 5443 default: 5444 return NOT_HANDLED; 5445 } 5446 return HANDLED; 5447 } 5448 } 5449 5450 class SupplicantStartedState extends State { 5451 @Override 5452 public void enter() { 5453 /* Wifi is available as long as we have a connection to supplicant */ 5454 mNetworkInfo.setIsAvailable(true); 5455 if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo); 5456 5457 int defaultInterval = mContext.getResources().getInteger( 5458 R.integer.config_wifi_supplicant_scan_interval); 5459 5460 mSupplicantScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 5461 Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS, 5462 defaultInterval); 5463 5464 mWifiNative.setScanInterval((int)mSupplicantScanIntervalMs / 1000); 5465 mWifiNative.setExternalSim(true); 5466 5467 /* turn on use of DFS channels */ 5468 WifiNative.setDfsFlag(true); 5469 5470 /* set country code */ 5471 setCountryCode(); 5472 5473 setRandomMacOui(); 5474 mWifiNative.enableAutoConnect(false); 5475 } 5476 5477 @Override 5478 public boolean processMessage(Message message) { 5479 logStateAndMessage(message, getClass().getSimpleName()); 5480 5481 switch(message.what) { 5482 case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */ 5483 if (mP2pSupported) { 5484 transitionTo(mWaitForP2pDisableState); 5485 } else { 5486 transitionTo(mSupplicantStoppingState); 5487 } 5488 break; 5489 case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */ 5490 loge("Connection lost, restart supplicant"); 5491 handleSupplicantConnectionLoss(); 5492 handleNetworkDisconnect(); 5493 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 5494 if (mP2pSupported) { 5495 transitionTo(mWaitForP2pDisableState); 5496 } else { 5497 transitionTo(mInitialState); 5498 } 5499 sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS); 5500 break; 5501 case WifiMonitor.SCAN_RESULTS_EVENT: 5502 maybeRegisterNetworkFactory(); // Make sure our NetworkFactory is registered 5503 closeRadioScanStats(); 5504 noteScanEnd(); 5505 setScanResults(); 5506 if (mIsFullScanOngoing || mSendScanResultsBroadcast) { 5507 /* Just updated results from full scan, let apps know about this */ 5508 sendScanResultsAvailableBroadcast(); 5509 } 5510 mSendScanResultsBroadcast = false; 5511 mIsScanOngoing = false; 5512 mIsFullScanOngoing = false; 5513 if (mBufferedScanMsg.size() > 0) 5514 sendMessage(mBufferedScanMsg.remove()); 5515 break; 5516 case CMD_PING_SUPPLICANT: 5517 boolean ok = mWifiNative.ping(); 5518 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 5519 break; 5520 case CMD_GET_CAPABILITY_FREQ: 5521 String freqs = mWifiNative.getFreqCapability(); 5522 replyToMessage(message, message.what, freqs); 5523 break; 5524 case CMD_START_AP: 5525 /* Cannot start soft AP while in client mode */ 5526 loge("Failed to start soft AP with a running supplicant"); 5527 setWifiApState(WIFI_AP_STATE_FAILED); 5528 break; 5529 case CMD_SET_OPERATIONAL_MODE: 5530 mOperationalMode = message.arg1; 5531 mWifiConfigStore. 5532 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 5533 break; 5534 case CMD_TARGET_BSSID: 5535 // Trying to associate to this BSSID 5536 if (message.obj != null) { 5537 mTargetRoamBSSID = (String) message.obj; 5538 } 5539 break; 5540 case CMD_GET_LINK_LAYER_STATS: 5541 WifiLinkLayerStats stats = getWifiLinkLayerStats(DBG); 5542 if (stats == null) { 5543 // When firmware doesnt support link layer stats, return an empty object 5544 stats = new WifiLinkLayerStats(); 5545 } 5546 replyToMessage(message, message.what, stats); 5547 break; 5548 case CMD_SET_COUNTRY_CODE: 5549 String country = (String) message.obj; 5550 5551 final boolean persist = (message.arg2 == 1); 5552 final int sequence = message.arg1; 5553 5554 if (sequence != mCountryCodeSequence.get()) { 5555 if (DBG) log("set country code ignored due to sequnce num"); 5556 break; 5557 } 5558 if (DBG) log("set country code " + country); 5559 country = country.toUpperCase(Locale.ROOT); 5560 5561 if (mDriverSetCountryCode == null || !mDriverSetCountryCode.equals(country)) { 5562 if (mWifiNative.setCountryCode(country)) { 5563 mDriverSetCountryCode = country; 5564 } else { 5565 loge("Failed to set country code " + country); 5566 } 5567 } 5568 5569 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.SET_COUNTRY_CODE, country); 5570 break; 5571 default: 5572 return NOT_HANDLED; 5573 } 5574 return HANDLED; 5575 } 5576 5577 @Override 5578 public void exit() { 5579 mNetworkInfo.setIsAvailable(false); 5580 if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo); 5581 } 5582 } 5583 5584 class SupplicantStoppingState extends State { 5585 @Override 5586 public void enter() { 5587 /* Send any reset commands to supplicant before shutting it down */ 5588 handleNetworkDisconnect(); 5589 if (mDhcpStateMachine != null) { 5590 mDhcpStateMachine.doQuit(); 5591 } 5592 5593 String suppState = System.getProperty("init.svc.wpa_supplicant"); 5594 if (suppState == null) suppState = "unknown"; 5595 String p2pSuppState = System.getProperty("init.svc.p2p_supplicant"); 5596 if (p2pSuppState == null) p2pSuppState = "unknown"; 5597 5598 loge("SupplicantStoppingState: stopSupplicant " 5599 + " init.svc.wpa_supplicant=" + suppState 5600 + " init.svc.p2p_supplicant=" + p2pSuppState); 5601 mWifiMonitor.stopSupplicant(); 5602 5603 /* Send ourselves a delayed message to indicate failure after a wait time */ 5604 sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED, 5605 ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS); 5606 setWifiState(WIFI_STATE_DISABLING); 5607 mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE); 5608 } 5609 @Override 5610 public boolean processMessage(Message message) { 5611 logStateAndMessage(message, getClass().getSimpleName()); 5612 5613 switch(message.what) { 5614 case WifiMonitor.SUP_CONNECTION_EVENT: 5615 loge("Supplicant connection received while stopping"); 5616 break; 5617 case WifiMonitor.SUP_DISCONNECTION_EVENT: 5618 if (DBG) log("Supplicant connection lost"); 5619 handleSupplicantConnectionLoss(); 5620 transitionTo(mInitialState); 5621 break; 5622 case CMD_STOP_SUPPLICANT_FAILED: 5623 if (message.arg1 == mSupplicantStopFailureToken) { 5624 loge("Timed out on a supplicant stop, kill and proceed"); 5625 handleSupplicantConnectionLoss(); 5626 transitionTo(mInitialState); 5627 } 5628 break; 5629 case CMD_START_SUPPLICANT: 5630 case CMD_STOP_SUPPLICANT: 5631 case CMD_START_AP: 5632 case CMD_STOP_AP: 5633 case CMD_START_DRIVER: 5634 case CMD_STOP_DRIVER: 5635 case CMD_SET_OPERATIONAL_MODE: 5636 case CMD_SET_COUNTRY_CODE: 5637 case CMD_SET_FREQUENCY_BAND: 5638 case CMD_START_PACKET_FILTERING: 5639 case CMD_STOP_PACKET_FILTERING: 5640 deferMessage(message); 5641 break; 5642 default: 5643 return NOT_HANDLED; 5644 } 5645 return HANDLED; 5646 } 5647 } 5648 5649 class DriverStartingState extends State { 5650 private int mTries; 5651 @Override 5652 public void enter() { 5653 mTries = 1; 5654 /* Send ourselves a delayed message to start driver a second time */ 5655 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 5656 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 5657 } 5658 @Override 5659 public boolean processMessage(Message message) { 5660 logStateAndMessage(message, getClass().getSimpleName()); 5661 5662 switch(message.what) { 5663 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 5664 SupplicantState state = handleSupplicantStateChange(message); 5665 /* If suplicant is exiting out of INTERFACE_DISABLED state into 5666 * a state that indicates driver has started, it is ready to 5667 * receive driver commands 5668 */ 5669 if (SupplicantState.isDriverActive(state)) { 5670 transitionTo(mDriverStartedState); 5671 } 5672 break; 5673 case CMD_DRIVER_START_TIMED_OUT: 5674 if (message.arg1 == mDriverStartToken) { 5675 if (mTries >= 2) { 5676 loge("Failed to start driver after " + mTries); 5677 transitionTo(mDriverStoppedState); 5678 } else { 5679 loge("Driver start failed, retrying"); 5680 mWakeLock.acquire(); 5681 mWifiNative.startDriver(); 5682 mWakeLock.release(); 5683 5684 ++mTries; 5685 /* Send ourselves a delayed message to start driver again */ 5686 sendMessageDelayed(obtainMessage(CMD_DRIVER_START_TIMED_OUT, 5687 ++mDriverStartToken, 0), DRIVER_START_TIME_OUT_MSECS); 5688 } 5689 } 5690 break; 5691 /* Queue driver commands & connection events */ 5692 case CMD_START_DRIVER: 5693 case CMD_STOP_DRIVER: 5694 case WifiMonitor.NETWORK_CONNECTION_EVENT: 5695 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 5696 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 5697 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 5698 case WifiMonitor.WPS_OVERLAP_EVENT: 5699 case CMD_SET_COUNTRY_CODE: 5700 case CMD_SET_FREQUENCY_BAND: 5701 case CMD_START_PACKET_FILTERING: 5702 case CMD_STOP_PACKET_FILTERING: 5703 case CMD_START_SCAN: 5704 case CMD_DISCONNECT: 5705 case CMD_REASSOCIATE: 5706 case CMD_RECONNECT: 5707 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 5708 deferMessage(message); 5709 break; 5710 case WifiMonitor.SCAN_RESULTS_EVENT: 5711 // Loose scan results obtained in Driver Starting state, they can only confuse 5712 // the state machine 5713 break; 5714 default: 5715 return NOT_HANDLED; 5716 } 5717 return HANDLED; 5718 } 5719 } 5720 5721 class DriverStartedState extends State { 5722 @Override 5723 public void enter() { 5724 5725 if (PDBG) { 5726 loge("DriverStartedState enter"); 5727 } 5728 mIsRunning = true; 5729 mInDelayedStop = false; 5730 mDelayedStopCounter++; 5731 updateBatteryWorkSource(null); 5732 /** 5733 * Enable bluetooth coexistence scan mode when bluetooth connection is active. 5734 * When this mode is on, some of the low-level scan parameters used by the 5735 * driver are changed to reduce interference with bluetooth 5736 */ 5737 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 5738 /* set frequency band of operation */ 5739 setFrequencyBand(); 5740 /* initialize network state */ 5741 setNetworkDetailedState(DetailedState.DISCONNECTED); 5742 5743 /* Remove any filtering on Multicast v6 at start */ 5744 mWifiNative.stopFilteringMulticastV6Packets(); 5745 5746 /* Reset Multicast v4 filtering state */ 5747 if (mFilteringMulticastV4Packets.get()) { 5748 mWifiNative.startFilteringMulticastV4Packets(); 5749 } else { 5750 mWifiNative.stopFilteringMulticastV4Packets(); 5751 } 5752 5753 mDhcpActive = false; 5754 5755 startBatchedScan(); 5756 5757 if (mOperationalMode != CONNECT_MODE) { 5758 mWifiNative.disconnect(); 5759 mWifiConfigStore.disableAllNetworks(); 5760 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 5761 setWifiState(WIFI_STATE_DISABLED); 5762 } 5763 transitionTo(mScanModeState); 5764 } else { 5765 5766 // Status pulls in the current supplicant state and network connection state 5767 // events over the monitor connection. This helps framework sync up with 5768 // current supplicant state 5769 // TODO: actually check th supplicant status string and make sure the supplicant 5770 // is in disconnecte4d state. 5771 mWifiNative.status(); 5772 // Transitioning to Disconnected state will trigger a scan and subsequently AutoJoin 5773 transitionTo(mDisconnectedState); 5774 } 5775 5776 // We may have missed screen update at boot 5777 if (mScreenBroadcastReceived.get() == false) { 5778 PowerManager powerManager = (PowerManager)mContext.getSystemService( 5779 Context.POWER_SERVICE); 5780 handleScreenStateChanged(powerManager.isScreenOn(), 5781 /* startBackgroundScanIfNeeded = */ false); 5782 } else { 5783 // Set the right suspend mode settings 5784 mWifiNative.setSuspendOptimizations(mSuspendOptNeedsDisabled == 0 5785 && mUserWantsSuspendOpt.get()); 5786 } 5787 mWifiNative.setPowerSave(true); 5788 5789 if (mP2pSupported) { 5790 if (mOperationalMode == CONNECT_MODE) { 5791 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); 5792 } else { 5793 // P2P statemachine starts in disabled state, and is not enabled until 5794 // CMD_ENABLE_P2P is sent from here; so, nothing needs to be done to 5795 // keep it disabled. 5796 } 5797 } 5798 5799 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 5800 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 5801 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_ENABLED); 5802 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 5803 5804 if (WifiNative.startHal()) { 5805 mHalFeatureSet = WifiNative.getSupportedFeatureSet(); 5806 if ((mHalFeatureSet & WifiManager.WIFI_FEATURE_HAL_EPNO) 5807 == WifiManager.WIFI_FEATURE_HAL_EPNO) { 5808 mAlwaysOnPnoSupported = true; 5809 } 5810 } 5811 5812 if (PDBG) { 5813 loge("Driverstarted State enter done, epno=" + mAlwaysOnPnoSupported 5814 + " feature=" + mHalFeatureSet); 5815 } 5816 } 5817 5818 @Override 5819 public boolean processMessage(Message message) { 5820 logStateAndMessage(message, getClass().getSimpleName()); 5821 5822 switch(message.what) { 5823 case CMD_START_SCAN: 5824 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 5825 break; 5826 case CMD_SET_BATCHED_SCAN: 5827 if (recordBatchedScanSettings(message.arg1, message.arg2, 5828 (Bundle) message.obj)) { 5829 if (mBatchedScanSettings != null) { 5830 startBatchedScan(); 5831 } else { 5832 stopBatchedScan(); 5833 } 5834 } 5835 break; 5836 case CMD_SET_FREQUENCY_BAND: 5837 int band = message.arg1; 5838 if (DBG) log("set frequency band " + band); 5839 if (mWifiNative.setBand(band)) { 5840 5841 if (PDBG) loge("did set frequency band " + band); 5842 5843 mFrequencyBand.set(band); 5844 // Flush old data - like scan results 5845 mWifiNative.bssFlush(); 5846 // Fetch the latest scan results when frequency band is set 5847 startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, null); 5848 5849 if (PDBG) loge("done set frequency band " + band); 5850 5851 } else { 5852 loge("Failed to set frequency band " + band); 5853 } 5854 break; 5855 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 5856 mBluetoothConnectionActive = (message.arg1 != 5857 BluetoothAdapter.STATE_DISCONNECTED); 5858 mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive); 5859 break; 5860 case CMD_STOP_DRIVER: 5861 int mode = message.arg1; 5862 5863 /* Already doing a delayed stop */ 5864 if (mInDelayedStop) { 5865 if (DBG) log("Already in delayed stop"); 5866 break; 5867 } 5868 /* disconnect right now, but leave the driver running for a bit */ 5869 mWifiConfigStore.disableAllNetworks(); 5870 5871 mInDelayedStop = true; 5872 mDelayedStopCounter++; 5873 if (DBG) log("Delayed stop message " + mDelayedStopCounter); 5874 5875 /* send regular delayed shut down */ 5876 Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); 5877 driverStopIntent.setPackage(this.getClass().getPackage().getName()); 5878 driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); 5879 mDriverStopIntent = PendingIntent.getBroadcast(mContext, 5880 DRIVER_STOP_REQUEST, driverStopIntent, 5881 PendingIntent.FLAG_UPDATE_CURRENT); 5882 5883 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 5884 + mDriverStopDelayMs, mDriverStopIntent); 5885 break; 5886 case CMD_START_DRIVER: 5887 if (mInDelayedStop) { 5888 mInDelayedStop = false; 5889 mDelayedStopCounter++; 5890 mAlarmManager.cancel(mDriverStopIntent); 5891 if (DBG) log("Delayed stop ignored due to start"); 5892 if (mOperationalMode == CONNECT_MODE) { 5893 mWifiConfigStore.enableAllNetworks(); 5894 } 5895 } 5896 break; 5897 case CMD_DELAYED_STOP_DRIVER: 5898 if (DBG) log("delayed stop " + message.arg1 + " " + mDelayedStopCounter); 5899 if (message.arg1 != mDelayedStopCounter) break; 5900 if (getCurrentState() != mDisconnectedState) { 5901 mWifiNative.disconnect(); 5902 handleNetworkDisconnect(); 5903 } 5904 mWakeLock.acquire(); 5905 mWifiNative.stopDriver(); 5906 mWakeLock.release(); 5907 if (mP2pSupported) { 5908 transitionTo(mWaitForP2pDisableState); 5909 } else { 5910 transitionTo(mDriverStoppingState); 5911 } 5912 break; 5913 case CMD_START_PACKET_FILTERING: 5914 if (message.arg1 == MULTICAST_V6) { 5915 mWifiNative.startFilteringMulticastV6Packets(); 5916 } else if (message.arg1 == MULTICAST_V4) { 5917 mWifiNative.startFilteringMulticastV4Packets(); 5918 } else { 5919 loge("Illegal arugments to CMD_START_PACKET_FILTERING"); 5920 } 5921 break; 5922 case CMD_STOP_PACKET_FILTERING: 5923 if (message.arg1 == MULTICAST_V6) { 5924 mWifiNative.stopFilteringMulticastV6Packets(); 5925 } else if (message.arg1 == MULTICAST_V4) { 5926 mWifiNative.stopFilteringMulticastV4Packets(); 5927 } else { 5928 loge("Illegal arugments to CMD_STOP_PACKET_FILTERING"); 5929 } 5930 break; 5931 case CMD_SET_SUSPEND_OPT_ENABLED: 5932 if (message.arg1 == 1) { 5933 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, true); 5934 mSuspendWakeLock.release(); 5935 } else { 5936 setSuspendOptimizationsNative(SUSPEND_DUE_TO_SCREEN, false); 5937 } 5938 break; 5939 case CMD_SET_HIGH_PERF_MODE: 5940 if (message.arg1 == 1) { 5941 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, false); 5942 } else { 5943 setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true); 5944 } 5945 break; 5946 case CMD_ENABLE_TDLS: 5947 if (message.obj != null) { 5948 String remoteAddress = (String) message.obj; 5949 boolean enable = (message.arg1 == 1); 5950 mWifiNative.startTdls(remoteAddress, enable); 5951 } 5952 break; 5953 default: 5954 return NOT_HANDLED; 5955 } 5956 return HANDLED; 5957 } 5958 @Override 5959 public void exit() { 5960 mIsRunning = false; 5961 updateBatteryWorkSource(null); 5962 mScanResults = new ArrayList<>(); 5963 5964 stopBatchedScan(); 5965 5966 final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE); 5967 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 5968 intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED); 5969 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 5970 noteScanEnd(); // wrap up any pending request. 5971 mBufferedScanMsg.clear(); 5972 } 5973 } 5974 5975 class WaitForP2pDisableState extends State { 5976 private State mTransitionToState; 5977 @Override 5978 public void enter() { 5979 switch (getCurrentMessage().what) { 5980 case WifiMonitor.SUP_DISCONNECTION_EVENT: 5981 mTransitionToState = mInitialState; 5982 break; 5983 case CMD_DELAYED_STOP_DRIVER: 5984 mTransitionToState = mDriverStoppingState; 5985 break; 5986 case CMD_STOP_SUPPLICANT: 5987 mTransitionToState = mSupplicantStoppingState; 5988 break; 5989 default: 5990 mTransitionToState = mDriverStoppingState; 5991 break; 5992 } 5993 mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ); 5994 } 5995 @Override 5996 public boolean processMessage(Message message) { 5997 logStateAndMessage(message, getClass().getSimpleName()); 5998 5999 switch(message.what) { 6000 case WifiStateMachine.CMD_DISABLE_P2P_RSP: 6001 transitionTo(mTransitionToState); 6002 break; 6003 /* Defer wifi start/shut and driver commands */ 6004 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6005 case CMD_START_SUPPLICANT: 6006 case CMD_STOP_SUPPLICANT: 6007 case CMD_START_AP: 6008 case CMD_STOP_AP: 6009 case CMD_START_DRIVER: 6010 case CMD_STOP_DRIVER: 6011 case CMD_SET_OPERATIONAL_MODE: 6012 case CMD_SET_COUNTRY_CODE: 6013 case CMD_SET_FREQUENCY_BAND: 6014 case CMD_START_PACKET_FILTERING: 6015 case CMD_STOP_PACKET_FILTERING: 6016 case CMD_START_SCAN: 6017 case CMD_DISCONNECT: 6018 case CMD_REASSOCIATE: 6019 case CMD_RECONNECT: 6020 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 6021 deferMessage(message); 6022 break; 6023 default: 6024 return NOT_HANDLED; 6025 } 6026 return HANDLED; 6027 } 6028 } 6029 6030 class DriverStoppingState extends State { 6031 @Override 6032 public boolean processMessage(Message message) { 6033 logStateAndMessage(message, getClass().getSimpleName()); 6034 6035 switch(message.what) { 6036 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6037 SupplicantState state = handleSupplicantStateChange(message); 6038 if (state == SupplicantState.INTERFACE_DISABLED) { 6039 transitionTo(mDriverStoppedState); 6040 } 6041 break; 6042 /* Queue driver commands */ 6043 case CMD_START_DRIVER: 6044 case CMD_STOP_DRIVER: 6045 case CMD_SET_COUNTRY_CODE: 6046 case CMD_SET_FREQUENCY_BAND: 6047 case CMD_START_PACKET_FILTERING: 6048 case CMD_STOP_PACKET_FILTERING: 6049 case CMD_START_SCAN: 6050 case CMD_DISCONNECT: 6051 case CMD_REASSOCIATE: 6052 case CMD_RECONNECT: 6053 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 6054 deferMessage(message); 6055 break; 6056 default: 6057 return NOT_HANDLED; 6058 } 6059 return HANDLED; 6060 } 6061 } 6062 6063 class DriverStoppedState extends State { 6064 @Override 6065 public boolean processMessage(Message message) { 6066 logStateAndMessage(message, getClass().getSimpleName()); 6067 switch (message.what) { 6068 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6069 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 6070 SupplicantState state = stateChangeResult.state; 6071 // A WEXT bug means that we can be back to driver started state 6072 // unexpectedly 6073 if (SupplicantState.isDriverActive(state)) { 6074 transitionTo(mDriverStartedState); 6075 } 6076 break; 6077 case CMD_START_DRIVER: 6078 mWakeLock.acquire(); 6079 mWifiNative.startDriver(); 6080 mWakeLock.release(); 6081 transitionTo(mDriverStartingState); 6082 break; 6083 default: 6084 return NOT_HANDLED; 6085 } 6086 return HANDLED; 6087 } 6088 } 6089 6090 class ScanModeState extends State { 6091 private int mLastOperationMode; 6092 @Override 6093 public void enter() { 6094 mLastOperationMode = mOperationalMode; 6095 } 6096 @Override 6097 public boolean processMessage(Message message) { 6098 logStateAndMessage(message, getClass().getSimpleName()); 6099 6100 switch(message.what) { 6101 case CMD_SET_OPERATIONAL_MODE: 6102 if (message.arg1 == CONNECT_MODE) { 6103 6104 if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 6105 setWifiState(WIFI_STATE_ENABLED); 6106 // Load and re-enable networks when going back to enabled state 6107 // This is essential for networks to show up after restore 6108 mWifiConfigStore.loadAndEnableAllNetworks(); 6109 mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P); 6110 } else { 6111 mWifiConfigStore.enableAllNetworks(); 6112 } 6113 6114 // Try autojoining with recent network already present in the cache 6115 // If none are found then trigger a scan which will trigger autojoin 6116 // upon reception of scan results event 6117 if (!mWifiAutoJoinController.attemptAutoJoin()) { 6118 startScan(ENABLE_WIFI, 0, null, null); 6119 } 6120 6121 // Loose last selection choice since user toggled WiFi 6122 mWifiConfigStore. 6123 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 6124 6125 mOperationalMode = CONNECT_MODE; 6126 transitionTo(mDisconnectedState); 6127 } else { 6128 // Nothing to do 6129 return HANDLED; 6130 } 6131 break; 6132 // Handle scan. All the connection related commands are 6133 // handled only in ConnectModeState 6134 case CMD_START_SCAN: 6135 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 6136 break; 6137 default: 6138 return NOT_HANDLED; 6139 } 6140 return HANDLED; 6141 } 6142 } 6143 6144 6145 String smToString(Message message) { 6146 return smToString(message.what); 6147 } 6148 6149 String smToString(int what) { 6150 String s = "unknown"; 6151 switch (what) { 6152 case WifiMonitor.DRIVER_HUNG_EVENT: 6153 s = "DRIVER_HUNG_EVENT"; 6154 break; 6155 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 6156 s = "AsyncChannel.CMD_CHANNEL_HALF_CONNECTED"; 6157 break; 6158 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 6159 s = "AsyncChannel.CMD_CHANNEL_DISCONNECTED"; 6160 break; 6161 case CMD_SET_FREQUENCY_BAND: 6162 s = "CMD_SET_FREQUENCY_BAND"; 6163 break; 6164 case CMD_DELAYED_NETWORK_DISCONNECT: 6165 s = "CMD_DELAYED_NETWORK_DISCONNECT"; 6166 break; 6167 case CMD_TEST_NETWORK_DISCONNECT: 6168 s = "CMD_TEST_NETWORK_DISCONNECT"; 6169 break; 6170 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: 6171 s = "CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER"; 6172 break; 6173 case CMD_DISABLE_EPHEMERAL_NETWORK: 6174 s = "CMD_DISABLE_EPHEMERAL_NETWORK"; 6175 break; 6176 case CMD_START_DRIVER: 6177 s = "CMD_START_DRIVER"; 6178 break; 6179 case CMD_STOP_DRIVER: 6180 s = "CMD_STOP_DRIVER"; 6181 break; 6182 case CMD_STOP_SUPPLICANT: 6183 s = "CMD_STOP_SUPPLICANT"; 6184 break; 6185 case CMD_STOP_SUPPLICANT_FAILED: 6186 s = "CMD_STOP_SUPPLICANT_FAILED"; 6187 break; 6188 case CMD_START_SUPPLICANT: 6189 s = "CMD_START_SUPPLICANT"; 6190 break; 6191 case CMD_REQUEST_AP_CONFIG: 6192 s = "CMD_REQUEST_AP_CONFIG"; 6193 break; 6194 case CMD_RESPONSE_AP_CONFIG: 6195 s = "CMD_RESPONSE_AP_CONFIG"; 6196 break; 6197 case CMD_TETHER_STATE_CHANGE: 6198 s = "CMD_TETHER_STATE_CHANGE"; 6199 break; 6200 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 6201 s = "CMD_TETHER_NOTIFICATION_TIMED_OUT"; 6202 break; 6203 case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE: 6204 s = "CMD_BLUETOOTH_ADAPTER_STATE_CHANGE"; 6205 break; 6206 case CMD_ADD_OR_UPDATE_NETWORK: 6207 s = "CMD_ADD_OR_UPDATE_NETWORK"; 6208 break; 6209 case CMD_REMOVE_NETWORK: 6210 s = "CMD_REMOVE_NETWORK"; 6211 break; 6212 case CMD_ENABLE_NETWORK: 6213 s = "CMD_ENABLE_NETWORK"; 6214 break; 6215 case CMD_ENABLE_ALL_NETWORKS: 6216 s = "CMD_ENABLE_ALL_NETWORKS"; 6217 break; 6218 case CMD_AUTO_CONNECT: 6219 s = "CMD_AUTO_CONNECT"; 6220 break; 6221 case CMD_AUTO_ROAM: 6222 s = "CMD_AUTO_ROAM"; 6223 break; 6224 case CMD_AUTO_SAVE_NETWORK: 6225 s = "CMD_AUTO_SAVE_NETWORK"; 6226 break; 6227 case CMD_BOOT_COMPLETED: 6228 s = "CMD_BOOT_COMPLETED"; 6229 break; 6230 case DhcpStateMachine.CMD_START_DHCP: 6231 s = "CMD_START_DHCP"; 6232 break; 6233 case DhcpStateMachine.CMD_STOP_DHCP: 6234 s = "CMD_STOP_DHCP"; 6235 break; 6236 case DhcpStateMachine.CMD_RENEW_DHCP: 6237 s = "CMD_RENEW_DHCP"; 6238 break; 6239 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 6240 s = "CMD_PRE_DHCP_ACTION"; 6241 break; 6242 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 6243 s = "CMD_POST_DHCP_ACTION"; 6244 break; 6245 case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE: 6246 s = "CMD_PRE_DHCP_ACTION_COMPLETE"; 6247 break; 6248 case DhcpStateMachine.CMD_ON_QUIT: 6249 s = "CMD_ON_QUIT"; 6250 break; 6251 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 6252 s = "WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST"; 6253 break; 6254 case WifiManager.DISABLE_NETWORK: 6255 s = "WifiManager.DISABLE_NETWORK"; 6256 break; 6257 case CMD_BLACKLIST_NETWORK: 6258 s = "CMD_BLACKLIST_NETWORK"; 6259 break; 6260 case CMD_CLEAR_BLACKLIST: 6261 s = "CMD_CLEAR_BLACKLIST"; 6262 break; 6263 case CMD_SAVE_CONFIG: 6264 s = "CMD_SAVE_CONFIG"; 6265 break; 6266 case CMD_GET_CONFIGURED_NETWORKS: 6267 s = "CMD_GET_CONFIGURED_NETWORKS"; 6268 break; 6269 case CMD_GET_SUPPORTED_FEATURES: 6270 s = "CMD_GET_SUPPORTED_FEATURES"; 6271 break; 6272 case CMD_UNWANTED_NETWORK: 6273 s = "CMD_UNWANTED_NETWORK"; 6274 break; 6275 case CMD_NETWORK_STATUS: 6276 s = "CMD_NETWORK_STATUS"; 6277 break; 6278 case CMD_GET_LINK_LAYER_STATS: 6279 s = "CMD_GET_LINK_LAYER_STATS"; 6280 break; 6281 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS: 6282 s = "CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS"; 6283 break; 6284 case CMD_DISCONNECT: 6285 s = "CMD_DISCONNECT"; 6286 break; 6287 case CMD_RECONNECT: 6288 s = "CMD_RECONNECT"; 6289 break; 6290 case CMD_REASSOCIATE: 6291 s = "CMD_REASSOCIATE"; 6292 break; 6293 case CMD_GET_CONNECTION_STATISTICS: 6294 s = "CMD_GET_CONNECTION_STATISTICS"; 6295 break; 6296 case CMD_SET_HIGH_PERF_MODE: 6297 s = "CMD_SET_HIGH_PERF_MODE"; 6298 break; 6299 case CMD_SET_COUNTRY_CODE: 6300 s = "CMD_SET_COUNTRY_CODE"; 6301 break; 6302 case CMD_ENABLE_RSSI_POLL: 6303 s = "CMD_ENABLE_RSSI_POLL"; 6304 break; 6305 case CMD_RSSI_POLL: 6306 s = "CMD_RSSI_POLL"; 6307 break; 6308 case CMD_START_PACKET_FILTERING: 6309 s = "CMD_START_PACKET_FILTERING"; 6310 break; 6311 case CMD_STOP_PACKET_FILTERING: 6312 s = "CMD_STOP_PACKET_FILTERING"; 6313 break; 6314 case CMD_SET_SUSPEND_OPT_ENABLED: 6315 s = "CMD_SET_SUSPEND_OPT_ENABLED"; 6316 break; 6317 case CMD_NO_NETWORKS_PERIODIC_SCAN: 6318 s = "CMD_NO_NETWORKS_PERIODIC_SCAN"; 6319 break; 6320 case CMD_SET_BATCHED_SCAN: 6321 s = "CMD_SET_BATCHED_SCAN"; 6322 break; 6323 case CMD_START_NEXT_BATCHED_SCAN: 6324 s = "CMD_START_NEXT_BATCHED_SCAN"; 6325 break; 6326 case CMD_POLL_BATCHED_SCAN: 6327 s = "CMD_POLL_BATCHED_SCAN"; 6328 break; 6329 case CMD_UPDATE_LINKPROPERTIES: 6330 s = "CMD_UPDATE_LINKPROPERTIES"; 6331 break; 6332 case CMD_RELOAD_TLS_AND_RECONNECT: 6333 s = "CMD_RELOAD_TLS_AND_RECONNECT"; 6334 break; 6335 case WifiManager.CONNECT_NETWORK: 6336 s = "CONNECT_NETWORK"; 6337 break; 6338 case WifiManager.SAVE_NETWORK: 6339 s = "SAVE_NETWORK"; 6340 break; 6341 case WifiManager.FORGET_NETWORK: 6342 s = "FORGET_NETWORK"; 6343 break; 6344 case WifiMonitor.SUP_CONNECTION_EVENT: 6345 s = "SUP_CONNECTION_EVENT"; 6346 break; 6347 case WifiMonitor.SUP_DISCONNECTION_EVENT: 6348 s = "SUP_DISCONNECTION_EVENT"; 6349 break; 6350 case WifiMonitor.SCAN_RESULTS_EVENT: 6351 s = "SCAN_RESULTS_EVENT"; 6352 break; 6353 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6354 s = "SUPPLICANT_STATE_CHANGE_EVENT"; 6355 break; 6356 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 6357 s = "AUTHENTICATION_FAILURE_EVENT"; 6358 break; 6359 case WifiMonitor.SSID_TEMP_DISABLED: 6360 s = "SSID_TEMP_DISABLED"; 6361 break; 6362 case WifiMonitor.SSID_REENABLED: 6363 s = "SSID_REENABLED"; 6364 break; 6365 case WifiMonitor.WPS_SUCCESS_EVENT: 6366 s = "WPS_SUCCESS_EVENT"; 6367 break; 6368 case WifiMonitor.WPS_FAIL_EVENT: 6369 s = "WPS_FAIL_EVENT"; 6370 break; 6371 case WifiMonitor.SUP_REQUEST_IDENTITY: 6372 s = "SUP_REQUEST_IDENTITY"; 6373 break; 6374 case WifiMonitor.NETWORK_CONNECTION_EVENT: 6375 s = "NETWORK_CONNECTION_EVENT"; 6376 break; 6377 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 6378 s = "NETWORK_DISCONNECTION_EVENT"; 6379 break; 6380 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 6381 s = "ASSOCIATION_REJECTION_EVENT"; 6382 break; 6383 case CMD_SET_OPERATIONAL_MODE: 6384 s = "CMD_SET_OPERATIONAL_MODE"; 6385 break; 6386 case CMD_START_SCAN: 6387 s = "CMD_START_SCAN"; 6388 break; 6389 case CMD_DISABLE_P2P_RSP: 6390 s = "CMD_DISABLE_P2P_RSP"; 6391 break; 6392 case CMD_DISABLE_P2P_REQ: 6393 s = "CMD_DISABLE_P2P_REQ"; 6394 break; 6395 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 6396 s = "GOOD_LINK_DETECTED"; 6397 break; 6398 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 6399 s = "POOR_LINK_DETECTED"; 6400 break; 6401 case WifiP2pServiceImpl.GROUP_CREATING_TIMED_OUT: 6402 s = "GROUP_CREATING_TIMED_OUT"; 6403 break; 6404 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 6405 s = "P2P_CONNECTION_CHANGED"; 6406 break; 6407 case WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE: 6408 s = "P2P.DISCONNECT_WIFI_RESPONSE"; 6409 break; 6410 case WifiP2pServiceImpl.SET_MIRACAST_MODE: 6411 s = "P2P.SET_MIRACAST_MODE"; 6412 break; 6413 case WifiP2pServiceImpl.BLOCK_DISCOVERY: 6414 s = "P2P.BLOCK_DISCOVERY"; 6415 break; 6416 case WifiP2pServiceImpl.SET_COUNTRY_CODE: 6417 s = "P2P.SET_COUNTRY_CODE"; 6418 break; 6419 case WifiManager.CANCEL_WPS: 6420 s = "CANCEL_WPS"; 6421 break; 6422 case WifiManager.CANCEL_WPS_FAILED: 6423 s = "CANCEL_WPS_FAILED"; 6424 break; 6425 case WifiManager.CANCEL_WPS_SUCCEDED: 6426 s = "CANCEL_WPS_SUCCEDED"; 6427 break; 6428 case WifiManager.START_WPS: 6429 s = "START_WPS"; 6430 break; 6431 case WifiManager.START_WPS_SUCCEEDED: 6432 s = "START_WPS_SUCCEEDED"; 6433 break; 6434 case WifiManager.WPS_FAILED: 6435 s = "WPS_FAILED"; 6436 break; 6437 case WifiManager.WPS_COMPLETED: 6438 s = "WPS_COMPLETED"; 6439 break; 6440 case WifiManager.RSSI_PKTCNT_FETCH: 6441 s = "RSSI_PKTCNT_FETCH"; 6442 break; 6443 case CMD_IP_CONFIGURATION_LOST: 6444 s = "CMD_IP_CONFIGURATION_LOST"; 6445 break; 6446 case CMD_IP_CONFIGURATION_SUCCESSFUL: 6447 s = "CMD_IP_CONFIGURATION_SUCCESSFUL"; 6448 break; 6449 case CMD_STATIC_IP_SUCCESS: 6450 s = "CMD_STATIC_IP_SUCCESSFUL"; 6451 break; 6452 case CMD_STATIC_IP_FAILURE: 6453 s = "CMD_STATIC_IP_FAILURE"; 6454 break; 6455 case DhcpStateMachine.DHCP_SUCCESS: 6456 s = "DHCP_SUCCESS"; 6457 break; 6458 case DhcpStateMachine.DHCP_FAILURE: 6459 s = "DHCP_FAILURE"; 6460 break; 6461 case CMD_TARGET_BSSID: 6462 s = "CMD_TARGET_BSSID"; 6463 break; 6464 case CMD_ASSOCIATED_BSSID: 6465 s = "CMD_ASSOCIATED_BSSID"; 6466 break; 6467 case CMD_ROAM_WATCHDOG_TIMER: 6468 s = "CMD_ROAM_WATCHDOG_TIMER"; 6469 break; 6470 case CMD_SCREEN_STATE_CHANGED: 6471 s = "CMD_SCREEN_STATE_CHANGED"; 6472 break; 6473 case CMD_DISCONNECTING_WATCHDOG_TIMER: 6474 s = "CMD_DISCONNECTING_WATCHDOG_TIMER"; 6475 break; 6476 case CMD_START_PNO: 6477 s = "CMD_START_PNO"; 6478 break; 6479 case CMD_STARTED_PNO_DBG: 6480 s = "CMD_STARTED_PNO_DBG"; 6481 break; 6482 case CMD_PNO_NETWORK_FOUND: 6483 s = "CMD_PNO_NETWORK_FOUND"; 6484 break; 6485 default: 6486 s = "what:" + Integer.toString(what); 6487 break; 6488 } 6489 return s; 6490 } 6491 6492 void registerConnected() { 6493 if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 6494 long now_ms = System.currentTimeMillis(); 6495 // We are switching away from this configuration, 6496 // hence record the time we were connected last 6497 WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 6498 if (config != null) { 6499 config.lastConnected = System.currentTimeMillis(); 6500 config.autoJoinBailedDueToLowRssi = false; 6501 config.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED); 6502 config.numConnectionFailures = 0; 6503 config.numIpConfigFailures = 0; 6504 config.numAuthFailures = 0; 6505 config.numAssociation++; 6506 } 6507 mBadLinkspeedcount = 0; 6508 } 6509 } 6510 6511 void registerDisconnected() { 6512 if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 6513 long now_ms = System.currentTimeMillis(); 6514 // We are switching away from this configuration, 6515 // hence record the time we were connected last 6516 WifiConfiguration config = mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 6517 if (config != null) { 6518 config.lastDisconnected = System.currentTimeMillis(); 6519 if (config.ephemeral) { 6520 // Remove ephemeral WifiConfigurations from file 6521 mWifiConfigStore.forgetNetwork(mLastNetworkId); 6522 } 6523 } 6524 } 6525 } 6526 6527 void noteWifiDisabledWhileAssociated() { 6528 // We got disabled by user while we were associated, make note of it 6529 int rssi = mWifiInfo.getRssi(); 6530 WifiConfiguration config = getCurrentWifiConfiguration(); 6531 if (getCurrentState() == mConnectedState 6532 && rssi != WifiInfo.INVALID_RSSI 6533 && config != null) { 6534 boolean is24GHz = mWifiInfo.is24GHz(); 6535 boolean isBadRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdBadRssi24.get()) 6536 || (!is24GHz && rssi < mWifiConfigStore.thresholdBadRssi5.get()); 6537 boolean isLowRSSI = (is24GHz && rssi < mWifiConfigStore.thresholdLowRssi24.get()) 6538 || (!is24GHz && mWifiInfo.getRssi() < mWifiConfigStore.thresholdLowRssi5.get()); 6539 boolean isHighRSSI = (is24GHz && rssi >= mWifiConfigStore.thresholdGoodRssi24.get()) 6540 || (!is24GHz && mWifiInfo.getRssi() >= mWifiConfigStore.thresholdGoodRssi5.get()); 6541 if (isBadRSSI) { 6542 // Take note that we got disabled while RSSI was Bad 6543 config.numUserTriggeredWifiDisableLowRSSI++; 6544 } else if (isLowRSSI) { 6545 // Take note that we got disabled while RSSI was Low 6546 config.numUserTriggeredWifiDisableBadRSSI++; 6547 } else if (!isHighRSSI) { 6548 // Take note that we got disabled while RSSI was Not high 6549 config.numUserTriggeredWifiDisableNotHighRSSI++; 6550 } 6551 } 6552 } 6553 6554 WifiConfiguration getCurrentWifiConfiguration() { 6555 if (mLastNetworkId == WifiConfiguration.INVALID_NETWORK_ID) { 6556 return null; 6557 } 6558 return mWifiConfigStore.getWifiConfiguration(mLastNetworkId); 6559 } 6560 6561 ScanResult getCurrentScanResult() { 6562 WifiConfiguration config = getCurrentWifiConfiguration(); 6563 if (config == null) { 6564 return null; 6565 } 6566 String BSSID = mWifiInfo.getBSSID(); 6567 if (BSSID == null) { 6568 BSSID = mTargetRoamBSSID; 6569 } 6570 ScanDetailCache scanDetailCache = 6571 mWifiConfigStore.getScanDetailCache(config); 6572 6573 if (scanDetailCache == null) { 6574 return null; 6575 } 6576 6577 return scanDetailCache.get(BSSID); 6578 } 6579 6580 String getCurrentBSSID() { 6581 if (linkDebouncing) { 6582 return null; 6583 } 6584 return mLastBssid; 6585 } 6586 6587 class ConnectModeState extends State { 6588 @Override 6589 public boolean processMessage(Message message) { 6590 WifiConfiguration config; 6591 int netId; 6592 boolean ok; 6593 boolean didDisconnect; 6594 String bssid; 6595 String ssid; 6596 NetworkUpdateResult result; 6597 logStateAndMessage(message, getClass().getSimpleName()); 6598 6599 connectScanningService(); 6600 6601 switch (message.what) { 6602 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 6603 didBlackListBSSID = false; 6604 bssid = (String) message.obj; 6605 if (bssid == null || TextUtils.isEmpty(bssid)) { 6606 // If BSSID is null, use the target roam BSSID 6607 bssid = mTargetRoamBSSID; 6608 } 6609 if (bssid != null) { 6610 // If we have a BSSID, tell configStore to black list it 6611 synchronized(mScanResultCache) { 6612 didBlackListBSSID = mWifiConfigStore.handleBSSIDBlackList 6613 (mLastNetworkId, bssid, false); 6614 } 6615 } 6616 mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT); 6617 break; 6618 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 6619 mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT); 6620 break; 6621 case WifiMonitor.SSID_TEMP_DISABLED: 6622 case WifiMonitor.SSID_REENABLED: 6623 String substr = (String) message.obj; 6624 String en = message.what == WifiMonitor.SSID_TEMP_DISABLED ? 6625 "temp-disabled" : "re-enabled"; 6626 loge("ConnectModeState SSID state=" + en + " nid=" 6627 + Integer.toString(message.arg1) + " [" + substr + "]"); 6628 synchronized(mScanResultCache) { 6629 mWifiConfigStore.handleSSIDStateChange(message.arg1, message.what == 6630 WifiMonitor.SSID_REENABLED, substr, mWifiInfo.getBSSID()); 6631 } 6632 break; 6633 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 6634 SupplicantState state = handleSupplicantStateChange(message); 6635 // A driver/firmware hang can now put the interface in a down state. 6636 // We detect the interface going down and recover from it 6637 if (!SupplicantState.isDriverActive(state)) { 6638 if (mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 6639 handleNetworkDisconnect(); 6640 } 6641 log("Detected an interface down, restart driver"); 6642 transitionTo(mDriverStoppedState); 6643 sendMessage(CMD_START_DRIVER); 6644 break; 6645 } 6646 6647 // Supplicant can fail to report a NETWORK_DISCONNECTION_EVENT 6648 // when authentication times out after a successful connection, 6649 // we can figure this from the supplicant state. If supplicant 6650 // state is DISCONNECTED, but the mNetworkInfo says we are not 6651 // disconnected, we need to handle a disconnection 6652 if (!linkDebouncing && state == SupplicantState.DISCONNECTED && 6653 mNetworkInfo.getState() != NetworkInfo.State.DISCONNECTED) { 6654 if (DBG) log("Missed CTRL-EVENT-DISCONNECTED, disconnect"); 6655 handleNetworkDisconnect(); 6656 transitionTo(mDisconnectedState); 6657 } 6658 break; 6659 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 6660 if (message.arg1 == 1) { 6661 mWifiNative.disconnect(); 6662 mTemporarilyDisconnectWifi = true; 6663 } else { 6664 mWifiNative.reconnect(); 6665 mTemporarilyDisconnectWifi = false; 6666 } 6667 break; 6668 case CMD_ADD_OR_UPDATE_NETWORK: 6669 config = (WifiConfiguration) message.obj; 6670 int res = mWifiConfigStore.addOrUpdateNetwork(config, message.sendingUid); 6671 if (res < 0) { 6672 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 6673 } else { 6674 WifiConfiguration curConfig = getCurrentWifiConfiguration(); 6675 if (curConfig != null && config != null) { 6676 if (curConfig.priority < config.priority 6677 && config.status == WifiConfiguration.Status.ENABLED) { 6678 // Interpret this as a connect attempt 6679 // Set the last selected configuration so as to allow the system to 6680 // stick the last user choice without persisting the choice 6681 mWifiConfigStore.setLastSelectedConfiguration(res); 6682 6683 // Remember time of last connection attempt 6684 lastConnectAttempt = System.currentTimeMillis(); 6685 6686 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 6687 6688 // As a courtesy to the caller, trigger a scan now 6689 startScan(ADD_OR_UPDATE_SOURCE, 0, null, null); 6690 } 6691 } 6692 } 6693 replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK, res); 6694 break; 6695 case CMD_REMOVE_NETWORK: 6696 ok = mWifiConfigStore.removeNetwork(message.arg1); 6697 if (!ok) { 6698 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 6699 } 6700 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 6701 break; 6702 case CMD_ENABLE_NETWORK: 6703 boolean others = message.arg2 == 1; 6704 // Tell autojoin the user did try to select to that network 6705 // However, do NOT persist the choice by bumping the priority of the network 6706 if (others) { 6707 mWifiAutoJoinController. 6708 updateConfigurationHistory(message.arg1, true, false); 6709 // Set the last selected configuration so as to allow the system to 6710 // stick the last user choice without persisting the choice 6711 mWifiConfigStore.setLastSelectedConfiguration(message.arg1); 6712 6713 // Remember time of last connection attempt 6714 lastConnectAttempt = System.currentTimeMillis(); 6715 6716 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 6717 } 6718 // Cancel auto roam requests 6719 autoRoamSetBSSID(message.arg1, "any"); 6720 6721 ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1); 6722 if (!ok) { 6723 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 6724 } 6725 replyToMessage(message, message.what, ok ? SUCCESS : FAILURE); 6726 break; 6727 case CMD_ENABLE_ALL_NETWORKS: 6728 long time = android.os.SystemClock.elapsedRealtime(); 6729 if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) { 6730 mWifiConfigStore.enableAllNetworks(); 6731 mLastEnableAllNetworksTime = time; 6732 } 6733 break; 6734 case WifiManager.DISABLE_NETWORK: 6735 if (mWifiConfigStore.disableNetwork(message.arg1, 6736 WifiConfiguration.DISABLED_BY_WIFI_MANAGER) == true) { 6737 replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED); 6738 } else { 6739 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 6740 replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED, 6741 WifiManager.ERROR); 6742 } 6743 break; 6744 case CMD_DISABLE_EPHEMERAL_NETWORK: 6745 config = mWifiConfigStore.disableEphemeralNetwork((String)message.obj); 6746 if (config != null) { 6747 if (config.networkId == mLastNetworkId) { 6748 // Disconnect and let autojoin reselect a new network 6749 sendMessage(CMD_DISCONNECT); 6750 } 6751 } 6752 break; 6753 case CMD_BLACKLIST_NETWORK: 6754 mWifiNative.addToBlacklist((String) message.obj); 6755 break; 6756 case CMD_CLEAR_BLACKLIST: 6757 mWifiNative.clearBlacklist(); 6758 break; 6759 case CMD_SAVE_CONFIG: 6760 ok = mWifiConfigStore.saveConfig(); 6761 6762 if (DBG) loge("wifistatemachine did save config " + ok); 6763 replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE); 6764 6765 // Inform the backup manager about a data change 6766 IBackupManager ibm = IBackupManager.Stub.asInterface( 6767 ServiceManager.getService(Context.BACKUP_SERVICE)); 6768 if (ibm != null) { 6769 try { 6770 ibm.dataChanged("com.android.providers.settings"); 6771 } catch (Exception e) { 6772 // Try again later 6773 } 6774 } 6775 break; 6776 case CMD_GET_CONFIGURED_NETWORKS: 6777 replyToMessage(message, message.what, 6778 mWifiConfigStore.getConfiguredNetworks()); 6779 break; 6780 case WifiMonitor.SUP_REQUEST_IDENTITY: 6781 int networkId = message.arg2; 6782 boolean identitySent = false; 6783 int eapMethod = WifiEnterpriseConfig.Eap.NONE; 6784 6785 if (targetWificonfiguration != null 6786 && targetWificonfiguration.enterpriseConfig != null) { 6787 eapMethod = targetWificonfiguration.enterpriseConfig.getEapMethod(); 6788 } 6789 6790 // For SIM & AKA/AKA' EAP method Only, get identity from ICC 6791 if (targetWificonfiguration != null 6792 && targetWificonfiguration.networkId == networkId 6793 && targetWificonfiguration.allowedKeyManagement 6794 .get(WifiConfiguration.KeyMgmt.IEEE8021X) 6795 && (eapMethod == WifiEnterpriseConfig.Eap.SIM 6796 || eapMethod == WifiEnterpriseConfig.Eap.AKA 6797 || eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME)) { 6798 TelephonyManager tm = (TelephonyManager) 6799 mContext.getSystemService(Context.TELEPHONY_SERVICE); 6800 if (tm != null) { 6801 String imsi = tm.getSubscriberId(); 6802 String mccMnc = ""; 6803 6804 if (tm.getSimState() == TelephonyManager.SIM_STATE_READY) 6805 mccMnc = tm.getSimOperator(); 6806 6807 String identity = buildIdentity(eapMethod, imsi, mccMnc); 6808 6809 if (!identity.isEmpty()) { 6810 mWifiNative.simIdentityResponse(networkId, identity); 6811 identitySent = true; 6812 } 6813 } 6814 } 6815 if (!identitySent) { 6816 // Supplicant lacks credentials to connect to that network, hence black list 6817 ssid = (String) message.obj; 6818 if (targetWificonfiguration != null && ssid != null 6819 && targetWificonfiguration.SSID != null 6820 && targetWificonfiguration.SSID.equals("\"" + ssid + "\"")) { 6821 mWifiConfigStore.handleSSIDStateChange( 6822 targetWificonfiguration.networkId, false, 6823 "AUTH_FAILED no identity", null); 6824 } 6825 // Disconnect now, as we don't have any way to fullfill 6826 // the supplicant request. 6827 mWifiConfigStore.setLastSelectedConfiguration( 6828 WifiConfiguration.INVALID_NETWORK_ID); 6829 mWifiNative.disconnect(); 6830 } 6831 break; 6832 case WifiMonitor.SUP_REQUEST_SIM_AUTH: 6833 logd("Received SUP_REQUEST_SIM_AUTH"); 6834 SimAuthRequestData requestData = (SimAuthRequestData) message.obj; 6835 if (requestData != null) { 6836 if (requestData.protocol == WifiEnterpriseConfig.Eap.SIM) { 6837 handleGsmAuthRequest(requestData); 6838 } else if (requestData.protocol == WifiEnterpriseConfig.Eap.AKA 6839 || requestData.protocol == WifiEnterpriseConfig.Eap.AKA_PRIME) { 6840 handle3GAuthRequest(requestData); 6841 } 6842 } else { 6843 loge("Invalid sim auth request"); 6844 } 6845 break; 6846 case CMD_GET_PRIVILEGED_CONFIGURED_NETWORKS: 6847 replyToMessage(message, message.what, 6848 mWifiConfigStore.getPrivilegedConfiguredNetworks()); 6849 break; 6850 case CMD_GET_MATCHING_CONFIG: 6851 replyToMessage(message, message.what, 6852 mWifiConfigStore.getMatchingConfig((ScanResult)message.obj)); 6853 break; 6854 /* Do a redundant disconnect without transition */ 6855 case CMD_DISCONNECT: 6856 mWifiConfigStore.setLastSelectedConfiguration 6857 (WifiConfiguration.INVALID_NETWORK_ID); 6858 mWifiNative.disconnect(); 6859 break; 6860 case CMD_RECONNECT: 6861 mWifiAutoJoinController.attemptAutoJoin(); 6862 break; 6863 case CMD_REASSOCIATE: 6864 lastConnectAttempt = System.currentTimeMillis(); 6865 mWifiNative.reassociate(); 6866 break; 6867 case CMD_RELOAD_TLS_AND_RECONNECT: 6868 if (mWifiConfigStore.needsUnlockedKeyStore()) { 6869 logd("Reconnecting to give a chance to un-connected TLS networks"); 6870 mWifiNative.disconnect(); 6871 lastConnectAttempt = System.currentTimeMillis(); 6872 mWifiNative.reconnect(); 6873 } 6874 break; 6875 case CMD_AUTO_ROAM: 6876 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 6877 return HANDLED; 6878 case CMD_AUTO_CONNECT: 6879 /* Work Around: wpa_supplicant can get in a bad state where it returns a non 6880 * associated status to the STATUS command but somehow-someplace still thinks 6881 * it is associated and thus will ignore select/reconnect command with 6882 * following message: 6883 * "Already associated with the selected network - do nothing" 6884 * 6885 * Hence, sends a disconnect to supplicant first. 6886 */ 6887 didDisconnect = false; 6888 if (getCurrentState() != mDisconnectedState) { 6889 /** Supplicant will ignore the reconnect if we are currently associated, 6890 * hence trigger a disconnect 6891 */ 6892 didDisconnect = true; 6893 mWifiNative.disconnect(); 6894 } 6895 6896 /* connect command coming from auto-join */ 6897 config = (WifiConfiguration) message.obj; 6898 netId = message.arg1; 6899 int roam = message.arg2; 6900 loge("CMD_AUTO_CONNECT sup state " 6901 + mSupplicantStateTracker.getSupplicantStateName() 6902 + " my state " + getCurrentState().getName() 6903 + " nid=" + Integer.toString(netId) 6904 + " roam=" + Integer.toString(roam)); 6905 if (config == null) { 6906 loge("AUTO_CONNECT and no config, bail out..."); 6907 break; 6908 } 6909 6910 /* Make sure we cancel any previous roam request */ 6911 autoRoamSetBSSID(netId, config.BSSID); 6912 6913 /* Save the network config */ 6914 loge("CMD_AUTO_CONNECT will save config -> " + config.SSID 6915 + " nid=" + Integer.toString(netId)); 6916 result = mWifiConfigStore.saveNetwork(config, -1); 6917 netId = result.getNetworkId(); 6918 loge("CMD_AUTO_CONNECT did save config -> " 6919 + " nid=" + Integer.toString(netId)); 6920 6921 // Make sure the network is enabled, since supplicant will not reenable it 6922 mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false); 6923 6924 if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ false) && 6925 mWifiNative.reconnect()) { 6926 lastConnectAttempt = System.currentTimeMillis(); 6927 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 6928 config = mWifiConfigStore.getWifiConfiguration(netId); 6929 if (config != null 6930 && !mWifiConfigStore.isLastSelectedConfiguration(config)) { 6931 // If we autojoined a different config than the user selected one, 6932 // it means we could not see the last user selection, 6933 // or that the last user selection was faulty and ended up blacklisted 6934 // for some reason (in which case the user is notified with an error 6935 // message in the Wifi picker), and thus we managed to auto-join away 6936 // from the selected config. -> in that case we need to forget 6937 // the selection because we don't want to abruptly switch back to it. 6938 // 6939 // Note that the user selection is also forgotten after a period of time 6940 // during which the device has been disconnected. 6941 // The default value is 30 minutes : see the code path at bottom of 6942 // setScanResults() function. 6943 mWifiConfigStore. 6944 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 6945 } 6946 mAutoRoaming = roam; 6947 if (isRoaming() || linkDebouncing) { 6948 transitionTo(mRoamingState); 6949 } else if (didDisconnect) { 6950 transitionTo(mDisconnectingState); 6951 } else { 6952 /* Already in disconnected state, nothing to change */ 6953 } 6954 } else { 6955 loge("Failed to connect config: " + config + " netId: " + netId); 6956 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 6957 WifiManager.ERROR); 6958 break; 6959 } 6960 break; 6961 case WifiManager.CONNECT_NETWORK: 6962 /** 6963 * The connect message can contain a network id passed as arg1 on message or 6964 * or a config passed as obj on message. 6965 * For a new network, a config is passed to create and connect. 6966 * For an existing network, a network id is passed 6967 */ 6968 netId = message.arg1; 6969 config = (WifiConfiguration) message.obj; 6970 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 6971 boolean updatedExisting = false; 6972 6973 /* Save the network config */ 6974 if (config != null) { 6975 String configKey = config.configKey(true /* allowCached */); 6976 WifiConfiguration savedConfig = 6977 mWifiConfigStore.getWifiConfiguration(configKey); 6978 if (savedConfig != null) { 6979 // There is an existing config with this netId, but it wasn't exposed 6980 // (either AUTO_JOIN_DELETED or ephemeral; see WifiConfigStore# 6981 // getConfiguredNetworks). Remove those bits and update the config. 6982 config = savedConfig; 6983 loge("CONNECT_NETWORK updating existing config with id=" + 6984 config.networkId + " configKey=" + configKey); 6985 config.ephemeral = false; 6986 config.autoJoinStatus = WifiConfiguration.AUTO_JOIN_ENABLED; 6987 updatedExisting = true; 6988 } 6989 6990 result = mWifiConfigStore.saveNetwork(config, message.sendingUid); 6991 netId = result.getNetworkId(); 6992 } 6993 config = mWifiConfigStore.getWifiConfiguration(netId); 6994 6995 if (config == null) { 6996 loge("CONNECT_NETWORK no config for id=" + Integer.toString(netId) + " " 6997 + mSupplicantStateTracker.getSupplicantStateName() + " my state " 6998 + getCurrentState().getName()); 6999 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 7000 WifiManager.ERROR); 7001 break; 7002 } else { 7003 String wasSkipped = config.autoJoinBailedDueToLowRssi ? " skipped" : ""; 7004 loge("CONNECT_NETWORK id=" + Integer.toString(netId) 7005 + " config=" + config.SSID 7006 + " cnid=" + config.networkId 7007 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 7008 + " my state " + getCurrentState().getName() 7009 + " uid = " + message.sendingUid 7010 + wasSkipped); 7011 } 7012 7013 autoRoamSetBSSID(netId, "any"); 7014 7015 if (message.sendingUid == Process.WIFI_UID 7016 || message.sendingUid == Process.SYSTEM_UID) { 7017 // As a sanity measure, clear the BSSID in the supplicant network block. 7018 // If system or Wifi Settings want to connect, they will not 7019 // specify the BSSID. 7020 // If an app however had added a BSSID to this configuration, and the BSSID 7021 // was wrong, Then we would forever fail to connect until that BSSID 7022 // is cleaned up. 7023 clearConfigBSSID(config, "CONNECT_NETWORK"); 7024 } 7025 7026 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 7027 7028 /* Tell autojoin the user did try to connect to that network */ 7029 mWifiAutoJoinController.updateConfigurationHistory(netId, true, true); 7030 7031 mWifiConfigStore.setLastSelectedConfiguration(netId); 7032 7033 didDisconnect = false; 7034 if (mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID 7035 && mLastNetworkId != netId) { 7036 /** Supplicant will ignore the reconnect if we are currently associated, 7037 * hence trigger a disconnect 7038 */ 7039 didDisconnect = true; 7040 mWifiNative.disconnect(); 7041 } 7042 7043 // Make sure the network is enabled, since supplicant will not reenable it 7044 mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false); 7045 7046 if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ true) && 7047 mWifiNative.reconnect()) { 7048 lastConnectAttempt = System.currentTimeMillis(); 7049 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 7050 7051 /* The state tracker handles enabling networks upon completion/failure */ 7052 mSupplicantStateTracker.sendMessage(WifiManager.CONNECT_NETWORK); 7053 replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 7054 if (didDisconnect) { 7055 /* Expect a disconnection from the old connection */ 7056 transitionTo(mDisconnectingState); 7057 } else if (updatedExisting && getCurrentState() == mConnectedState && 7058 getCurrentWifiConfiguration().networkId == netId) { 7059 // Update the current set of network capabilities, but stay in the 7060 // current state. 7061 updateCapabilities(config); 7062 } else { 7063 /** 7064 * Directly go to disconnected state where we 7065 * process the connection events from supplicant 7066 **/ 7067 transitionTo(mDisconnectedState); 7068 } 7069 } else { 7070 loge("Failed to connect config: " + config + " netId: " + netId); 7071 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 7072 WifiManager.ERROR); 7073 break; 7074 } 7075 break; 7076 case WifiManager.SAVE_NETWORK: 7077 mWifiConnectionStatistics.numWifiManagerJoinAttempt++; 7078 // Fall thru 7079 case WifiStateMachine.CMD_AUTO_SAVE_NETWORK: 7080 lastSavedConfigurationAttempt = null; // Used for debug 7081 config = (WifiConfiguration) message.obj; 7082 if (config == null) { 7083 loge("ERROR: SAVE_NETWORK with null configuration" 7084 + mSupplicantStateTracker.getSupplicantStateName() 7085 + " my state " + getCurrentState().getName()); 7086 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 7087 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 7088 WifiManager.ERROR); 7089 break; 7090 } 7091 lastSavedConfigurationAttempt = new WifiConfiguration(config); 7092 int nid = config.networkId; 7093 loge("SAVE_NETWORK id=" + Integer.toString(nid) 7094 + " config=" + config.SSID 7095 + " nid=" + config.networkId 7096 + " supstate=" + mSupplicantStateTracker.getSupplicantStateName() 7097 + " my state " + getCurrentState().getName()); 7098 7099 result = mWifiConfigStore.saveNetwork(config, -1); 7100 if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) { 7101 if (mWifiInfo.getNetworkId() == result.getNetworkId()) { 7102 if (result.hasIpChanged()) { 7103 // The currently connection configuration was changed 7104 // We switched from DHCP to static or from static to DHCP, or the 7105 // static IP address has changed. 7106 log("Reconfiguring IP on connection"); 7107 // TODO: clear addresses and disable IPv6 7108 // to simplify obtainingIpState. 7109 transitionTo(mObtainingIpState); 7110 } 7111 if (result.hasProxyChanged()) { 7112 log("Reconfiguring proxy on connection"); 7113 updateLinkProperties(CMD_UPDATE_LINKPROPERTIES); 7114 } 7115 } 7116 replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED); 7117 if (VDBG) { 7118 loge("Success save network nid=" 7119 + Integer.toString(result.getNetworkId())); 7120 } 7121 7122 synchronized(mScanResultCache) { 7123 /** 7124 * If the command comes from WifiManager, then 7125 * tell autojoin the user did try to modify and save that network, 7126 * and interpret the SAVE_NETWORK as a request to connect 7127 */ 7128 boolean user = message.what == WifiManager.SAVE_NETWORK; 7129 mWifiAutoJoinController.updateConfigurationHistory(result.getNetworkId() 7130 , user, true); 7131 mWifiAutoJoinController.attemptAutoJoin(); 7132 } 7133 } else { 7134 loge("Failed to save network"); 7135 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 7136 replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, 7137 WifiManager.ERROR); 7138 } 7139 break; 7140 case WifiManager.FORGET_NETWORK: 7141 // Debug only, remember last configuration that was forgotten 7142 WifiConfiguration toRemove 7143 = mWifiConfigStore.getWifiConfiguration(message.arg1); 7144 if (toRemove == null) { 7145 lastForgetConfigurationAttempt = null; 7146 } else { 7147 lastForgetConfigurationAttempt = new WifiConfiguration(toRemove); 7148 } 7149 if (mWifiConfigStore.forgetNetwork(message.arg1)) { 7150 replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED); 7151 } else { 7152 loge("Failed to forget network"); 7153 replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED, 7154 WifiManager.ERROR); 7155 } 7156 break; 7157 case WifiManager.START_WPS: 7158 WpsInfo wpsInfo = (WpsInfo) message.obj; 7159 WpsResult wpsResult; 7160 switch (wpsInfo.setup) { 7161 case WpsInfo.PBC: 7162 wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo); 7163 break; 7164 case WpsInfo.KEYPAD: 7165 wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo); 7166 break; 7167 case WpsInfo.DISPLAY: 7168 wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo); 7169 break; 7170 default: 7171 wpsResult = new WpsResult(Status.FAILURE); 7172 loge("Invalid setup for WPS"); 7173 break; 7174 } 7175 mWifiConfigStore.setLastSelectedConfiguration 7176 (WifiConfiguration.INVALID_NETWORK_ID); 7177 if (wpsResult.status == Status.SUCCESS) { 7178 replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult); 7179 transitionTo(mWpsRunningState); 7180 } else { 7181 loge("Failed to start WPS with config " + wpsInfo.toString()); 7182 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR); 7183 } 7184 break; 7185 case WifiMonitor.NETWORK_CONNECTION_EVENT: 7186 if (DBG) log("Network connection established"); 7187 mLastNetworkId = message.arg1; 7188 mLastBssid = (String) message.obj; 7189 7190 mWifiInfo.setBSSID(mLastBssid); 7191 mWifiInfo.setNetworkId(mLastNetworkId); 7192 7193 sendNetworkStateChangeBroadcast(mLastBssid); 7194 transitionTo(mObtainingIpState); 7195 break; 7196 case WifiMonitor.ANQP_DONE_EVENT: 7197 Log.d("HS2J", String.format("WFSM: ANQP for %016x %s", 7198 (Long)message.obj, message.arg1 != 0 ? "success" : "fail")); 7199 mWifiConfigStore.notifyANQPDone((Long) message.obj, message.arg1 != 0); 7200 break; 7201 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 7202 // Calling handleNetworkDisconnect here is redundant because we might already 7203 // have called it when leaving L2ConnectedState to go to disconnecting state 7204 // or thru other path 7205 // We should normally check the mWifiInfo or mLastNetworkId so as to check 7206 // if they are valid, and only in this case call handleNEtworkDisconnect, 7207 // TODO: this should be fixed for a L MR release 7208 // The side effect of calling handleNetworkDisconnect twice is that a bunch of 7209 // idempotent commands are executed twice (stopping Dhcp, enabling the SPS mode 7210 // at the chip etc... 7211 if (DBG) log("ConnectModeState: Network connection lost "); 7212 handleNetworkDisconnect(); 7213 transitionTo(mDisconnectedState); 7214 break; 7215 case CMD_START_PNO: 7216 // Restart Pno if required, reevaluating the list of networks 7217 startPno(); 7218 break; 7219 case CMD_PNO_NETWORK_FOUND: 7220 processPnoNetworkFound((ScanResult[])message.obj); 7221 break; 7222 default: 7223 return NOT_HANDLED; 7224 } 7225 return HANDLED; 7226 } 7227 } 7228 7229 private void updateCapabilities(WifiConfiguration config) { 7230 if (config.ephemeral) { 7231 mNetworkCapabilities.removeCapability( 7232 NetworkCapabilities.NET_CAPABILITY_TRUSTED); 7233 } else { 7234 mNetworkCapabilities.addCapability( 7235 NetworkCapabilities.NET_CAPABILITY_TRUSTED); 7236 } 7237 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); 7238 } 7239 7240 private class WifiNetworkAgent extends NetworkAgent { 7241 public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni, 7242 NetworkCapabilities nc, LinkProperties lp, int score) { 7243 super(l, c, TAG, ni, nc, lp, score); 7244 } 7245 protected void unwanted() { 7246 // Ignore if we're not the current networkAgent. 7247 if (this != mNetworkAgent) return; 7248 if (DBG) log("WifiNetworkAgent -> Wifi unwanted score " 7249 + Integer.toString(mWifiInfo.score)); 7250 unwantedNetwork(network_status_unwanted_disconnect); 7251 } 7252 7253 protected void networkStatus(int status) { 7254 if (status == NetworkAgent.INVALID_NETWORK) { 7255 if (DBG) log("WifiNetworkAgent -> Wifi networkStatus invalid, score=" 7256 + Integer.toString(mWifiInfo.score)); 7257 unwantedNetwork(network_status_unwanted_disable_autojoin); 7258 } else if (status == NetworkAgent.VALID_NETWORK) { 7259 if (DBG && mWifiInfo != null) log("WifiNetworkAgent -> Wifi networkStatus valid, score= " 7260 + Integer.toString(mWifiInfo.score)); 7261 doNetworkStatus(status); 7262 } 7263 } 7264 } 7265 7266 void unwantedNetwork(int reason) { 7267 sendMessage(CMD_UNWANTED_NETWORK, reason); 7268 } 7269 7270 void doNetworkStatus(int status) { 7271 sendMessage(CMD_NETWORK_STATUS, status); 7272 } 7273 7274 // rfc4186 & rfc4187: 7275 // create Permanent Identity base on IMSI, 7276 // identity = usernam@realm 7277 // with username = prefix | IMSI 7278 // and realm is derived MMC/MNC tuple according 3GGP spec(TS23.003) 7279 private String buildIdentity(int eapMethod, String imsi, String mccMnc) { 7280 String mcc; 7281 String mnc; 7282 String prefix; 7283 7284 if (imsi == null || imsi.isEmpty()) 7285 return ""; 7286 7287 if (eapMethod == WifiEnterpriseConfig.Eap.SIM) 7288 prefix = "1"; 7289 else if (eapMethod == WifiEnterpriseConfig.Eap.AKA) 7290 prefix = "0"; 7291 else if (eapMethod == WifiEnterpriseConfig.Eap.AKA_PRIME) 7292 prefix = "6"; 7293 else // not a valide EapMethod 7294 return ""; 7295 7296 /* extract mcc & mnc from mccMnc */ 7297 if (mccMnc != null && !mccMnc.isEmpty()) { 7298 mcc = mccMnc.substring(0, 3); 7299 mnc = mccMnc.substring(3); 7300 if (mnc.length() == 2) 7301 mnc = "0" + mnc; 7302 } else { 7303 // extract mcc & mnc from IMSI, assume mnc size is 3 7304 mcc = imsi.substring(0, 3); 7305 mnc = imsi.substring(3, 6); 7306 } 7307 7308 return prefix + imsi + "@wlan.mnc" + mnc + ".mcc" + mcc + ".3gppnetwork.org"; 7309 } 7310 7311 boolean startScanForConfiguration(WifiConfiguration config, boolean restrictChannelList) { 7312 if (config == null) 7313 return false; 7314 7315 // We are still seeing a fairly high power consumption triggered by autojoin scans 7316 // Hence do partial scans only for PSK configuration that are roamable since the 7317 // primary purpose of the partial scans is roaming. 7318 // Full badn scans with exponential backoff for the purpose or extended roaming and 7319 // network switching are performed unconditionally. 7320 ScanDetailCache scanDetailCache = 7321 mWifiConfigStore.getScanDetailCache(config); 7322 if (scanDetailCache == null 7323 || !config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK) 7324 || scanDetailCache.size() > 6) { 7325 //return true but to not trigger the scan 7326 return true; 7327 } 7328 HashSet<Integer> channels = mWifiConfigStore.makeChannelList(config, 7329 ONE_HOUR_MILLI, restrictChannelList); 7330 if (channels != null && channels.size() != 0) { 7331 StringBuilder freqs = new StringBuilder(); 7332 boolean first = true; 7333 for (Integer channel : channels) { 7334 if (!first) 7335 freqs.append(","); 7336 freqs.append(channel.toString()); 7337 first = false; 7338 } 7339 //if (DBG) { 7340 loge("WifiStateMachine starting scan for " + config.configKey() + " with " + freqs); 7341 //} 7342 // Call wifi native to start the scan 7343 if (startScanNative( 7344 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, 7345 freqs.toString())) { 7346 // Only count battery consumption if scan request is accepted 7347 noteScanStart(SCAN_ALARM_SOURCE, null); 7348 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OK; 7349 } else { 7350 // used for debug only, mark scan as failed 7351 messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR; 7352 } 7353 return true; 7354 } else { 7355 if (DBG) loge("WifiStateMachine no channels for " + config.configKey()); 7356 return false; 7357 } 7358 } 7359 7360 void clearCurrentConfigBSSID(String dbg) { 7361 // Clear the bssid in the current config's network block 7362 WifiConfiguration config = getCurrentWifiConfiguration(); 7363 if (config == null) 7364 return; 7365 clearConfigBSSID(config, dbg); 7366 } 7367 void clearConfigBSSID(WifiConfiguration config, String dbg) { 7368 if (config == null) 7369 return; 7370 if (DBG) { 7371 loge(dbg + " " + mTargetRoamBSSID + " config " + config.configKey() 7372 + " config.bssid " + config.BSSID); 7373 } 7374 config.autoJoinBSSID = "any"; 7375 config.BSSID = "any"; 7376 if (DBG) { 7377 loge(dbg + " " + config.SSID 7378 + " nid=" + Integer.toString(config.networkId)); 7379 } 7380 mWifiConfigStore.saveWifiConfigBSSID(config); 7381 } 7382 7383 class L2ConnectedState extends State { 7384 @Override 7385 public void enter() { 7386 mRssiPollToken++; 7387 if (mEnableRssiPolling) { 7388 sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0); 7389 } 7390 if (mNetworkAgent != null) { 7391 loge("Have NetworkAgent when entering L2Connected"); 7392 setNetworkDetailedState(DetailedState.DISCONNECTED); 7393 } 7394 setNetworkDetailedState(DetailedState.CONNECTING); 7395 7396 if (TextUtils.isEmpty(mTcpBufferSizes) == false) { 7397 mLinkProperties.setTcpBufferSizes(mTcpBufferSizes); 7398 } 7399 mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext, 7400 "WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter, 7401 mLinkProperties, 60); 7402 7403 // We must clear the config BSSID, as the wifi chipset may decide to roam 7404 // from this point on and having the BSSID specified in the network block would 7405 // cause the roam to faile and the device to disconnect 7406 clearCurrentConfigBSSID("L2ConnectedState"); 7407 } 7408 7409 @Override 7410 public void exit() { 7411 // This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState 7412 // Bug: 15347363 7413 // For paranoia's sake, call handleNetworkDisconnect 7414 // only if BSSID is null or last networkId 7415 // is not invalid. 7416 if (DBG) { 7417 StringBuilder sb = new StringBuilder(); 7418 sb.append("leaving L2ConnectedState state nid=" + Integer.toString(mLastNetworkId)); 7419 if (mLastBssid !=null) { 7420 sb.append(" ").append(mLastBssid); 7421 } 7422 } 7423 if (mLastBssid != null || mLastNetworkId != WifiConfiguration.INVALID_NETWORK_ID) { 7424 handleNetworkDisconnect(); 7425 } 7426 } 7427 7428 @Override 7429 public boolean processMessage(Message message) { 7430 logStateAndMessage(message, getClass().getSimpleName()); 7431 7432 switch (message.what) { 7433 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 7434 handlePreDhcpSetup(); 7435 break; 7436 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 7437 handlePostDhcpSetup(); 7438 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) { 7439 if (DBG) log("WifiStateMachine DHCP successful"); 7440 handleIPv4Success((DhcpResults) message.obj, DhcpStateMachine.DHCP_SUCCESS); 7441 // We advance to mVerifyingLinkState because handleIPv4Success will call 7442 // updateLinkProperties, which then sends CMD_IP_CONFIGURATION_SUCCESSFUL. 7443 } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) { 7444 if (DBG) { 7445 int count = -1; 7446 WifiConfiguration config = getCurrentWifiConfiguration(); 7447 if (config != null) { 7448 count = config.numConnectionFailures; 7449 } 7450 log("WifiStateMachine DHCP failure count=" + count); 7451 } 7452 handleIPv4Failure(DhcpStateMachine.DHCP_FAILURE); 7453 // As above, we transition to mDisconnectingState via updateLinkProperties. 7454 } 7455 break; 7456 case CMD_IP_CONFIGURATION_SUCCESSFUL: 7457 handleSuccessfulIpConfiguration(); 7458 sendConnectedState(); 7459 transitionTo(mConnectedState); 7460 break; 7461 case CMD_IP_CONFIGURATION_LOST: 7462 // Get Link layer stats so as we get fresh tx packet counters 7463 getWifiLinkLayerStats(true); 7464 handleIpConfigurationLost(); 7465 transitionTo(mDisconnectingState); 7466 break; 7467 case CMD_DISCONNECT: 7468 mWifiNative.disconnect(); 7469 transitionTo(mDisconnectingState); 7470 break; 7471 case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: 7472 if (message.arg1 == 1) { 7473 mWifiNative.disconnect(); 7474 mTemporarilyDisconnectWifi = true; 7475 transitionTo(mDisconnectingState); 7476 } 7477 break; 7478 case CMD_SET_OPERATIONAL_MODE: 7479 if (message.arg1 != CONNECT_MODE) { 7480 sendMessage(CMD_DISCONNECT); 7481 deferMessage(message); 7482 if (message.arg1 == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 7483 noteWifiDisabledWhileAssociated(); 7484 } 7485 } 7486 mWifiConfigStore. 7487 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 7488 break; 7489 case CMD_SET_COUNTRY_CODE: 7490 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 7491 deferMessage(message); 7492 break; 7493 case CMD_START_SCAN: 7494 //if (DBG) { 7495 loge("WifiStateMachine CMD_START_SCAN source " + message.arg1 7496 + " txSuccessRate="+String.format( "%.2f", mWifiInfo.txSuccessRate) 7497 + " rxSuccessRate="+String.format( "%.2f", mWifiInfo.rxSuccessRate) 7498 + " targetRoamBSSID=" + mTargetRoamBSSID 7499 + " RSSI=" + mWifiInfo.getRssi()); 7500 //} 7501 if (message.arg1 == SCAN_ALARM_SOURCE) { 7502 // Check if the CMD_START_SCAN message is obsolete (and thus if it should 7503 // not be processed) and restart the scan if needed 7504 boolean shouldScan = 7505 mScreenOn && mWifiConfigStore.enableAutoJoinScanWhenAssociated.get(); 7506 if (!checkAndRestartDelayedScan(message.arg2, 7507 shouldScan, 7508 mWifiConfigStore.associatedPartialScanPeriodMilli.get(), null, null)) { 7509 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE; 7510 loge("WifiStateMachine L2Connected CMD_START_SCAN source " 7511 + message.arg1 7512 + " " + message.arg2 + ", " + mDelayedScanCounter 7513 + " -> obsolete"); 7514 return HANDLED; 7515 } 7516 if (mP2pConnected.get()) { 7517 loge("WifiStateMachine L2Connected CMD_START_SCAN source " 7518 + message.arg1 7519 + " " + message.arg2 + ", " + mDelayedScanCounter 7520 + " ignore because P2P is connected"); 7521 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 7522 return HANDLED; 7523 } 7524 boolean tryFullBandScan = false; 7525 boolean restrictChannelList = false; 7526 long now_ms = System.currentTimeMillis(); 7527 if (DBG) { 7528 loge("WifiStateMachine CMD_START_SCAN with age=" 7529 + Long.toString(now_ms - lastFullBandConnectedTimeMilli) 7530 + " interval=" + fullBandConnectedTimeIntervalMilli 7531 + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli); 7532 } 7533 if (mWifiInfo != null) { 7534 if (mWifiConfigStore.enableFullBandScanWhenAssociated.get() && 7535 (now_ms - lastFullBandConnectedTimeMilli) 7536 > fullBandConnectedTimeIntervalMilli) { 7537 if (DBG) { 7538 loge("WifiStateMachine CMD_START_SCAN try full band scan age=" 7539 + Long.toString(now_ms - lastFullBandConnectedTimeMilli) 7540 + " interval=" + fullBandConnectedTimeIntervalMilli 7541 + " maxinterval=" + maxFullBandConnectedTimeIntervalMilli); 7542 } 7543 tryFullBandScan = true; 7544 } 7545 7546 if (mWifiInfo.txSuccessRate > 7547 mWifiConfigStore.maxTxPacketForFullScans 7548 || mWifiInfo.rxSuccessRate > 7549 mWifiConfigStore.maxRxPacketForFullScans) { 7550 // Too much traffic at the interface, hence no full band scan 7551 if (DBG) { 7552 loge("WifiStateMachine CMD_START_SCAN " + 7553 "prevent full band scan due to pkt rate"); 7554 } 7555 tryFullBandScan = false; 7556 } 7557 7558 if (mWifiInfo.txSuccessRate > 7559 mWifiConfigStore.maxTxPacketForPartialScans 7560 || mWifiInfo.rxSuccessRate > 7561 mWifiConfigStore.maxRxPacketForPartialScans) { 7562 // Don't scan if lots of packets are being sent 7563 restrictChannelList = true; 7564 if (mWifiConfigStore.alwaysEnableScansWhileAssociated.get() == 0) { 7565 if (DBG) { 7566 loge("WifiStateMachine CMD_START_SCAN source " + message.arg1 7567 + " ...and ignore scans" 7568 + " tx=" + String.format("%.2f", mWifiInfo.txSuccessRate) 7569 + " rx=" + String.format("%.2f", mWifiInfo.rxSuccessRate)); 7570 } 7571 messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED; 7572 return HANDLED; 7573 } 7574 } 7575 } 7576 7577 WifiConfiguration currentConfiguration = getCurrentWifiConfiguration(); 7578 if (DBG) { 7579 loge("WifiStateMachine CMD_START_SCAN full=" + 7580 tryFullBandScan); 7581 } 7582 if (currentConfiguration != null) { 7583 if (fullBandConnectedTimeIntervalMilli 7584 < mWifiConfigStore.associatedPartialScanPeriodMilli.get()) { 7585 // Sanity 7586 fullBandConnectedTimeIntervalMilli 7587 = mWifiConfigStore.associatedPartialScanPeriodMilli.get(); 7588 } 7589 if (tryFullBandScan) { 7590 lastFullBandConnectedTimeMilli = now_ms; 7591 if (fullBandConnectedTimeIntervalMilli 7592 < mWifiConfigStore.associatedFullScanMaxIntervalMilli) { 7593 // Increase the interval 7594 fullBandConnectedTimeIntervalMilli 7595 = fullBandConnectedTimeIntervalMilli 7596 * mWifiConfigStore.associatedFullScanBackoff.get() / 8; 7597 7598 if (DBG) { 7599 loge("WifiStateMachine CMD_START_SCAN bump interval =" 7600 + fullBandConnectedTimeIntervalMilli); 7601 } 7602 } 7603 handleScanRequest( 7604 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 7605 } else { 7606 if (!startScanForConfiguration( 7607 currentConfiguration, restrictChannelList)) { 7608 if (DBG) { 7609 loge("WifiStateMachine starting scan, " + 7610 " did not find channels -> full"); 7611 } 7612 lastFullBandConnectedTimeMilli = now_ms; 7613 if (fullBandConnectedTimeIntervalMilli 7614 < mWifiConfigStore.associatedFullScanMaxIntervalMilli) { 7615 // Increase the interval 7616 fullBandConnectedTimeIntervalMilli 7617 = fullBandConnectedTimeIntervalMilli 7618 * mWifiConfigStore.associatedFullScanBackoff.get() / 8; 7619 7620 if (DBG) { 7621 loge("WifiStateMachine CMD_START_SCAN bump interval =" 7622 + fullBandConnectedTimeIntervalMilli); 7623 } 7624 } 7625 handleScanRequest( 7626 WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 7627 } 7628 } 7629 7630 } else { 7631 loge("CMD_START_SCAN : connected mode and no configuration"); 7632 messageHandlingStatus = MESSAGE_HANDLING_STATUS_HANDLING_ERROR; 7633 } 7634 } else { 7635 // Not scan alarm source 7636 return NOT_HANDLED; 7637 } 7638 break; 7639 /* Ignore connection to same network */ 7640 case WifiManager.CONNECT_NETWORK: 7641 int netId = message.arg1; 7642 if (mWifiInfo.getNetworkId() == netId) { 7643 break; 7644 } 7645 return NOT_HANDLED; 7646 /* Ignore */ 7647 case WifiMonitor.NETWORK_CONNECTION_EVENT: 7648 break; 7649 case CMD_RSSI_POLL: 7650 if (message.arg1 == mRssiPollToken) { 7651 if (mWifiConfigStore.enableChipWakeUpWhenAssociated.get()) { 7652 if (VVDBG) log(" get link layer stats " + mWifiLinkLayerStatsSupported); 7653 WifiLinkLayerStats stats = getWifiLinkLayerStats(VDBG); 7654 if (stats != null) { 7655 // Sanity check the results provided by driver 7656 if (mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI 7657 && (stats.rssi_mgmt == 0 7658 || stats.beacon_rx == 0)) { 7659 stats = null; 7660 } 7661 } 7662 // Get Info and continue polling 7663 fetchRssiLinkSpeedAndFrequencyNative(); 7664 calculateWifiScore(stats); 7665 } 7666 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 7667 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 7668 7669 if (DBG) sendRssiChangeBroadcast(mWifiInfo.getRssi()); 7670 } else { 7671 // Polling has completed 7672 } 7673 break; 7674 case CMD_ENABLE_RSSI_POLL: 7675 if (mWifiConfigStore.enableRssiPollWhenAssociated.get()) { 7676 mEnableRssiPolling = (message.arg1 == 1); 7677 } else { 7678 mEnableRssiPolling = false; 7679 } 7680 mRssiPollToken++; 7681 if (mEnableRssiPolling) { 7682 // First poll 7683 fetchRssiLinkSpeedAndFrequencyNative(); 7684 sendMessageDelayed(obtainMessage(CMD_RSSI_POLL, 7685 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS); 7686 } else { 7687 cleanWifiScore(); 7688 } 7689 break; 7690 case WifiManager.RSSI_PKTCNT_FETCH: 7691 RssiPacketCountInfo info = new RssiPacketCountInfo(); 7692 fetchRssiLinkSpeedAndFrequencyNative(); 7693 info.rssi = mWifiInfo.getRssi(); 7694 fetchPktcntNative(info); 7695 replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info); 7696 break; 7697 case CMD_DELAYED_NETWORK_DISCONNECT: 7698 if (!linkDebouncing && mWifiConfigStore.enableLinkDebouncing) { 7699 7700 // Ignore if we are not debouncing 7701 loge("CMD_DELAYED_NETWORK_DISCONNECT and not debouncing - ignore " 7702 + message.arg1); 7703 return HANDLED; 7704 } else { 7705 loge("CMD_DELAYED_NETWORK_DISCONNECT and debouncing - disconnect " 7706 + message.arg1); 7707 7708 linkDebouncing = false; 7709 // If we are still debouncing while this message comes, 7710 // it means we were not able to reconnect within the alloted time 7711 // = LINK_FLAPPING_DEBOUNCE_MSEC 7712 // and thus, trigger a real disconnect 7713 handleNetworkDisconnect(); 7714 transitionTo(mDisconnectedState); 7715 } 7716 break; 7717 case CMD_ASSOCIATED_BSSID: 7718 if ((String) message.obj == null) { 7719 loge("Associated command w/o BSSID"); 7720 break; 7721 } 7722 mLastBssid = (String) message.obj; 7723 if (mLastBssid != null 7724 && (mWifiInfo.getBSSID() == null 7725 || !mLastBssid.equals(mWifiInfo.getBSSID()))) { 7726 mWifiInfo.setBSSID((String) message.obj); 7727 sendNetworkStateChangeBroadcast(mLastBssid); 7728 } 7729 break; 7730 default: 7731 return NOT_HANDLED; 7732 } 7733 7734 return HANDLED; 7735 } 7736 } 7737 7738 class ObtainingIpState extends State { 7739 @Override 7740 public void enter() { 7741 if (DBG) { 7742 String key = ""; 7743 if (getCurrentWifiConfiguration() != null) { 7744 key = getCurrentWifiConfiguration().configKey(); 7745 } 7746 log("enter ObtainingIpState netId=" + Integer.toString(mLastNetworkId) 7747 + " " + key + " " 7748 + " roam=" + mAutoRoaming 7749 + " static=" + mWifiConfigStore.isUsingStaticIp(mLastNetworkId) 7750 + " watchdog= " + obtainingIpWatchdogCount); 7751 } 7752 7753 // Reset link Debouncing, indicating we have successfully re-connected to the AP 7754 // We might still be roaming 7755 linkDebouncing = false; 7756 7757 // Send event to CM & network change broadcast 7758 setNetworkDetailedState(DetailedState.OBTAINING_IPADDR); 7759 7760 // We must clear the config BSSID, as the wifi chipset may decide to roam 7761 // from this point on and having the BSSID specified in the network block would 7762 // cause the roam to faile and the device to disconnect 7763 clearCurrentConfigBSSID("ObtainingIpAddress"); 7764 7765 try { 7766 mNwService.enableIpv6(mInterfaceName); 7767 } catch (RemoteException re) { 7768 loge("Failed to enable IPv6: " + re); 7769 } catch (IllegalStateException e) { 7770 loge("Failed to enable IPv6: " + e); 7771 } 7772 7773 if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) { 7774 if (isRoaming()) { 7775 renewDhcp(); 7776 } else { 7777 // Remove any IP address on the interface in case we're switching from static 7778 // IP configuration to DHCP. This is safe because if we get here when not 7779 // roaming, we don't have a usable address. 7780 clearIPv4Address(mInterfaceName); 7781 startDhcp(); 7782 } 7783 obtainingIpWatchdogCount++; 7784 loge("Start Dhcp Watchdog " + obtainingIpWatchdogCount); 7785 // Get Link layer stats so as we get fresh tx packet counters 7786 getWifiLinkLayerStats(true); 7787 sendMessageDelayed(obtainMessage(CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER, 7788 obtainingIpWatchdogCount, 0), OBTAINING_IP_ADDRESS_GUARD_TIMER_MSEC); 7789 } else { 7790 // stop any running dhcp before assigning static IP 7791 stopDhcp(); 7792 StaticIpConfiguration config = mWifiConfigStore.getStaticIpConfiguration( 7793 mLastNetworkId); 7794 if (config.ipAddress == null) { 7795 loge("Static IP lacks address"); 7796 sendMessage(CMD_STATIC_IP_FAILURE); 7797 } else { 7798 InterfaceConfiguration ifcg = new InterfaceConfiguration(); 7799 ifcg.setLinkAddress(config.ipAddress); 7800 ifcg.setInterfaceUp(); 7801 try { 7802 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 7803 if (DBG) log("Static IP configuration succeeded"); 7804 DhcpResults dhcpResults = new DhcpResults(config); 7805 sendMessage(CMD_STATIC_IP_SUCCESS, dhcpResults); 7806 } catch (RemoteException re) { 7807 loge("Static IP configuration failed: " + re); 7808 sendMessage(CMD_STATIC_IP_FAILURE); 7809 } catch (IllegalStateException e) { 7810 loge("Static IP configuration failed: " + e); 7811 sendMessage(CMD_STATIC_IP_FAILURE); 7812 } 7813 } 7814 } 7815 } 7816 @Override 7817 public boolean processMessage(Message message) { 7818 logStateAndMessage(message, getClass().getSimpleName()); 7819 7820 switch(message.what) { 7821 case CMD_STATIC_IP_SUCCESS: 7822 handleIPv4Success((DhcpResults) message.obj, CMD_STATIC_IP_SUCCESS); 7823 break; 7824 case CMD_STATIC_IP_FAILURE: 7825 handleIPv4Failure(CMD_STATIC_IP_FAILURE); 7826 break; 7827 case CMD_AUTO_CONNECT: 7828 case CMD_AUTO_ROAM: 7829 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 7830 break; 7831 case WifiManager.SAVE_NETWORK: 7832 case WifiStateMachine.CMD_AUTO_SAVE_NETWORK: 7833 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 7834 deferMessage(message); 7835 break; 7836 /* Defer any power mode changes since we must keep active power mode at DHCP */ 7837 case CMD_SET_HIGH_PERF_MODE: 7838 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 7839 deferMessage(message); 7840 break; 7841 /* Defer scan request since we should not switch to other channels at DHCP */ 7842 case CMD_START_SCAN: 7843 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; 7844 deferMessage(message); 7845 break; 7846 case CMD_OBTAINING_IP_ADDRESS_WATCHDOG_TIMER: 7847 if (message.arg1 == obtainingIpWatchdogCount) { 7848 loge("ObtainingIpAddress: Watchdog Triggered, count=" 7849 + obtainingIpWatchdogCount); 7850 handleIpConfigurationLost(); 7851 transitionTo(mDisconnectingState); 7852 break; 7853 } 7854 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 7855 break; 7856 default: 7857 return NOT_HANDLED; 7858 } 7859 return HANDLED; 7860 } 7861 } 7862 7863 class VerifyingLinkState extends State { 7864 @Override 7865 public void enter() { 7866 log(getName() + " enter"); 7867 setNetworkDetailedState(DetailedState.VERIFYING_POOR_LINK); 7868 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.VERIFYING_POOR_LINK); 7869 sendNetworkStateChangeBroadcast(mLastBssid); 7870 // End roaming 7871 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 7872 } 7873 @Override 7874 public boolean processMessage(Message message) { 7875 logStateAndMessage(message, getClass().getSimpleName()); 7876 7877 switch (message.what) { 7878 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 7879 // Stay here 7880 log(getName() + " POOR_LINK_DETECTED: no transition"); 7881 break; 7882 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED: 7883 log(getName() + " GOOD_LINK_DETECTED: transition to captive portal check"); 7884 7885 log(getName() + " GOOD_LINK_DETECTED: transition to CONNECTED"); 7886 sendConnectedState(); 7887 transitionTo(mConnectedState); 7888 break; 7889 default: 7890 if (DBG) log(getName() + " what=" + message.what + " NOT_HANDLED"); 7891 return NOT_HANDLED; 7892 } 7893 return HANDLED; 7894 } 7895 } 7896 7897 private void sendConnectedState() { 7898 // Send out a broadcast with the CAPTIVE_PORTAL_CHECK to preserve 7899 // existing behaviour. The captive portal check really happens after we 7900 // transition into DetailedState.CONNECTED. 7901 setNetworkDetailedState(DetailedState.CAPTIVE_PORTAL_CHECK); 7902 mWifiConfigStore.updateStatus(mLastNetworkId, 7903 DetailedState.CAPTIVE_PORTAL_CHECK); 7904 sendNetworkStateChangeBroadcast(mLastBssid); 7905 7906 if (mWifiConfigStore.getLastSelectedConfiguration() != null) { 7907 if (mNetworkAgent != null) mNetworkAgent.explicitlySelected(); 7908 } 7909 7910 setNetworkDetailedState(DetailedState.CONNECTED); 7911 mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.CONNECTED); 7912 sendNetworkStateChangeBroadcast(mLastBssid); 7913 } 7914 7915 class RoamingState extends State { 7916 boolean mAssociated; 7917 @Override 7918 public void enter() { 7919 if (DBG) { 7920 log("RoamingState Enter" 7921 + " mScreenOn=" + mScreenOn ); 7922 } 7923 setScanAlarm(false); 7924 7925 // Make sure we disconnect if roaming fails 7926 roamWatchdogCount++; 7927 loge("Start Roam Watchdog " + roamWatchdogCount); 7928 sendMessageDelayed(obtainMessage(CMD_ROAM_WATCHDOG_TIMER, 7929 roamWatchdogCount, 0), ROAM_GUARD_TIMER_MSEC); 7930 mAssociated = false; 7931 } 7932 @Override 7933 public boolean processMessage(Message message) { 7934 logStateAndMessage(message, getClass().getSimpleName()); 7935 WifiConfiguration config; 7936 switch (message.what) { 7937 case CMD_IP_CONFIGURATION_LOST: 7938 config = getCurrentWifiConfiguration(); 7939 if (config != null) { 7940 mWifiConfigStore.noteRoamingFailure(config, 7941 WifiConfiguration.ROAMING_FAILURE_IP_CONFIG); 7942 } 7943 return NOT_HANDLED; 7944 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 7945 if (DBG) log("Roaming and Watchdog reports poor link -> ignore"); 7946 return HANDLED; 7947 case CMD_UNWANTED_NETWORK: 7948 if (DBG) log("Roaming and CS doesnt want the network -> ignore"); 7949 return HANDLED; 7950 case CMD_SET_OPERATIONAL_MODE: 7951 if (message.arg1 != CONNECT_MODE) { 7952 deferMessage(message); 7953 } 7954 break; 7955 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 7956 /** 7957 * If we get a SUPPLICANT_STATE_CHANGE_EVENT indicating a DISCONNECT 7958 * before NETWORK_DISCONNECTION_EVENT 7959 * And there is an associated BSSID corresponding to our target BSSID, then 7960 * we have missed the network disconnection, transition to mDisconnectedState 7961 * and handle the rest of the events there. 7962 */ 7963 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 7964 if (stateChangeResult.state == SupplicantState.DISCONNECTED 7965 || stateChangeResult.state == SupplicantState.INACTIVE 7966 || stateChangeResult.state == SupplicantState.INTERFACE_DISABLED) { 7967 if (DBG) { 7968 log("STATE_CHANGE_EVENT in roaming state " 7969 + stateChangeResult.toString() ); 7970 } 7971 if (stateChangeResult.BSSID != null 7972 && stateChangeResult.BSSID.equals(mTargetRoamBSSID)) { 7973 handleNetworkDisconnect(); 7974 transitionTo(mDisconnectedState); 7975 } 7976 } 7977 if (stateChangeResult.state == SupplicantState.ASSOCIATED) { 7978 // We completed the layer2 roaming part 7979 mAssociated = true; 7980 if (stateChangeResult.BSSID != null) { 7981 mTargetRoamBSSID = (String) stateChangeResult.BSSID; 7982 } 7983 } 7984 break; 7985 case CMD_ROAM_WATCHDOG_TIMER: 7986 if (roamWatchdogCount == message.arg1) { 7987 if (DBG) log("roaming watchdog! -> disconnect"); 7988 mRoamFailCount++; 7989 handleNetworkDisconnect(); 7990 mWifiNative.disconnect(); 7991 transitionTo(mDisconnectedState); 7992 } 7993 break; 7994 case WifiMonitor.NETWORK_CONNECTION_EVENT: 7995 if (mAssociated) { 7996 if (DBG) log("roaming and Network connection established"); 7997 mLastNetworkId = message.arg1; 7998 mLastBssid = (String) message.obj; 7999 mWifiInfo.setBSSID(mLastBssid); 8000 mWifiInfo.setNetworkId(mLastNetworkId); 8001 mWifiConfigStore.handleBSSIDBlackList(mLastNetworkId, mLastBssid, true); 8002 sendNetworkStateChangeBroadcast(mLastBssid); 8003 transitionTo(mObtainingIpState); 8004 } else { 8005 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 8006 } 8007 break; 8008 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 8009 // Throw away but only if it corresponds to the network we're roaming to 8010 String bssid = (String)message.obj; 8011 if (true) { 8012 String target = ""; 8013 if (mTargetRoamBSSID != null) target = mTargetRoamBSSID; 8014 log("NETWORK_DISCONNECTION_EVENT in roaming state" 8015 + " BSSID=" + bssid 8016 + " target=" + target); 8017 } 8018 if (bssid != null && bssid.equals(mTargetRoamBSSID)) { 8019 handleNetworkDisconnect(); 8020 transitionTo(mDisconnectedState); 8021 } 8022 break; 8023 case WifiMonitor.SSID_TEMP_DISABLED: 8024 // Auth error while roaming 8025 loge("SSID_TEMP_DISABLED nid=" + Integer.toString(mLastNetworkId) 8026 + " id=" + Integer.toString(message.arg1) 8027 + " isRoaming=" + isRoaming() 8028 + " roam=" + Integer.toString(mAutoRoaming)); 8029 if (message.arg1 == mLastNetworkId) { 8030 config = getCurrentWifiConfiguration(); 8031 if (config != null) { 8032 mWifiConfigStore.noteRoamingFailure(config, 8033 WifiConfiguration.ROAMING_FAILURE_AUTH_FAILURE); 8034 } 8035 handleNetworkDisconnect(); 8036 transitionTo(mDisconnectingState); 8037 } 8038 return NOT_HANDLED; 8039 case CMD_START_SCAN: 8040 deferMessage(message); 8041 break; 8042 default: 8043 return NOT_HANDLED; 8044 } 8045 return HANDLED; 8046 } 8047 8048 @Override 8049 public void exit() { 8050 loge("WifiStateMachine: Leaving Roaming state"); 8051 } 8052 } 8053 8054 class ConnectedState extends State { 8055 @Override 8056 public void enter() { 8057 String address; 8058 updateDefaultRouteMacAddress(1000); 8059 if (DBG) { 8060 log("ConnectedState Enter " 8061 + " mScreenOn=" + mScreenOn 8062 + " scanperiod=" 8063 + Integer.toString(mWifiConfigStore.associatedPartialScanPeriodMilli.get()) ); 8064 } 8065 if (mScreenOn 8066 && mWifiConfigStore.enableAutoJoinScanWhenAssociated.get()) { 8067 if (mAlwaysOnPnoSupported) { 8068 startPno(); 8069 } else { 8070 // restart scan alarm 8071 startDelayedScan(mWifiConfigStore.associatedPartialScanPeriodMilli.get(), 8072 null, null); 8073 } 8074 } 8075 registerConnected(); 8076 lastConnectAttempt = 0; 8077 targetWificonfiguration = null; 8078 // Paranoia 8079 linkDebouncing = false; 8080 8081 // Not roaming anymore 8082 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 8083 8084 if (testNetworkDisconnect) { 8085 testNetworkDisconnectCounter++; 8086 loge("ConnectedState Enter start disconnect test " + 8087 testNetworkDisconnectCounter); 8088 sendMessageDelayed(obtainMessage(CMD_TEST_NETWORK_DISCONNECT, 8089 testNetworkDisconnectCounter, 0), 15000); 8090 } 8091 8092 // Reenable all networks, allow for hidden networks to be scanned 8093 mWifiConfigStore.enableAllNetworks(); 8094 8095 mLastDriverRoamAttempt = 0; 8096 } 8097 @Override 8098 public boolean processMessage(Message message) { 8099 WifiConfiguration config = null; 8100 logStateAndMessage(message, getClass().getSimpleName()); 8101 8102 switch (message.what) { 8103 case WifiWatchdogStateMachine.POOR_LINK_DETECTED: 8104 if (DBG) log("Watchdog reports poor link"); 8105 transitionTo(mVerifyingLinkState); 8106 break; 8107 case CMD_UNWANTED_NETWORK: 8108 if (message.arg1 == network_status_unwanted_disconnect) { 8109 mWifiConfigStore.handleBadNetworkDisconnectReport(mLastNetworkId, mWifiInfo); 8110 mWifiNative.disconnect(); 8111 transitionTo(mDisconnectingState); 8112 } else if (message.arg1 == network_status_unwanted_disable_autojoin) { 8113 config = getCurrentWifiConfiguration(); 8114 if (config != null) { 8115 // Disable autojoin 8116 config.numNoInternetAccessReports += 1; 8117 } 8118 } 8119 return HANDLED; 8120 case CMD_NETWORK_STATUS: 8121 if (message.arg1 == NetworkAgent.VALID_NETWORK) { 8122 config = getCurrentWifiConfiguration(); 8123 if (config != null) { 8124 // re-enable autojoin 8125 config.numNoInternetAccessReports = 0; 8126 config.validatedInternetAccess = true; 8127 } 8128 } 8129 return HANDLED; 8130 case CMD_TEST_NETWORK_DISCONNECT: 8131 // Force a disconnect 8132 if (message.arg1 == testNetworkDisconnectCounter) { 8133 mWifiNative.disconnect(); 8134 } 8135 break; 8136 case CMD_ASSOCIATED_BSSID: 8137 // ASSOCIATING to a new BSSID while already connected, indicates 8138 // that driver is roaming 8139 mLastDriverRoamAttempt = System.currentTimeMillis(); 8140 String toBSSID = (String)message.obj; 8141 if (toBSSID != null && !toBSSID.equals(mWifiInfo.getBSSID())) { 8142 mWifiConfigStore.driverRoamedFrom(mWifiInfo); 8143 } 8144 return NOT_HANDLED; 8145 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 8146 long lastRoam = 0; 8147 if (mLastDriverRoamAttempt != 0) { 8148 // Calculate time since last driver roam attempt 8149 lastRoam = System.currentTimeMillis() - mLastDriverRoamAttempt; 8150 mLastDriverRoamAttempt = 0; 8151 } 8152 config = getCurrentWifiConfiguration(); 8153 if (mScreenOn 8154 && !linkDebouncing 8155 && config != null 8156 && config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED 8157 && !mWifiConfigStore.isLastSelectedConfiguration(config) 8158 && (message.arg2 != 3 /* reason cannot be 3, i.e. locally generated */ 8159 || (lastRoam > 0 && lastRoam < 2000) /* unless driver is roaming */) 8160 && ((ScanResult.is24GHz(mWifiInfo.getFrequency()) 8161 && mWifiInfo.getRssi() > 8162 WifiConfiguration.BAD_RSSI_24) 8163 || (ScanResult.is5GHz(mWifiInfo.getFrequency()) 8164 && mWifiInfo.getRssi() > 8165 WifiConfiguration.BAD_RSSI_5))) { 8166 // Start de-bouncing the L2 disconnection: 8167 // this L2 disconnection might be spurious. 8168 // Hence we allow 7 seconds for the state machine to try 8169 // to reconnect, go thru the 8170 // roaming cycle and enter Obtaining IP address 8171 // before signalling the disconnect to ConnectivityService and L3 8172 startScanForConfiguration(getCurrentWifiConfiguration(), false); 8173 linkDebouncing = true; 8174 8175 sendMessageDelayed(obtainMessage(CMD_DELAYED_NETWORK_DISCONNECT, 8176 0, mLastNetworkId), LINK_FLAPPING_DEBOUNCE_MSEC); 8177 if (DBG) { 8178 log("NETWORK_DISCONNECTION_EVENT in connected state" 8179 + " BSSID=" + mWifiInfo.getBSSID() 8180 + " RSSI=" + mWifiInfo.getRssi() 8181 + " freq=" + mWifiInfo.getFrequency() 8182 + " reason=" + message.arg2 8183 + " -> debounce"); 8184 } 8185 return HANDLED; 8186 } else { 8187 if (DBG) { 8188 int ajst = -1; 8189 if (config != null) ajst = config.autoJoinStatus; 8190 log("NETWORK_DISCONNECTION_EVENT in connected state" 8191 + " BSSID=" + mWifiInfo.getBSSID() 8192 + " RSSI=" + mWifiInfo.getRssi() 8193 + " freq=" + mWifiInfo.getFrequency() 8194 + " was debouncing=" + linkDebouncing 8195 + " reason=" + message.arg2 8196 + " ajst=" + ajst); 8197 } 8198 } 8199 break; 8200 case CMD_AUTO_ROAM: 8201 // Clear the driver roam indication since we are attempting a framerwork roam 8202 mLastDriverRoamAttempt = 0; 8203 8204 /* Connect command coming from auto-join */ 8205 ScanResult candidate = (ScanResult)message.obj; 8206 String bssid = "any"; 8207 if (candidate != null && candidate.is5GHz()) { 8208 // Only lock BSSID for 5GHz networks 8209 bssid = candidate.BSSID; 8210 } 8211 int netId = mLastNetworkId; 8212 config = getCurrentWifiConfiguration(); 8213 8214 8215 if (config == null) { 8216 loge("AUTO_ROAM and no config, bail out..."); 8217 break; 8218 } 8219 8220 loge("CMD_AUTO_ROAM sup state " 8221 + mSupplicantStateTracker.getSupplicantStateName() 8222 + " my state " + getCurrentState().getName() 8223 + " nid=" + Integer.toString(netId) 8224 + " config " + config.configKey() 8225 + " roam=" + Integer.toString(message.arg2) 8226 + " to " + bssid 8227 + " targetRoamBSSID " + mTargetRoamBSSID); 8228 8229 /* Save the BSSID so as to lock it @ firmware */ 8230 if (!autoRoamSetBSSID(config, bssid) && !linkDebouncing) { 8231 loge("AUTO_ROAM nothing to do"); 8232 // Same BSSID, nothing to do 8233 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 8234 break; 8235 }; 8236 8237 // Make sure the network is enabled, since supplicant will not reenable it 8238 mWifiConfigStore.enableNetworkWithoutBroadcast(netId, false); 8239 8240 boolean ret = false; 8241 if (mLastNetworkId != netId) { 8242 if (mWifiConfigStore.selectNetwork(config, /* updatePriorities = */ false) && 8243 mWifiNative.reconnect()) { 8244 ret = true; 8245 } 8246 } else { 8247 ret = mWifiNative.reassociate(); 8248 } 8249 if (ret) { 8250 lastConnectAttempt = System.currentTimeMillis(); 8251 targetWificonfiguration = mWifiConfigStore.getWifiConfiguration(netId); 8252 8253 // replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED); 8254 mAutoRoaming = message.arg2; 8255 transitionTo(mRoamingState); 8256 8257 } else { 8258 loge("Failed to connect config: " + config + " netId: " + netId); 8259 replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED, 8260 WifiManager.ERROR); 8261 messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL; 8262 break; 8263 } 8264 break; 8265 default: 8266 return NOT_HANDLED; 8267 } 8268 return HANDLED; 8269 } 8270 8271 @Override 8272 public void exit() { 8273 loge("WifiStateMachine: Leaving Connected state"); 8274 setScanAlarm(false); 8275 mLastDriverRoamAttempt = 0; 8276 } 8277 } 8278 8279 class DisconnectingState extends State { 8280 8281 @Override 8282 public void enter() { 8283 8284 if (PDBG) { 8285 loge(" Enter DisconnectingState State scan interval " 8286 + mWifiConfigStore.wifiDisconnectedScanIntervalMs 8287 + " mEnableBackgroundScan= " + mEnableBackgroundScan 8288 + " screenOn=" + mScreenOn); 8289 } 8290 8291 // Make sure we disconnect: we enter this state prior connecting to a new 8292 // network, waiting for either a DISCONECT event or a SUPPLICANT_STATE_CHANGE 8293 // event which in this case will be indicating that supplicant started to associate. 8294 // In some cases supplicant doesn't ignore the connect requests (it might not 8295 // find the target SSID in its cache), 8296 // Therefore we end up stuck that state, hence the need for the watchdog. 8297 disconnectingWatchdogCount++; 8298 loge("Start Disconnecting Watchdog " + disconnectingWatchdogCount); 8299 sendMessageDelayed(obtainMessage(CMD_DISCONNECTING_WATCHDOG_TIMER, 8300 disconnectingWatchdogCount, 0), DISCONNECTING_GUARD_TIMER_MSEC); 8301 } 8302 8303 @Override 8304 public boolean processMessage(Message message) { 8305 logStateAndMessage(message, getClass().getSimpleName()); 8306 switch (message.what) { 8307 case CMD_SET_OPERATIONAL_MODE: 8308 if (message.arg1 != CONNECT_MODE) { 8309 deferMessage(message); 8310 } 8311 break; 8312 case CMD_START_SCAN: 8313 deferMessage(message); 8314 return HANDLED; 8315 case CMD_DISCONNECTING_WATCHDOG_TIMER: 8316 if (disconnectingWatchdogCount == message.arg1) { 8317 if (DBG) log("disconnecting watchdog! -> disconnect"); 8318 handleNetworkDisconnect(); 8319 transitionTo(mDisconnectedState); 8320 } 8321 break; 8322 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 8323 /** 8324 * If we get a SUPPLICANT_STATE_CHANGE_EVENT before NETWORK_DISCONNECTION_EVENT 8325 * we have missed the network disconnection, transition to mDisconnectedState 8326 * and handle the rest of the events there 8327 */ 8328 deferMessage(message); 8329 handleNetworkDisconnect(); 8330 transitionTo(mDisconnectedState); 8331 break; 8332 default: 8333 return NOT_HANDLED; 8334 } 8335 return HANDLED; 8336 } 8337 } 8338 8339 class DisconnectedState extends State { 8340 @Override 8341 public void enter() { 8342 // We dont scan frequently if this is a temporary disconnect 8343 // due to p2p 8344 if (mTemporarilyDisconnectWifi) { 8345 mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_RESPONSE); 8346 return; 8347 } 8348 8349 if (PDBG) { 8350 loge(" Enter disconnected State scan interval " 8351 + mWifiConfigStore.wifiDisconnectedScanIntervalMs.get() 8352 + " mEnableBackgroundScan= " + mEnableBackgroundScan 8353 + " screenOn=" + mScreenOn); 8354 } 8355 8356 /** clear the roaming state, if we were roaming, we failed */ 8357 mAutoRoaming = WifiAutoJoinController.AUTO_JOIN_IDLE; 8358 8359 if (!startPno()) { 8360 if (mScreenOn) { 8361 /** 8362 * screen lit and => delayed timer 8363 */ 8364 startDelayedScan(mWifiConfigStore.wifiDisconnectedScanIntervalMs.get(), 8365 null, null); 8366 } else { 8367 /** 8368 * screen dark and PNO supported => scan alarm disabled 8369 */ 8370 if (mEnableBackgroundScan) { 8371 /* If a regular scan result is pending, do not initiate background 8372 * scan until the scan results are returned. This is needed because 8373 * initiating a background scan will cancel the regular scan and 8374 * scan results will not be returned until background scanning is 8375 * cleared 8376 */ 8377 if (!mIsScanOngoing) { 8378 enableBackgroundScan(true); 8379 } 8380 } else { 8381 setScanAlarm(true); 8382 } 8383 } 8384 } 8385 8386 /** 8387 * If we have no networks saved, the supplicant stops doing the periodic scan. 8388 * The scans are useful to notify the user of the presence of an open network. 8389 * Note that these are not wake up scans. 8390 */ 8391 if (!mP2pConnected.get() && mWifiConfigStore.getConfiguredNetworks().size() == 0) { 8392 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 8393 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 8394 } 8395 8396 mDisconnectedTimeStamp = System.currentTimeMillis(); 8397 8398 } 8399 @Override 8400 public boolean processMessage(Message message) { 8401 boolean ret = HANDLED; 8402 8403 logStateAndMessage(message, getClass().getSimpleName()); 8404 8405 switch (message.what) { 8406 case CMD_NO_NETWORKS_PERIODIC_SCAN: 8407 if (mP2pConnected.get()) break; 8408 if (message.arg1 == mPeriodicScanToken && 8409 mWifiConfigStore.getConfiguredNetworks().size() == 0) { 8410 startScan(UNKNOWN_SCAN_SOURCE, -1, null, null); 8411 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 8412 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 8413 } 8414 break; 8415 case WifiManager.FORGET_NETWORK: 8416 case CMD_REMOVE_NETWORK: 8417 // Set up a delayed message here. After the forget/remove is handled 8418 // the handled delayed message will determine if there is a need to 8419 // scan and continue 8420 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 8421 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 8422 ret = NOT_HANDLED; 8423 break; 8424 case CMD_SET_OPERATIONAL_MODE: 8425 if (message.arg1 != CONNECT_MODE) { 8426 mOperationalMode = message.arg1; 8427 8428 mWifiConfigStore.disableAllNetworks(); 8429 if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { 8430 mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); 8431 setWifiState(WIFI_STATE_DISABLED); 8432 } 8433 transitionTo(mScanModeState); 8434 } 8435 mWifiConfigStore. 8436 setLastSelectedConfiguration(WifiConfiguration.INVALID_NETWORK_ID); 8437 break; 8438 /* Ignore network disconnect */ 8439 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 8440 break; 8441 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 8442 StateChangeResult stateChangeResult = (StateChangeResult) message.obj; 8443 if (DBG) { 8444 loge("SUPPLICANT_STATE_CHANGE_EVENT state=" + stateChangeResult.state + 8445 " -> state= " + WifiInfo.getDetailedStateOf(stateChangeResult.state) 8446 + " debouncing=" + linkDebouncing); 8447 } 8448 setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state)); 8449 /* ConnectModeState does the rest of the handling */ 8450 ret = NOT_HANDLED; 8451 break; 8452 case CMD_START_SCAN: 8453 if (!checkOrDeferScanAllowed(message)) { 8454 // The scan request was rescheduled 8455 messageHandlingStatus = MESSAGE_HANDLING_STATUS_REFUSED; 8456 return HANDLED; 8457 } 8458 /* Disable background scan temporarily during a regular scan */ 8459 if (mEnableBackgroundScan) { 8460 enableBackgroundScan(false); 8461 } 8462 if (message.arg1 == SCAN_ALARM_SOURCE) { 8463 // Check if the CMD_START_SCAN message is obsolete (and thus if it should 8464 // not be processed) and restart the scan 8465 int period = mWifiConfigStore.wifiDisconnectedScanIntervalMs.get(); 8466 if (mP2pConnected.get()) { 8467 period = (int)Settings.Global.getLong(mContext.getContentResolver(), 8468 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 8469 period); 8470 } 8471 if (!checkAndRestartDelayedScan(message.arg2, 8472 true, period, null, null)) { 8473 messageHandlingStatus = MESSAGE_HANDLING_STATUS_OBSOLETE; 8474 loge("WifiStateMachine Disconnected CMD_START_SCAN source " 8475 + message.arg1 8476 + " " + message.arg2 + ", " + mDelayedScanCounter 8477 + " -> obsolete"); 8478 return HANDLED; 8479 } 8480 handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); 8481 ret = HANDLED; 8482 } else { 8483 ret = NOT_HANDLED; 8484 } 8485 break; 8486 case WifiMonitor.SCAN_RESULTS_EVENT: 8487 /* Re-enable background scan when a pending scan result is received */ 8488 if (mEnableBackgroundScan && mIsScanOngoing) { 8489 enableBackgroundScan(true); 8490 } 8491 /* Handled in parent state */ 8492 ret = NOT_HANDLED; 8493 break; 8494 case WifiP2pServiceImpl.P2P_CONNECTION_CHANGED: 8495 NetworkInfo info = (NetworkInfo) message.obj; 8496 mP2pConnected.set(info.isConnected()); 8497 if (mP2pConnected.get()) { 8498 int defaultInterval = mContext.getResources().getInteger( 8499 R.integer.config_wifi_scan_interval_p2p_connected); 8500 long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), 8501 Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, 8502 defaultInterval); 8503 mWifiNative.setScanInterval((int) scanIntervalMs/1000); 8504 } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { 8505 if (DBG) log("Turn on scanning after p2p disconnected"); 8506 sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, 8507 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); 8508 } else { 8509 // If P2P is not connected and there are saved networks, then restart 8510 // scanning at the normal period. This is necessary because scanning might 8511 // have been disabled altogether if WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS 8512 // was set to zero. 8513 if (!startPno()) { 8514 startDelayedScan(mWifiConfigStore.wifiDisconnectedScanIntervalMs.get(), 8515 null, null); 8516 } 8517 } 8518 break; 8519 case CMD_RECONNECT: 8520 case CMD_REASSOCIATE: 8521 if (mTemporarilyDisconnectWifi) { 8522 // Drop a third party reconnect/reassociate if STA is 8523 // temporarily disconnected for p2p 8524 break; 8525 } else { 8526 // ConnectModeState handles it 8527 ret = NOT_HANDLED; 8528 } 8529 break; 8530 case CMD_SCREEN_STATE_CHANGED: 8531 handleScreenStateChanged(message.arg1 != 0, 8532 /* startBackgroundScanIfNeeded = */ true); 8533 break; 8534 default: 8535 ret = NOT_HANDLED; 8536 } 8537 return ret; 8538 } 8539 8540 @Override 8541 public void exit() { 8542 /* No need for a background scan upon exit from a disconnected state */ 8543 if (mEnableBackgroundScan) { 8544 enableBackgroundScan(false); 8545 } 8546 setScanAlarm(false); 8547 } 8548 } 8549 8550 class WpsRunningState extends State { 8551 // Tracks the source to provide a reply 8552 private Message mSourceMessage; 8553 @Override 8554 public void enter() { 8555 mSourceMessage = Message.obtain(getCurrentMessage()); 8556 } 8557 @Override 8558 public boolean processMessage(Message message) { 8559 logStateAndMessage(message, getClass().getSimpleName()); 8560 8561 switch (message.what) { 8562 case WifiMonitor.WPS_SUCCESS_EVENT: 8563 // Ignore intermediate success, wait for full connection 8564 break; 8565 case WifiMonitor.NETWORK_CONNECTION_EVENT: 8566 replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED); 8567 mSourceMessage.recycle(); 8568 mSourceMessage = null; 8569 deferMessage(message); 8570 transitionTo(mDisconnectedState); 8571 break; 8572 case WifiMonitor.WPS_OVERLAP_EVENT: 8573 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 8574 WifiManager.WPS_OVERLAP_ERROR); 8575 mSourceMessage.recycle(); 8576 mSourceMessage = null; 8577 transitionTo(mDisconnectedState); 8578 break; 8579 case WifiMonitor.WPS_FAIL_EVENT: 8580 // Arg1 has the reason for the failure 8581 if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) { 8582 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1); 8583 mSourceMessage.recycle(); 8584 mSourceMessage = null; 8585 transitionTo(mDisconnectedState); 8586 } else { 8587 if (DBG) log("Ignore unspecified fail event during WPS connection"); 8588 } 8589 break; 8590 case WifiMonitor.WPS_TIMEOUT_EVENT: 8591 replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, 8592 WifiManager.WPS_TIMED_OUT); 8593 mSourceMessage.recycle(); 8594 mSourceMessage = null; 8595 transitionTo(mDisconnectedState); 8596 break; 8597 case WifiManager.START_WPS: 8598 replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS); 8599 break; 8600 case WifiManager.CANCEL_WPS: 8601 if (mWifiNative.cancelWps()) { 8602 replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED); 8603 } else { 8604 replyToMessage(message, WifiManager.CANCEL_WPS_FAILED, WifiManager.ERROR); 8605 } 8606 transitionTo(mDisconnectedState); 8607 break; 8608 /** 8609 * Defer all commands that can cause connections to a different network 8610 * or put the state machine out of connect mode 8611 */ 8612 case CMD_STOP_DRIVER: 8613 case CMD_SET_OPERATIONAL_MODE: 8614 case WifiManager.CONNECT_NETWORK: 8615 case CMD_ENABLE_NETWORK: 8616 case CMD_RECONNECT: 8617 case CMD_REASSOCIATE: 8618 deferMessage(message); 8619 break; 8620 case CMD_AUTO_CONNECT: 8621 case CMD_AUTO_ROAM: 8622 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 8623 return HANDLED; 8624 case CMD_START_SCAN: 8625 messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; 8626 return HANDLED; 8627 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 8628 if (DBG) log("Network connection lost"); 8629 handleNetworkDisconnect(); 8630 break; 8631 case WifiMonitor.ASSOCIATION_REJECTION_EVENT: 8632 if (DBG) log("Ignore Assoc reject event during WPS Connection"); 8633 break; 8634 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 8635 // Disregard auth failure events during WPS connection. The 8636 // EAP sequence is retried several times, and there might be 8637 // failures (especially for wps pin). We will get a WPS_XXX 8638 // event at the end of the sequence anyway. 8639 if (DBG) log("Ignore auth failure during WPS connection"); 8640 break; 8641 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 8642 // Throw away supplicant state changes when WPS is running. 8643 // We will start getting supplicant state changes once we get 8644 // a WPS success or failure 8645 break; 8646 default: 8647 return NOT_HANDLED; 8648 } 8649 return HANDLED; 8650 } 8651 8652 @Override 8653 public void exit() { 8654 mWifiConfigStore.enableAllNetworks(); 8655 mWifiConfigStore.loadConfiguredNetworks(); 8656 } 8657 } 8658 8659 class SoftApStartingState extends State { 8660 @Override 8661 public void enter() { 8662 final Message message = getCurrentMessage(); 8663 if (message.what == CMD_START_AP) { 8664 final WifiConfiguration config = (WifiConfiguration) message.obj; 8665 8666 if (config == null) { 8667 mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG); 8668 } else { 8669 mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config); 8670 startSoftApWithConfig(config); 8671 } 8672 } else { 8673 throw new RuntimeException("Illegal transition to SoftApStartingState: " + message); 8674 } 8675 } 8676 @Override 8677 public boolean processMessage(Message message) { 8678 logStateAndMessage(message, getClass().getSimpleName()); 8679 8680 switch(message.what) { 8681 case CMD_START_SUPPLICANT: 8682 case CMD_STOP_SUPPLICANT: 8683 case CMD_START_AP: 8684 case CMD_STOP_AP: 8685 case CMD_START_DRIVER: 8686 case CMD_STOP_DRIVER: 8687 case CMD_SET_OPERATIONAL_MODE: 8688 case CMD_SET_COUNTRY_CODE: 8689 case CMD_SET_FREQUENCY_BAND: 8690 case CMD_START_PACKET_FILTERING: 8691 case CMD_STOP_PACKET_FILTERING: 8692 case CMD_TETHER_STATE_CHANGE: 8693 deferMessage(message); 8694 break; 8695 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: 8696 WifiConfiguration config = (WifiConfiguration) message.obj; 8697 if (config != null) { 8698 startSoftApWithConfig(config); 8699 } else { 8700 loge("Softap config is null!"); 8701 sendMessage(CMD_START_AP_FAILURE); 8702 } 8703 break; 8704 case CMD_START_AP_SUCCESS: 8705 setWifiApState(WIFI_AP_STATE_ENABLED); 8706 transitionTo(mSoftApStartedState); 8707 break; 8708 case CMD_START_AP_FAILURE: 8709 setWifiApState(WIFI_AP_STATE_FAILED); 8710 transitionTo(mInitialState); 8711 break; 8712 default: 8713 return NOT_HANDLED; 8714 } 8715 return HANDLED; 8716 } 8717 } 8718 8719 class SoftApStartedState extends State { 8720 @Override 8721 public boolean processMessage(Message message) { 8722 logStateAndMessage(message, getClass().getSimpleName()); 8723 8724 switch(message.what) { 8725 case CMD_STOP_AP: 8726 if (DBG) log("Stopping Soft AP"); 8727 /* We have not tethered at this point, so we just shutdown soft Ap */ 8728 try { 8729 mNwService.stopAccessPoint(mInterfaceName); 8730 } catch(Exception e) { 8731 loge("Exception in stopAccessPoint()"); 8732 } 8733 setWifiApState(WIFI_AP_STATE_DISABLED); 8734 transitionTo(mInitialState); 8735 break; 8736 case CMD_START_AP: 8737 // Ignore a start on a running access point 8738 break; 8739 // Fail client mode operation when soft AP is enabled 8740 case CMD_START_SUPPLICANT: 8741 loge("Cannot start supplicant with a running soft AP"); 8742 setWifiState(WIFI_STATE_UNKNOWN); 8743 break; 8744 case CMD_TETHER_STATE_CHANGE: 8745 TetherStateChange stateChange = (TetherStateChange) message.obj; 8746 if (startTethering(stateChange.available)) { 8747 transitionTo(mTetheringState); 8748 } 8749 break; 8750 default: 8751 return NOT_HANDLED; 8752 } 8753 return HANDLED; 8754 } 8755 } 8756 8757 class TetheringState extends State { 8758 @Override 8759 public void enter() { 8760 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 8761 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 8762 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 8763 } 8764 @Override 8765 public boolean processMessage(Message message) { 8766 logStateAndMessage(message, getClass().getSimpleName()); 8767 8768 switch(message.what) { 8769 case CMD_TETHER_STATE_CHANGE: 8770 TetherStateChange stateChange = (TetherStateChange) message.obj; 8771 if (isWifiTethered(stateChange.active)) { 8772 transitionTo(mTetheredState); 8773 } 8774 return HANDLED; 8775 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 8776 if (message.arg1 == mTetherToken) { 8777 loge("Failed to get tether update, shutdown soft access point"); 8778 transitionTo(mSoftApStartedState); 8779 // Needs to be first thing handled 8780 sendMessageAtFrontOfQueue(CMD_STOP_AP); 8781 } 8782 break; 8783 case CMD_START_SUPPLICANT: 8784 case CMD_STOP_SUPPLICANT: 8785 case CMD_START_AP: 8786 case CMD_STOP_AP: 8787 case CMD_START_DRIVER: 8788 case CMD_STOP_DRIVER: 8789 case CMD_SET_OPERATIONAL_MODE: 8790 case CMD_SET_COUNTRY_CODE: 8791 case CMD_SET_FREQUENCY_BAND: 8792 case CMD_START_PACKET_FILTERING: 8793 case CMD_STOP_PACKET_FILTERING: 8794 deferMessage(message); 8795 break; 8796 default: 8797 return NOT_HANDLED; 8798 } 8799 return HANDLED; 8800 } 8801 } 8802 8803 class TetheredState extends State { 8804 @Override 8805 public boolean processMessage(Message message) { 8806 logStateAndMessage(message, getClass().getSimpleName()); 8807 8808 switch(message.what) { 8809 case CMD_TETHER_STATE_CHANGE: 8810 TetherStateChange stateChange = (TetherStateChange) message.obj; 8811 if (!isWifiTethered(stateChange.active)) { 8812 loge("Tethering reports wifi as untethered!, shut down soft Ap"); 8813 setHostApRunning(null, false); 8814 setHostApRunning(null, true); 8815 } 8816 return HANDLED; 8817 case CMD_STOP_AP: 8818 if (DBG) log("Untethering before stopping AP"); 8819 setWifiApState(WIFI_AP_STATE_DISABLING); 8820 stopTethering(); 8821 transitionTo(mUntetheringState); 8822 // More work to do after untethering 8823 deferMessage(message); 8824 break; 8825 default: 8826 return NOT_HANDLED; 8827 } 8828 return HANDLED; 8829 } 8830 } 8831 8832 class UntetheringState extends State { 8833 @Override 8834 public void enter() { 8835 /* Send ourselves a delayed message to shut down if tethering fails to notify */ 8836 sendMessageDelayed(obtainMessage(CMD_TETHER_NOTIFICATION_TIMED_OUT, 8837 ++mTetherToken, 0), TETHER_NOTIFICATION_TIME_OUT_MSECS); 8838 8839 } 8840 @Override 8841 public boolean processMessage(Message message) { 8842 logStateAndMessage(message, getClass().getSimpleName()); 8843 8844 switch(message.what) { 8845 case CMD_TETHER_STATE_CHANGE: 8846 TetherStateChange stateChange = (TetherStateChange) message.obj; 8847 8848 /* Wait till wifi is untethered */ 8849 if (isWifiTethered(stateChange.active)) break; 8850 8851 transitionTo(mSoftApStartedState); 8852 break; 8853 case CMD_TETHER_NOTIFICATION_TIMED_OUT: 8854 if (message.arg1 == mTetherToken) { 8855 loge("Failed to get tether update, force stop access point"); 8856 transitionTo(mSoftApStartedState); 8857 } 8858 break; 8859 case CMD_START_SUPPLICANT: 8860 case CMD_STOP_SUPPLICANT: 8861 case CMD_START_AP: 8862 case CMD_STOP_AP: 8863 case CMD_START_DRIVER: 8864 case CMD_STOP_DRIVER: 8865 case CMD_SET_OPERATIONAL_MODE: 8866 case CMD_SET_COUNTRY_CODE: 8867 case CMD_SET_FREQUENCY_BAND: 8868 case CMD_START_PACKET_FILTERING: 8869 case CMD_STOP_PACKET_FILTERING: 8870 deferMessage(message); 8871 break; 8872 default: 8873 return NOT_HANDLED; 8874 } 8875 return HANDLED; 8876 } 8877 } 8878 8879 //State machine initiated requests can have replyTo set to null indicating 8880 //there are no recepients, we ignore those reply actions 8881 private void replyToMessage(Message msg, int what) { 8882 if (msg.replyTo == null) return; 8883 Message dstMsg = obtainMessageWithArg2(msg); 8884 dstMsg.what = what; 8885 mReplyChannel.replyToMessage(msg, dstMsg); 8886 } 8887 8888 private void replyToMessage(Message msg, int what, int arg1) { 8889 if (msg.replyTo == null) return; 8890 Message dstMsg = obtainMessageWithArg2(msg); 8891 dstMsg.what = what; 8892 dstMsg.arg1 = arg1; 8893 mReplyChannel.replyToMessage(msg, dstMsg); 8894 } 8895 8896 private void replyToMessage(Message msg, int what, Object obj) { 8897 if (msg.replyTo == null) return; 8898 Message dstMsg = obtainMessageWithArg2(msg); 8899 dstMsg.what = what; 8900 dstMsg.obj = obj; 8901 mReplyChannel.replyToMessage(msg, dstMsg); 8902 } 8903 8904 /** 8905 * arg2 on the source message has a unique id that needs to be retained in replies 8906 * to match the request 8907 8908 * see WifiManager for details 8909 */ 8910 private Message obtainMessageWithArg2(Message srcMsg) { 8911 Message msg = Message.obtain(); 8912 msg.arg2 = srcMsg.arg2; 8913 return msg; 8914 } 8915 8916 private static int parseHex(char ch) { 8917 if ('0' <= ch && ch <= '9') { 8918 return ch - '0'; 8919 } else if ('a' <= ch && ch <= 'f') { 8920 return ch - 'a' + 10; 8921 } else if ('A' <= ch && ch <= 'F') { 8922 return ch - 'A' + 10; 8923 } else { 8924 throw new NumberFormatException("" + ch + " is not a valid hex digit"); 8925 } 8926 } 8927 8928 private byte[] parseHex(String hex) { 8929 /* This only works for good input; don't throw bad data at it */ 8930 if (hex == null) { 8931 return new byte[0]; 8932 } 8933 8934 if (hex.length() % 2 != 0) { 8935 throw new NumberFormatException(hex + " is not a valid hex string"); 8936 } 8937 8938 byte[] result = new byte[(hex.length())/2 + 1]; 8939 result[0] = (byte) ((hex.length())/2); 8940 for (int i = 0, j = 1; i < hex.length(); i += 2, j++) { 8941 int val = parseHex(hex.charAt(i)) * 16 + parseHex(hex.charAt(i+1)); 8942 byte b = (byte) (val & 0xFF); 8943 result[j] = b; 8944 } 8945 8946 return result; 8947 } 8948 8949 private static String makeHex(byte[] bytes) { 8950 StringBuilder sb = new StringBuilder(); 8951 for (byte b : bytes) { 8952 sb.append(String.format("%02x", b)); 8953 } 8954 return sb.toString(); 8955 } 8956 8957 private static String makeHex(byte[] bytes, int from, int len) { 8958 StringBuilder sb = new StringBuilder(); 8959 for (int i = 0; i < len; i++) { 8960 sb.append(String.format("%02x", bytes[from+i])); 8961 } 8962 return sb.toString(); 8963 } 8964 8965 private static byte[] concat(byte[] array1, byte[] array2, byte[] array3) { 8966 8967 int len = array1.length + array2.length + array3.length; 8968 8969 if (array1.length != 0) { 8970 len++; /* add another byte for size */ 8971 } 8972 8973 if (array2.length != 0) { 8974 len++; /* add another byte for size */ 8975 } 8976 8977 if (array3.length != 0) { 8978 len++; /* add another byte for size */ 8979 } 8980 8981 byte[] result = new byte[len]; 8982 8983 int index = 0; 8984 if (array1.length != 0) { 8985 result[index] = (byte) (array1.length & 0xFF); 8986 index++; 8987 for (byte b : array1) { 8988 result[index] = b; 8989 index++; 8990 } 8991 } 8992 8993 if (array2.length != 0) { 8994 result[index] = (byte) (array2.length & 0xFF); 8995 index++; 8996 for (byte b : array2) { 8997 result[index] = b; 8998 index++; 8999 } 9000 } 9001 9002 if (array3.length != 0) { 9003 result[index] = (byte) (array3.length & 0xFF); 9004 index++; 9005 for (byte b : array3) { 9006 result[index] = b; 9007 index++; 9008 } 9009 } 9010 return result; 9011 } 9012 9013 private static byte[] concatHex(byte[] array1, byte[] array2) { 9014 9015 int len = array1.length + array2.length; 9016 9017 byte[] result = new byte[len]; 9018 9019 int index = 0; 9020 if (array1.length != 0) { 9021 for (byte b : array1) { 9022 result[index] = b; 9023 index++; 9024 } 9025 } 9026 9027 if (array2.length != 0) { 9028 for (byte b : array2) { 9029 result[index] = b; 9030 index++; 9031 } 9032 } 9033 9034 return result; 9035 } 9036 9037 void handleGsmAuthRequest(SimAuthRequestData requestData) { 9038 if (targetWificonfiguration == null 9039 || targetWificonfiguration.networkId == requestData.networkId) { 9040 logd("id matches targetWifiConfiguration"); 9041 } else { 9042 logd("id does not match targetWifiConfiguration"); 9043 return; 9044 } 9045 9046 TelephonyManager tm = (TelephonyManager) 9047 mContext.getSystemService(Context.TELEPHONY_SERVICE); 9048 9049 if (tm != null) { 9050 StringBuilder sb = new StringBuilder(); 9051 for (String challenge : requestData.data) { 9052 9053 if (challenge == null || challenge.isEmpty()) 9054 continue; 9055 logd("RAND = " + challenge); 9056 9057 byte[] rand = null; 9058 try { 9059 rand = parseHex(challenge); 9060 } catch (NumberFormatException e) { 9061 loge("malformed challenge"); 9062 continue; 9063 } 9064 9065 String base64Challenge = android.util.Base64.encodeToString( 9066 rand, android.util.Base64.NO_WRAP); 9067 /* 9068 * First, try with appType = 2 => USIM according to 9069 * com.android.internal.telephony.PhoneConstants#APPTYPE_xxx 9070 */ 9071 int appType = 2; 9072 String tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge); 9073 if (tmResponse == null) { 9074 /* Then, in case of failure, issue may be due to sim type, retry as a simple sim 9075 * appType = 1 => SIM 9076 */ 9077 appType = 1; 9078 tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge); 9079 } 9080 logv("Raw Response - " + tmResponse); 9081 9082 if (tmResponse != null && tmResponse.length() > 4) { 9083 byte[] result = android.util.Base64.decode(tmResponse, 9084 android.util.Base64.DEFAULT); 9085 logv("Hex Response -" + makeHex(result)); 9086 int sres_len = result[0]; 9087 String sres = makeHex(result, 1, sres_len); 9088 int kc_offset = 1+sres_len; 9089 int kc_len = result[kc_offset]; 9090 String kc = makeHex(result, 1+kc_offset, kc_len); 9091 sb.append(":" + kc + ":" + sres); 9092 logv("kc:" + kc + " sres:" + sres); 9093 } else { 9094 loge("bad response - " + tmResponse); 9095 } 9096 } 9097 9098 String response = sb.toString(); 9099 logv("Supplicant Response -" + response); 9100 mWifiNative.simAuthResponse(requestData.networkId, "GSM-AUTH", response); 9101 } else { 9102 loge("could not get telephony manager"); 9103 } 9104 } 9105 9106 void handle3GAuthRequest(SimAuthRequestData requestData) { 9107 StringBuilder sb = new StringBuilder(); 9108 byte[] rand = null; 9109 byte[] authn = null; 9110 String res_type = "UMTS-AUTH"; 9111 9112 if (targetWificonfiguration == null 9113 || targetWificonfiguration.networkId == requestData.networkId) { 9114 logd("id matches targetWifiConfiguration"); 9115 } else { 9116 logd("id does not match targetWifiConfiguration"); 9117 return; 9118 } 9119 if (requestData.data.length == 2) { 9120 try { 9121 rand = parseHex(requestData.data[0]); 9122 authn = parseHex(requestData.data[1]); 9123 } catch (NumberFormatException e) { 9124 loge("malformed challenge"); 9125 } 9126 } else { 9127 loge("malformed challenge"); 9128 } 9129 9130 String tmResponse = ""; 9131 if (rand != null && authn != null) { 9132 String base64Challenge = android.util.Base64.encodeToString( 9133 concatHex(rand,authn), android.util.Base64.NO_WRAP); 9134 9135 TelephonyManager tm = (TelephonyManager) 9136 mContext.getSystemService(Context.TELEPHONY_SERVICE); 9137 if (tm != null) { 9138 int appType = 2; // 2 => USIM 9139 tmResponse = tm.getIccSimChallengeResponse(appType, base64Challenge); 9140 logv("Raw Response - " + tmResponse); 9141 } else { 9142 loge("could not get telephony manager"); 9143 } 9144 } 9145 9146 if (tmResponse != null && tmResponse.length() > 4) { 9147 byte[] result = android.util.Base64.decode(tmResponse, 9148 android.util.Base64.DEFAULT); 9149 loge("Hex Response - " + makeHex(result)); 9150 byte tag = result[0]; 9151 if (tag == (byte) 0xdb) { 9152 logv("successful 3G authentication "); 9153 int res_len = result[1]; 9154 String res = makeHex(result, 2, res_len); 9155 int ck_len = result[res_len + 2]; 9156 String ck = makeHex(result, res_len + 3, ck_len); 9157 int ik_len = result[res_len + ck_len + 3]; 9158 String ik = makeHex(result, res_len + ck_len + 4, ik_len); 9159 sb.append(":" + ik + ":" + ck + ":" + res); 9160 logv("ik:" + ik + "ck:" + ck + " res:" + res); 9161 } else if (tag == (byte) 0xdc) { 9162 loge("synchronisation failure"); 9163 int auts_len = result[1]; 9164 String auts = makeHex(result, 2, auts_len); 9165 res_type = "UMTS-AUTS"; 9166 sb.append(":" + auts); 9167 logv("auts:" + auts); 9168 } else { 9169 loge("bad response - unknown tag = " + tag); 9170 return; 9171 } 9172 } else { 9173 loge("bad response - " + tmResponse); 9174 return; 9175 } 9176 9177 String response = sb.toString(); 9178 logv("Supplicant Response -" + response); 9179 mWifiNative.simAuthResponse(requestData.networkId, res_type, response); 9180 } 9181} 9182