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