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