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