1 /* 2 * Copyright (C) 2016 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 17 package com.android.server.wifi; 18 19 import static com.android.server.wifi.WifiStateMachine.WIFI_WORK_SOURCE; 20 21 import android.app.ActivityManager; 22 import android.app.AlarmManager; 23 import android.content.Context; 24 import android.net.wifi.ScanResult; 25 import android.net.wifi.SupplicantState; 26 import android.net.wifi.WifiConfiguration; 27 import android.net.wifi.WifiInfo; 28 import android.net.wifi.WifiManager; 29 import android.net.wifi.WifiScanner; 30 import android.net.wifi.WifiScanner.PnoSettings; 31 import android.net.wifi.WifiScanner.ScanSettings; 32 import android.os.Handler; 33 import android.os.Looper; 34 import android.util.LocalLog; 35 import android.util.Log; 36 37 import com.android.internal.R; 38 import com.android.internal.annotations.VisibleForTesting; 39 import com.android.server.wifi.util.ScanDetailUtil; 40 41 import java.io.FileDescriptor; 42 import java.io.PrintWriter; 43 import java.util.ArrayList; 44 import java.util.HashSet; 45 import java.util.Iterator; 46 import java.util.LinkedList; 47 import java.util.List; 48 import java.util.Set; 49 50 /** 51 * This class manages all the connectivity related scanning activities. 52 * 53 * When the screen is turned on or off, WiFi is connected or disconnected, 54 * or on-demand, a scan is initiatiated and the scan results are passed 55 * to QNS for it to make a recommendation on which network to connect to. 56 */ 57 public class WifiConnectivityManager { 58 public static final String WATCHDOG_TIMER_TAG = 59 "WifiConnectivityManager Schedule Watchdog Timer"; 60 public static final String PERIODIC_SCAN_TIMER_TAG = 61 "WifiConnectivityManager Schedule Periodic Scan Timer"; 62 public static final String RESTART_SINGLE_SCAN_TIMER_TAG = 63 "WifiConnectivityManager Restart Single Scan"; 64 public static final String RESTART_CONNECTIVITY_SCAN_TIMER_TAG = 65 "WifiConnectivityManager Restart Scan"; 66 67 private static final String TAG = "WifiConnectivityManager"; 68 private static final long RESET_TIME_STAMP = Long.MIN_VALUE; 69 // Constants to indicate whether a scan should start immediately or 70 // it should comply to the minimum scan interval rule. 71 private static final boolean SCAN_IMMEDIATELY = true; 72 private static final boolean SCAN_ON_SCHEDULE = false; 73 // Periodic scan interval in milli-seconds. This is the scan 74 // performed when screen is on. 75 @VisibleForTesting 76 public static final int PERIODIC_SCAN_INTERVAL_MS = 20 * 1000; // 20 seconds 77 // When screen is on and WiFi traffic is heavy, exponential backoff 78 // connectivity scans are scheduled. This constant defines the maximum 79 // scan interval in this scenario. 80 @VisibleForTesting 81 public static final int MAX_PERIODIC_SCAN_INTERVAL_MS = 160 * 1000; // 160 seconds 82 // PNO scan interval in milli-seconds. This is the scan 83 // performed when screen is off and disconnected. 84 private static final int DISCONNECTED_PNO_SCAN_INTERVAL_MS = 20 * 1000; // 20 seconds 85 // PNO scan interval in milli-seconds. This is the scan 86 // performed when screen is off and connected. 87 private static final int CONNECTED_PNO_SCAN_INTERVAL_MS = 160 * 1000; // 160 seconds 88 // When a network is found by PNO scan but gets rejected by QNS due to its 89 // low RSSI value, scan will be reschduled in an exponential back off manner. 90 private static final int LOW_RSSI_NETWORK_RETRY_START_DELAY_MS = 20 * 1000; // 20 seconds 91 private static final int LOW_RSSI_NETWORK_RETRY_MAX_DELAY_MS = 80 * 1000; // 80 seconds 92 // Maximum number of retries when starting a scan failed 93 @VisibleForTesting 94 public static final int MAX_SCAN_RESTART_ALLOWED = 5; 95 // Number of milli-seconds to delay before retry starting 96 // a previously failed scan 97 private static final int RESTART_SCAN_DELAY_MS = 2 * 1000; // 2 seconds 98 // When in disconnected mode, a watchdog timer will be fired 99 // every WATCHDOG_INTERVAL_MS to start a single scan. This is 100 // to prevent caveat from things like PNO scan. 101 private static final int WATCHDOG_INTERVAL_MS = 20 * 60 * 1000; // 20 minutes 102 // Restricted channel list age out value. 103 private static final int CHANNEL_LIST_AGE_MS = 60 * 60 * 1000; // 1 hour 104 // This is the time interval for the connection attempt rate calculation. Connection attempt 105 // timestamps beyond this interval is evicted from the list. 106 public static final int MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS = 4 * 60 * 1000; // 4 mins 107 // Max number of connection attempts in the above time interval. 108 public static final int MAX_CONNECTION_ATTEMPTS_RATE = 6; 109 110 // WifiStateMachine has a bunch of states. From the 111 // WifiConnectivityManager's perspective it only cares 112 // if it is in Connected state, Disconnected state or in 113 // transition between these two states. 114 public static final int WIFI_STATE_UNKNOWN = 0; 115 public static final int WIFI_STATE_CONNECTED = 1; 116 public static final int WIFI_STATE_DISCONNECTED = 2; 117 public static final int WIFI_STATE_TRANSITIONING = 3; 118 119 // Due to b/28020168, timer based single scan will be scheduled 120 // to provide periodic scan in an exponential backoff fashion. 121 private static final boolean ENABLE_BACKGROUND_SCAN = false; 122 // Flag to turn on connected PNO, when needed 123 private static final boolean ENABLE_CONNECTED_PNO_SCAN = false; 124 125 private final WifiStateMachine mStateMachine; 126 private final WifiScanner mScanner; 127 private final WifiConfigManager mConfigManager; 128 private final WifiInfo mWifiInfo; 129 private final WifiQualifiedNetworkSelector mQualifiedNetworkSelector; 130 private final WifiLastResortWatchdog mWifiLastResortWatchdog; 131 private final WifiMetrics mWifiMetrics; 132 private final AlarmManager mAlarmManager; 133 private final Handler mEventHandler; 134 private final Clock mClock; 135 private final LocalLog mLocalLog = 136 new LocalLog(ActivityManager.isLowRamDeviceStatic() ? 128 : 256); 137 private final LinkedList<Long> mConnectionAttemptTimeStamps; 138 139 private boolean mDbg = false; 140 private boolean mWifiEnabled = false; 141 private boolean mWifiConnectivityManagerEnabled = true; 142 private boolean mScreenOn = false; 143 private int mWifiState = WIFI_STATE_UNKNOWN; 144 private boolean mUntrustedConnectionAllowed = false; 145 private int mScanRestartCount = 0; 146 private int mSingleScanRestartCount = 0; 147 private int mTotalConnectivityAttemptsRateLimited = 0; 148 private String mLastConnectionAttemptBssid = null; 149 private int mPeriodicSingleScanInterval = PERIODIC_SCAN_INTERVAL_MS; 150 private long mLastPeriodicSingleScanTimeStamp = RESET_TIME_STAMP; 151 private boolean mPnoScanStarted = false; 152 private boolean mPeriodicScanTimerSet = false; 153 154 // PNO settings 155 private int mMin5GHzRssi; 156 private int mMin24GHzRssi; 157 private int mInitialScoreMax; 158 private int mCurrentConnectionBonus; 159 private int mSameNetworkBonus; 160 private int mSecureBonus; 161 private int mBand5GHzBonus; 162 163 // A helper to log debugging information in the local log buffer, which can 164 // be retrieved in bugreport. localLog(String log)165 private void localLog(String log) { 166 mLocalLog.log(log); 167 } 168 169 // A periodic/PNO scan will be rescheduled up to MAX_SCAN_RESTART_ALLOWED times 170 // if the start scan command failed. An timer is used here to make it a deferred retry. 171 private final AlarmManager.OnAlarmListener mRestartScanListener = 172 new AlarmManager.OnAlarmListener() { 173 public void onAlarm() { 174 startConnectivityScan(SCAN_IMMEDIATELY); 175 } 176 }; 177 178 // A single scan will be rescheduled up to MAX_SCAN_RESTART_ALLOWED times 179 // if the start scan command failed. An timer is used here to make it a deferred retry. 180 private class RestartSingleScanListener implements AlarmManager.OnAlarmListener { 181 private final boolean mIsFullBandScan; 182 RestartSingleScanListener(boolean isFullBandScan)183 RestartSingleScanListener(boolean isFullBandScan) { 184 mIsFullBandScan = isFullBandScan; 185 } 186 187 @Override onAlarm()188 public void onAlarm() { 189 startSingleScan(mIsFullBandScan); 190 } 191 } 192 193 // As a watchdog mechanism, a single scan will be scheduled every WATCHDOG_INTERVAL_MS 194 // if it is in the WIFI_STATE_DISCONNECTED state. 195 private final AlarmManager.OnAlarmListener mWatchdogListener = 196 new AlarmManager.OnAlarmListener() { 197 public void onAlarm() { 198 watchdogHandler(); 199 } 200 }; 201 202 // Due to b/28020168, timer based single scan will be scheduled 203 // to provide periodic scan in an exponential backoff fashion. 204 private final AlarmManager.OnAlarmListener mPeriodicScanTimerListener = 205 new AlarmManager.OnAlarmListener() { 206 public void onAlarm() { 207 periodicScanTimerHandler(); 208 } 209 }; 210 211 /** 212 * Handles 'onResult' callbacks for the Periodic, Single & Pno ScanListener. 213 * Executes selection of potential network candidates, initiation of connection attempt to that 214 * network. 215 * 216 * @return true - if a candidate is selected by QNS 217 * false - if no candidate is selected by QNS 218 */ handleScanResults(List<ScanDetail> scanDetails, String listenerName)219 private boolean handleScanResults(List<ScanDetail> scanDetails, String listenerName) { 220 localLog(listenerName + " onResults: start QNS"); 221 WifiConfiguration candidate = 222 mQualifiedNetworkSelector.selectQualifiedNetwork(false, 223 mUntrustedConnectionAllowed, scanDetails, 224 mStateMachine.isLinkDebouncing(), mStateMachine.isConnected(), 225 mStateMachine.isDisconnected(), 226 mStateMachine.isSupplicantTransientState()); 227 mWifiLastResortWatchdog.updateAvailableNetworks( 228 mQualifiedNetworkSelector.getFilteredScanDetails()); 229 if (candidate != null) { 230 localLog(listenerName + ": QNS candidate-" + candidate.SSID); 231 connectToNetwork(candidate); 232 return true; 233 } else { 234 return false; 235 } 236 } 237 238 // Periodic scan results listener. A periodic scan is initiated when 239 // screen is on. 240 private class PeriodicScanListener implements WifiScanner.ScanListener { 241 private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>(); 242 clearScanDetails()243 public void clearScanDetails() { 244 mScanDetails.clear(); 245 } 246 247 @Override onSuccess()248 public void onSuccess() { 249 localLog("PeriodicScanListener onSuccess"); 250 } 251 252 @Override onFailure(int reason, String description)253 public void onFailure(int reason, String description) { 254 Log.e(TAG, "PeriodicScanListener onFailure:" 255 + " reason: " + reason 256 + " description: " + description); 257 258 // reschedule the scan 259 if (mScanRestartCount++ < MAX_SCAN_RESTART_ALLOWED) { 260 scheduleDelayedConnectivityScan(RESTART_SCAN_DELAY_MS); 261 } else { 262 mScanRestartCount = 0; 263 Log.e(TAG, "Failed to successfully start periodic scan for " 264 + MAX_SCAN_RESTART_ALLOWED + " times"); 265 } 266 } 267 268 @Override onPeriodChanged(int periodInMs)269 public void onPeriodChanged(int periodInMs) { 270 localLog("PeriodicScanListener onPeriodChanged: " 271 + "actual scan period " + periodInMs + "ms"); 272 } 273 274 @Override onResults(WifiScanner.ScanData[] results)275 public void onResults(WifiScanner.ScanData[] results) { 276 handleScanResults(mScanDetails, "PeriodicScanListener"); 277 clearScanDetails(); 278 mScanRestartCount = 0; 279 } 280 281 @Override onFullResult(ScanResult fullScanResult)282 public void onFullResult(ScanResult fullScanResult) { 283 if (mDbg) { 284 localLog("PeriodicScanListener onFullResult: " 285 + fullScanResult.SSID + " capabilities " 286 + fullScanResult.capabilities); 287 } 288 289 mScanDetails.add(ScanDetailUtil.toScanDetail(fullScanResult)); 290 } 291 } 292 293 private final PeriodicScanListener mPeriodicScanListener = new PeriodicScanListener(); 294 295 // All single scan results listener. 296 // 297 // Note: This is the listener for all the available single scan results, 298 // including the ones initiated by WifiConnectivityManager and 299 // other modules. 300 private class AllSingleScanListener implements WifiScanner.ScanListener { 301 private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>(); 302 clearScanDetails()303 public void clearScanDetails() { 304 mScanDetails.clear(); 305 } 306 307 @Override onSuccess()308 public void onSuccess() { 309 localLog("registerScanListener onSuccess"); 310 } 311 312 @Override onFailure(int reason, String description)313 public void onFailure(int reason, String description) { 314 Log.e(TAG, "registerScanListener onFailure:" 315 + " reason: " + reason 316 + " description: " + description); 317 } 318 319 @Override onPeriodChanged(int periodInMs)320 public void onPeriodChanged(int periodInMs) { 321 } 322 323 @Override onResults(WifiScanner.ScanData[] results)324 public void onResults(WifiScanner.ScanData[] results) { 325 if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) { 326 clearScanDetails(); 327 return; 328 } 329 330 boolean wasConnectAttempted = handleScanResults(mScanDetails, "AllSingleScanListener"); 331 clearScanDetails(); 332 333 // Update metrics to see if a single scan detected a valid network 334 // while PNO scan didn't. 335 // Note: We don't update the background scan metrics any more as it is 336 // not in use. 337 if (mPnoScanStarted) { 338 if (wasConnectAttempted) { 339 mWifiMetrics.incrementNumConnectivityWatchdogPnoBad(); 340 } else { 341 mWifiMetrics.incrementNumConnectivityWatchdogPnoGood(); 342 } 343 } 344 } 345 346 @Override onFullResult(ScanResult fullScanResult)347 public void onFullResult(ScanResult fullScanResult) { 348 if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) { 349 return; 350 } 351 352 if (mDbg) { 353 localLog("AllSingleScanListener onFullResult: " 354 + fullScanResult.SSID + " capabilities " 355 + fullScanResult.capabilities); 356 } 357 358 mScanDetails.add(ScanDetailUtil.toScanDetail(fullScanResult)); 359 } 360 } 361 362 private final AllSingleScanListener mAllSingleScanListener = new AllSingleScanListener(); 363 364 // Single scan results listener. A single scan is initiated when 365 // Disconnected/ConnectedPNO scan found a valid network and woke up 366 // the system, or by the watchdog timer, or to form the timer based 367 // periodic scan. 368 // 369 // Note: This is the listener for the single scans initiated by the 370 // WifiConnectivityManager. 371 private class SingleScanListener implements WifiScanner.ScanListener { 372 private final boolean mIsFullBandScan; 373 SingleScanListener(boolean isFullBandScan)374 SingleScanListener(boolean isFullBandScan) { 375 mIsFullBandScan = isFullBandScan; 376 } 377 378 @Override onSuccess()379 public void onSuccess() { 380 localLog("SingleScanListener onSuccess"); 381 } 382 383 @Override onFailure(int reason, String description)384 public void onFailure(int reason, String description) { 385 Log.e(TAG, "SingleScanListener onFailure:" 386 + " reason: " + reason 387 + " description: " + description); 388 389 // reschedule the scan 390 if (mSingleScanRestartCount++ < MAX_SCAN_RESTART_ALLOWED) { 391 scheduleDelayedSingleScan(mIsFullBandScan); 392 } else { 393 mSingleScanRestartCount = 0; 394 Log.e(TAG, "Failed to successfully start single scan for " 395 + MAX_SCAN_RESTART_ALLOWED + " times"); 396 } 397 } 398 399 @Override onPeriodChanged(int periodInMs)400 public void onPeriodChanged(int periodInMs) { 401 localLog("SingleScanListener onPeriodChanged: " 402 + "actual scan period " + periodInMs + "ms"); 403 } 404 405 @Override onResults(WifiScanner.ScanData[] results)406 public void onResults(WifiScanner.ScanData[] results) { 407 } 408 409 @Override onFullResult(ScanResult fullScanResult)410 public void onFullResult(ScanResult fullScanResult) { 411 } 412 } 413 414 // re-enable this when b/27695292 is fixed 415 // private final SingleScanListener mSingleScanListener = new SingleScanListener(); 416 417 // PNO scan results listener for both disconected and connected PNO scanning. 418 // A PNO scan is initiated when screen is off. 419 private class PnoScanListener implements WifiScanner.PnoScanListener { 420 private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>(); 421 private int mLowRssiNetworkRetryDelay = 422 LOW_RSSI_NETWORK_RETRY_START_DELAY_MS; 423 clearScanDetails()424 public void clearScanDetails() { 425 mScanDetails.clear(); 426 } 427 428 // Reset to the start value when either a non-PNO scan is started or 429 // QNS selects a candidate from the PNO scan results. resetLowRssiNetworkRetryDelay()430 public void resetLowRssiNetworkRetryDelay() { 431 mLowRssiNetworkRetryDelay = LOW_RSSI_NETWORK_RETRY_START_DELAY_MS; 432 } 433 434 @VisibleForTesting getLowRssiNetworkRetryDelay()435 public int getLowRssiNetworkRetryDelay() { 436 return mLowRssiNetworkRetryDelay; 437 } 438 439 @Override onSuccess()440 public void onSuccess() { 441 localLog("PnoScanListener onSuccess"); 442 } 443 444 @Override onFailure(int reason, String description)445 public void onFailure(int reason, String description) { 446 Log.e(TAG, "PnoScanListener onFailure:" 447 + " reason: " + reason 448 + " description: " + description); 449 450 // reschedule the scan 451 if (mScanRestartCount++ < MAX_SCAN_RESTART_ALLOWED) { 452 scheduleDelayedConnectivityScan(RESTART_SCAN_DELAY_MS); 453 } else { 454 mScanRestartCount = 0; 455 Log.e(TAG, "Failed to successfully start PNO scan for " 456 + MAX_SCAN_RESTART_ALLOWED + " times"); 457 } 458 } 459 460 @Override onPeriodChanged(int periodInMs)461 public void onPeriodChanged(int periodInMs) { 462 localLog("PnoScanListener onPeriodChanged: " 463 + "actual scan period " + periodInMs + "ms"); 464 } 465 466 // Currently the PNO scan results doesn't include IE, 467 // which contains information required by QNS. Ignore them 468 // for now. 469 @Override onResults(WifiScanner.ScanData[] results)470 public void onResults(WifiScanner.ScanData[] results) { 471 } 472 473 @Override onFullResult(ScanResult fullScanResult)474 public void onFullResult(ScanResult fullScanResult) { 475 } 476 477 @Override onPnoNetworkFound(ScanResult[] results)478 public void onPnoNetworkFound(ScanResult[] results) { 479 localLog("PnoScanListener: onPnoNetworkFound: results len = " + results.length); 480 481 for (ScanResult result: results) { 482 mScanDetails.add(ScanDetailUtil.toScanDetail(result)); 483 } 484 485 boolean wasConnectAttempted; 486 wasConnectAttempted = handleScanResults(mScanDetails, "PnoScanListener"); 487 clearScanDetails(); 488 mScanRestartCount = 0; 489 490 if (!wasConnectAttempted) { 491 // The scan results were rejected by QNS due to low RSSI values 492 if (mLowRssiNetworkRetryDelay > LOW_RSSI_NETWORK_RETRY_MAX_DELAY_MS) { 493 mLowRssiNetworkRetryDelay = LOW_RSSI_NETWORK_RETRY_MAX_DELAY_MS; 494 } 495 scheduleDelayedConnectivityScan(mLowRssiNetworkRetryDelay); 496 497 // Set up the delay value for next retry. 498 mLowRssiNetworkRetryDelay *= 2; 499 } else { 500 resetLowRssiNetworkRetryDelay(); 501 } 502 } 503 } 504 505 private final PnoScanListener mPnoScanListener = new PnoScanListener(); 506 507 /** 508 * WifiConnectivityManager constructor 509 */ WifiConnectivityManager(Context context, WifiStateMachine stateMachine, WifiScanner scanner, WifiConfigManager configManager, WifiInfo wifiInfo, WifiQualifiedNetworkSelector qualifiedNetworkSelector, WifiInjector wifiInjector, Looper looper)510 public WifiConnectivityManager(Context context, WifiStateMachine stateMachine, 511 WifiScanner scanner, WifiConfigManager configManager, WifiInfo wifiInfo, 512 WifiQualifiedNetworkSelector qualifiedNetworkSelector, 513 WifiInjector wifiInjector, Looper looper) { 514 mStateMachine = stateMachine; 515 mScanner = scanner; 516 mConfigManager = configManager; 517 mWifiInfo = wifiInfo; 518 mQualifiedNetworkSelector = qualifiedNetworkSelector; 519 mWifiLastResortWatchdog = wifiInjector.getWifiLastResortWatchdog(); 520 mWifiMetrics = wifiInjector.getWifiMetrics(); 521 mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 522 mEventHandler = new Handler(looper); 523 mClock = wifiInjector.getClock(); 524 mConnectionAttemptTimeStamps = new LinkedList<>(); 525 526 mMin5GHzRssi = WifiQualifiedNetworkSelector.MINIMUM_5G_ACCEPT_RSSI; 527 mMin24GHzRssi = WifiQualifiedNetworkSelector.MINIMUM_2G_ACCEPT_RSSI; 528 mBand5GHzBonus = WifiQualifiedNetworkSelector.BAND_AWARD_5GHz; 529 mCurrentConnectionBonus = mConfigManager.mCurrentNetworkBoost.get(); 530 mSameNetworkBonus = context.getResources().getInteger( 531 R.integer.config_wifi_framework_SAME_BSSID_AWARD); 532 mSecureBonus = context.getResources().getInteger( 533 R.integer.config_wifi_framework_SECURITY_AWARD); 534 mInitialScoreMax = (mConfigManager.mThresholdSaturatedRssi24.get() 535 + WifiQualifiedNetworkSelector.RSSI_SCORE_OFFSET) 536 * WifiQualifiedNetworkSelector.RSSI_SCORE_SLOPE; 537 538 Log.i(TAG, "PNO settings:" + " min5GHzRssi " + mMin5GHzRssi 539 + " min24GHzRssi " + mMin24GHzRssi 540 + " currentConnectionBonus " + mCurrentConnectionBonus 541 + " sameNetworkBonus " + mSameNetworkBonus 542 + " secureNetworkBonus " + mSecureBonus 543 + " initialScoreMax " + mInitialScoreMax); 544 545 // Register for all single scan results 546 mScanner.registerScanListener(mAllSingleScanListener); 547 548 Log.i(TAG, "ConnectivityScanManager initialized "); 549 } 550 551 /** 552 * This checks the connection attempt rate and recommends whether the connection attempt 553 * should be skipped or not. This attempts to rate limit the rate of connections to 554 * prevent us from flapping between networks and draining battery rapidly. 555 */ shouldSkipConnectionAttempt(Long timeMillis)556 private boolean shouldSkipConnectionAttempt(Long timeMillis) { 557 Iterator<Long> attemptIter = mConnectionAttemptTimeStamps.iterator(); 558 // First evict old entries from the queue. 559 while (attemptIter.hasNext()) { 560 Long connectionAttemptTimeMillis = attemptIter.next(); 561 if ((timeMillis - connectionAttemptTimeMillis) 562 > MAX_CONNECTION_ATTEMPTS_TIME_INTERVAL_MS) { 563 attemptIter.remove(); 564 } else { 565 // This list is sorted by timestamps, so we can skip any more checks 566 break; 567 } 568 } 569 // If we've reached the max connection attempt rate, skip this connection attempt 570 return (mConnectionAttemptTimeStamps.size() >= MAX_CONNECTION_ATTEMPTS_RATE); 571 } 572 573 /** 574 * Add the current connection attempt timestamp to our queue of connection attempts. 575 */ noteConnectionAttempt(Long timeMillis)576 private void noteConnectionAttempt(Long timeMillis) { 577 mConnectionAttemptTimeStamps.addLast(timeMillis); 578 } 579 580 /** 581 * This is used to clear the connection attempt rate limiter. This is done when the user 582 * explicitly tries to connect to a specified network. 583 */ clearConnectionAttemptTimeStamps()584 private void clearConnectionAttemptTimeStamps() { 585 mConnectionAttemptTimeStamps.clear(); 586 } 587 588 /** 589 * Attempt to connect to a network candidate. 590 * 591 * Based on the currently connected network, this menthod determines whether we should 592 * connect or roam to the network candidate recommended by QNS. 593 */ connectToNetwork(WifiConfiguration candidate)594 private void connectToNetwork(WifiConfiguration candidate) { 595 ScanResult scanResultCandidate = candidate.getNetworkSelectionStatus().getCandidate(); 596 if (scanResultCandidate == null) { 597 Log.e(TAG, "connectToNetwork: bad candidate - " + candidate 598 + " scanResult: " + scanResultCandidate); 599 return; 600 } 601 602 String targetBssid = scanResultCandidate.BSSID; 603 String targetAssociationId = candidate.SSID + " : " + targetBssid; 604 605 // Check if we are already connected or in the process of connecting to the target 606 // BSSID. mWifiInfo.mBSSID tracks the currently connected BSSID. This is checked just 607 // in case the firmware automatically roamed to a BSSID different from what QNS 608 // selected. 609 if (targetBssid != null 610 && (targetBssid.equals(mLastConnectionAttemptBssid) 611 || targetBssid.equals(mWifiInfo.getBSSID())) 612 && SupplicantState.isConnecting(mWifiInfo.getSupplicantState())) { 613 localLog("connectToNetwork: Either already connected " 614 + "or is connecting to " + targetAssociationId); 615 return; 616 } 617 618 Long elapsedTimeMillis = mClock.elapsedRealtime(); 619 if (!mScreenOn && shouldSkipConnectionAttempt(elapsedTimeMillis)) { 620 localLog("connectToNetwork: Too many connection attempts. Skipping this attempt!"); 621 mTotalConnectivityAttemptsRateLimited++; 622 return; 623 } 624 noteConnectionAttempt(elapsedTimeMillis); 625 626 mLastConnectionAttemptBssid = targetBssid; 627 628 WifiConfiguration currentConnectedNetwork = mConfigManager 629 .getWifiConfiguration(mWifiInfo.getNetworkId()); 630 String currentAssociationId = (currentConnectedNetwork == null) ? "Disconnected" : 631 (mWifiInfo.getSSID() + " : " + mWifiInfo.getBSSID()); 632 633 if (currentConnectedNetwork != null 634 && (currentConnectedNetwork.networkId == candidate.networkId 635 || currentConnectedNetwork.isLinked(candidate))) { 636 localLog("connectToNetwork: Roaming from " + currentAssociationId + " to " 637 + targetAssociationId); 638 mStateMachine.autoRoamToNetwork(candidate.networkId, scanResultCandidate); 639 } else { 640 localLog("connectToNetwork: Reconnect from " + currentAssociationId + " to " 641 + targetAssociationId); 642 mStateMachine.autoConnectToNetwork(candidate.networkId, scanResultCandidate.BSSID); 643 } 644 } 645 646 // Helper for selecting the band for connectivity scan getScanBand()647 private int getScanBand() { 648 return getScanBand(true); 649 } 650 getScanBand(boolean isFullBandScan)651 private int getScanBand(boolean isFullBandScan) { 652 if (isFullBandScan) { 653 int freqBand = mStateMachine.getFrequencyBand(); 654 if (freqBand == WifiManager.WIFI_FREQUENCY_BAND_5GHZ) { 655 return WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS; 656 } else if (freqBand == WifiManager.WIFI_FREQUENCY_BAND_2GHZ) { 657 return WifiScanner.WIFI_BAND_24_GHZ; 658 } else { 659 return WifiScanner.WIFI_BAND_BOTH_WITH_DFS; 660 } 661 } else { 662 // Use channel list instead. 663 return WifiScanner.WIFI_BAND_UNSPECIFIED; 664 } 665 } 666 667 // Helper for setting the channels for connectivity scan when band is unspecified. Returns 668 // false if we can't retrieve the info. setScanChannels(ScanSettings settings)669 private boolean setScanChannels(ScanSettings settings) { 670 WifiConfiguration config = mStateMachine.getCurrentWifiConfiguration(); 671 672 if (config == null) { 673 return false; 674 } 675 676 HashSet<Integer> freqs = mConfigManager.makeChannelList(config, CHANNEL_LIST_AGE_MS); 677 678 if (freqs != null && freqs.size() != 0) { 679 int index = 0; 680 settings.channels = new WifiScanner.ChannelSpec[freqs.size()]; 681 for (Integer freq : freqs) { 682 settings.channels[index++] = new WifiScanner.ChannelSpec(freq); 683 } 684 return true; 685 } else { 686 localLog("No scan channels for " + config.configKey() + ". Perform full band scan"); 687 return false; 688 } 689 } 690 691 // Watchdog timer handler watchdogHandler()692 private void watchdogHandler() { 693 localLog("watchdogHandler"); 694 695 // Schedule the next timer and start a single scan if we are in disconnected state. 696 // Otherwise, the watchdog timer will be scheduled when entering disconnected 697 // state. 698 if (mWifiState == WIFI_STATE_DISCONNECTED) { 699 Log.i(TAG, "start a single scan from watchdogHandler"); 700 701 scheduleWatchdogTimer(); 702 startSingleScan(true); 703 } 704 } 705 706 // Start a single scan and set up the interval for next single scan. startPeriodicSingleScan()707 private void startPeriodicSingleScan() { 708 long currentTimeStamp = mClock.elapsedRealtime(); 709 710 if (mLastPeriodicSingleScanTimeStamp != RESET_TIME_STAMP) { 711 long msSinceLastScan = currentTimeStamp - mLastPeriodicSingleScanTimeStamp; 712 if (msSinceLastScan < PERIODIC_SCAN_INTERVAL_MS) { 713 localLog("Last periodic single scan started " + msSinceLastScan 714 + "ms ago, defer this new scan request."); 715 schedulePeriodicScanTimer(PERIODIC_SCAN_INTERVAL_MS - (int) msSinceLastScan); 716 return; 717 } 718 } 719 720 boolean isFullBandScan = true; 721 722 // If the WiFi traffic is heavy, only partial scan is initiated. 723 if (mWifiState == WIFI_STATE_CONNECTED 724 && (mWifiInfo.txSuccessRate 725 > mConfigManager.MAX_TX_PACKET_FOR_FULL_SCANS 726 || mWifiInfo.rxSuccessRate 727 > mConfigManager.MAX_RX_PACKET_FOR_FULL_SCANS)) { 728 localLog("No full band scan due to heavy traffic, txSuccessRate=" 729 + mWifiInfo.txSuccessRate + " rxSuccessRate=" 730 + mWifiInfo.rxSuccessRate); 731 isFullBandScan = false; 732 } 733 734 mLastPeriodicSingleScanTimeStamp = currentTimeStamp; 735 startSingleScan(isFullBandScan); 736 schedulePeriodicScanTimer(mPeriodicSingleScanInterval); 737 738 // Set up the next scan interval in an exponential backoff fashion. 739 mPeriodicSingleScanInterval *= 2; 740 if (mPeriodicSingleScanInterval > MAX_PERIODIC_SCAN_INTERVAL_MS) { 741 mPeriodicSingleScanInterval = MAX_PERIODIC_SCAN_INTERVAL_MS; 742 } 743 } 744 745 // Reset the last periodic single scan time stamp so that the next periodic single 746 // scan can start immediately. resetLastPeriodicSingleScanTimeStamp()747 private void resetLastPeriodicSingleScanTimeStamp() { 748 mLastPeriodicSingleScanTimeStamp = RESET_TIME_STAMP; 749 } 750 751 // Periodic scan timer handler periodicScanTimerHandler()752 private void periodicScanTimerHandler() { 753 localLog("periodicScanTimerHandler"); 754 755 // Schedule the next timer and start a single scan if screen is on. 756 if (mScreenOn) { 757 startPeriodicSingleScan(); 758 } 759 } 760 761 // Start a single scan startSingleScan(boolean isFullBandScan)762 private void startSingleScan(boolean isFullBandScan) { 763 if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) { 764 return; 765 } 766 767 mPnoScanListener.resetLowRssiNetworkRetryDelay(); 768 769 ScanSettings settings = new ScanSettings(); 770 if (!isFullBandScan) { 771 if (!setScanChannels(settings)) { 772 isFullBandScan = true; 773 } 774 } 775 settings.band = getScanBand(isFullBandScan); 776 settings.reportEvents = WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT 777 | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN; 778 settings.numBssidsPerScan = 0; 779 780 //Retrieve the list of hidden networkId's to scan for. 781 Set<Integer> hiddenNetworkIds = mConfigManager.getHiddenConfiguredNetworkIds(); 782 if (hiddenNetworkIds != null && hiddenNetworkIds.size() > 0) { 783 int i = 0; 784 settings.hiddenNetworkIds = new int[hiddenNetworkIds.size()]; 785 for (Integer netId : hiddenNetworkIds) { 786 settings.hiddenNetworkIds[i++] = netId; 787 } 788 } 789 790 // re-enable this when b/27695292 is fixed 791 // mSingleScanListener.clearScanDetails(); 792 // mScanner.startScan(settings, mSingleScanListener, WIFI_WORK_SOURCE); 793 SingleScanListener singleScanListener = 794 new SingleScanListener(isFullBandScan); 795 mScanner.startScan(settings, singleScanListener, WIFI_WORK_SOURCE); 796 } 797 798 // Start a periodic scan when screen is on startPeriodicScan(boolean scanImmediately)799 private void startPeriodicScan(boolean scanImmediately) { 800 mPnoScanListener.resetLowRssiNetworkRetryDelay(); 801 802 // No connectivity scan if auto roaming is disabled. 803 if (mWifiState == WIFI_STATE_CONNECTED 804 && !mConfigManager.getEnableAutoJoinWhenAssociated()) { 805 return; 806 } 807 808 // Due to b/28020168, timer based single scan will be scheduled 809 // to provide periodic scan in an exponential backoff fashion. 810 if (!ENABLE_BACKGROUND_SCAN) { 811 if (scanImmediately) { 812 resetLastPeriodicSingleScanTimeStamp(); 813 } 814 mPeriodicSingleScanInterval = PERIODIC_SCAN_INTERVAL_MS; 815 startPeriodicSingleScan(); 816 } else { 817 ScanSettings settings = new ScanSettings(); 818 settings.band = getScanBand(); 819 settings.reportEvents = WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT 820 | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN; 821 settings.numBssidsPerScan = 0; 822 settings.periodInMs = PERIODIC_SCAN_INTERVAL_MS; 823 824 mPeriodicScanListener.clearScanDetails(); 825 mScanner.startBackgroundScan(settings, mPeriodicScanListener, WIFI_WORK_SOURCE); 826 } 827 } 828 829 // Start a DisconnectedPNO scan when screen is off and Wifi is disconnected startDisconnectedPnoScan()830 private void startDisconnectedPnoScan() { 831 // Initialize PNO settings 832 PnoSettings pnoSettings = new PnoSettings(); 833 ArrayList<PnoSettings.PnoNetwork> pnoNetworkList = 834 mConfigManager.retrieveDisconnectedPnoNetworkList(); 835 int listSize = pnoNetworkList.size(); 836 837 if (listSize == 0) { 838 // No saved network 839 localLog("No saved network for starting disconnected PNO."); 840 return; 841 } 842 843 pnoSettings.networkList = new PnoSettings.PnoNetwork[listSize]; 844 pnoSettings.networkList = pnoNetworkList.toArray(pnoSettings.networkList); 845 pnoSettings.min5GHzRssi = mMin5GHzRssi; 846 pnoSettings.min24GHzRssi = mMin24GHzRssi; 847 pnoSettings.initialScoreMax = mInitialScoreMax; 848 pnoSettings.currentConnectionBonus = mCurrentConnectionBonus; 849 pnoSettings.sameNetworkBonus = mSameNetworkBonus; 850 pnoSettings.secureBonus = mSecureBonus; 851 pnoSettings.band5GHzBonus = mBand5GHzBonus; 852 853 // Initialize scan settings 854 ScanSettings scanSettings = new ScanSettings(); 855 scanSettings.band = getScanBand(); 856 scanSettings.reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH; 857 scanSettings.numBssidsPerScan = 0; 858 scanSettings.periodInMs = DISCONNECTED_PNO_SCAN_INTERVAL_MS; 859 // TODO: enable exponential back off scan later to further save energy 860 // scanSettings.maxPeriodInMs = 8 * scanSettings.periodInMs; 861 862 mPnoScanListener.clearScanDetails(); 863 864 mScanner.startDisconnectedPnoScan(scanSettings, pnoSettings, mPnoScanListener); 865 mPnoScanStarted = true; 866 } 867 868 // Start a ConnectedPNO scan when screen is off and Wifi is connected startConnectedPnoScan()869 private void startConnectedPnoScan() { 870 // Disable ConnectedPNO for now due to b/28020168 871 if (!ENABLE_CONNECTED_PNO_SCAN) { 872 return; 873 } 874 875 // Initialize PNO settings 876 PnoSettings pnoSettings = new PnoSettings(); 877 ArrayList<PnoSettings.PnoNetwork> pnoNetworkList = 878 mConfigManager.retrieveConnectedPnoNetworkList(); 879 int listSize = pnoNetworkList.size(); 880 881 if (listSize == 0) { 882 // No saved network 883 localLog("No saved network for starting connected PNO."); 884 return; 885 } 886 887 pnoSettings.networkList = new PnoSettings.PnoNetwork[listSize]; 888 pnoSettings.networkList = pnoNetworkList.toArray(pnoSettings.networkList); 889 pnoSettings.min5GHzRssi = mMin5GHzRssi; 890 pnoSettings.min24GHzRssi = mMin24GHzRssi; 891 pnoSettings.initialScoreMax = mInitialScoreMax; 892 pnoSettings.currentConnectionBonus = mCurrentConnectionBonus; 893 pnoSettings.sameNetworkBonus = mSameNetworkBonus; 894 pnoSettings.secureBonus = mSecureBonus; 895 pnoSettings.band5GHzBonus = mBand5GHzBonus; 896 897 // Initialize scan settings 898 ScanSettings scanSettings = new ScanSettings(); 899 scanSettings.band = getScanBand(); 900 scanSettings.reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH; 901 scanSettings.numBssidsPerScan = 0; 902 scanSettings.periodInMs = CONNECTED_PNO_SCAN_INTERVAL_MS; 903 // TODO: enable exponential back off scan later to further save energy 904 // scanSettings.maxPeriodInMs = 8 * scanSettings.periodInMs; 905 906 mPnoScanListener.clearScanDetails(); 907 908 mScanner.startConnectedPnoScan(scanSettings, pnoSettings, mPnoScanListener); 909 mPnoScanStarted = true; 910 } 911 912 // Stop a PNO scan. This includes both DisconnectedPNO and ConnectedPNO scans. stopPnoScan()913 private void stopPnoScan() { 914 if (mPnoScanStarted) { 915 mScanner.stopPnoScan(mPnoScanListener); 916 } 917 918 mPnoScanStarted = false; 919 } 920 921 // Set up watchdog timer scheduleWatchdogTimer()922 private void scheduleWatchdogTimer() { 923 Log.i(TAG, "scheduleWatchdogTimer"); 924 925 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 926 mClock.elapsedRealtime() + WATCHDOG_INTERVAL_MS, 927 WATCHDOG_TIMER_TAG, 928 mWatchdogListener, mEventHandler); 929 } 930 931 // Set up periodic scan timer schedulePeriodicScanTimer(int intervalMs)932 private void schedulePeriodicScanTimer(int intervalMs) { 933 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 934 mClock.elapsedRealtime() + intervalMs, 935 PERIODIC_SCAN_TIMER_TAG, 936 mPeriodicScanTimerListener, mEventHandler); 937 mPeriodicScanTimerSet = true; 938 } 939 940 // Cancel periodic scan timer cancelPeriodicScanTimer()941 private void cancelPeriodicScanTimer() { 942 if (mPeriodicScanTimerSet) { 943 mAlarmManager.cancel(mPeriodicScanTimerListener); 944 mPeriodicScanTimerSet = false; 945 } 946 } 947 948 // Set up timer to start a delayed single scan after RESTART_SCAN_DELAY_MS scheduleDelayedSingleScan(boolean isFullBandScan)949 private void scheduleDelayedSingleScan(boolean isFullBandScan) { 950 localLog("scheduleDelayedSingleScan"); 951 952 RestartSingleScanListener restartSingleScanListener = 953 new RestartSingleScanListener(isFullBandScan); 954 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 955 mClock.elapsedRealtime() + RESTART_SCAN_DELAY_MS, 956 RESTART_SINGLE_SCAN_TIMER_TAG, 957 restartSingleScanListener, mEventHandler); 958 } 959 960 // Set up timer to start a delayed scan after msFromNow milli-seconds scheduleDelayedConnectivityScan(int msFromNow)961 private void scheduleDelayedConnectivityScan(int msFromNow) { 962 localLog("scheduleDelayedConnectivityScan"); 963 964 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 965 mClock.elapsedRealtime() + msFromNow, 966 RESTART_CONNECTIVITY_SCAN_TIMER_TAG, 967 mRestartScanListener, mEventHandler); 968 969 } 970 971 // Start a connectivity scan. The scan method is chosen according to 972 // the current screen state and WiFi state. startConnectivityScan(boolean scanImmediately)973 private void startConnectivityScan(boolean scanImmediately) { 974 localLog("startConnectivityScan: screenOn=" + mScreenOn 975 + " wifiState=" + mWifiState 976 + " scanImmediately=" + scanImmediately 977 + " wifiEnabled=" + mWifiEnabled 978 + " wifiConnectivityManagerEnabled=" 979 + mWifiConnectivityManagerEnabled); 980 981 if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) { 982 return; 983 } 984 985 // Always stop outstanding connecivity scan if there is any 986 stopConnectivityScan(); 987 988 // Don't start a connectivity scan while Wifi is in the transition 989 // between connected and disconnected states. 990 if (mWifiState != WIFI_STATE_CONNECTED && mWifiState != WIFI_STATE_DISCONNECTED) { 991 return; 992 } 993 994 if (mScreenOn) { 995 startPeriodicScan(scanImmediately); 996 } else { // screenOff 997 if (mWifiState == WIFI_STATE_CONNECTED) { 998 startConnectedPnoScan(); 999 } else { 1000 startDisconnectedPnoScan(); 1001 } 1002 } 1003 } 1004 1005 // Stop connectivity scan if there is any. stopConnectivityScan()1006 private void stopConnectivityScan() { 1007 // Due to b/28020168, timer based single scan will be scheduled 1008 // to provide periodic scan in an exponential backoff fashion. 1009 if (!ENABLE_BACKGROUND_SCAN) { 1010 cancelPeriodicScanTimer(); 1011 } else { 1012 mScanner.stopBackgroundScan(mPeriodicScanListener); 1013 } 1014 stopPnoScan(); 1015 mScanRestartCount = 0; 1016 } 1017 1018 /** 1019 * Handler for screen state (on/off) changes 1020 */ handleScreenStateChanged(boolean screenOn)1021 public void handleScreenStateChanged(boolean screenOn) { 1022 localLog("handleScreenStateChanged: screenOn=" + screenOn); 1023 1024 mScreenOn = screenOn; 1025 1026 startConnectivityScan(SCAN_ON_SCHEDULE); 1027 } 1028 1029 /** 1030 * Handler for WiFi state (connected/disconnected) changes 1031 */ handleConnectionStateChanged(int state)1032 public void handleConnectionStateChanged(int state) { 1033 localLog("handleConnectionStateChanged: state=" + state); 1034 1035 mWifiState = state; 1036 1037 // Reset BSSID of last connection attempt and kick off 1038 // the watchdog timer if entering disconnected state. 1039 if (mWifiState == WIFI_STATE_DISCONNECTED) { 1040 mLastConnectionAttemptBssid = null; 1041 scheduleWatchdogTimer(); 1042 } 1043 1044 startConnectivityScan(SCAN_ON_SCHEDULE); 1045 } 1046 1047 /** 1048 * Handler when user toggles whether untrusted connection is allowed 1049 */ setUntrustedConnectionAllowed(boolean allowed)1050 public void setUntrustedConnectionAllowed(boolean allowed) { 1051 Log.i(TAG, "setUntrustedConnectionAllowed: allowed=" + allowed); 1052 1053 if (mUntrustedConnectionAllowed != allowed) { 1054 mUntrustedConnectionAllowed = allowed; 1055 startConnectivityScan(SCAN_IMMEDIATELY); 1056 } 1057 } 1058 1059 /** 1060 * Handler when user specifies a particular network to connect to 1061 */ connectToUserSelectNetwork(int netId, boolean persistent)1062 public void connectToUserSelectNetwork(int netId, boolean persistent) { 1063 Log.i(TAG, "connectToUserSelectNetwork: netId=" + netId 1064 + " persist=" + persistent); 1065 1066 mQualifiedNetworkSelector.userSelectNetwork(netId, persistent); 1067 1068 clearConnectionAttemptTimeStamps(); 1069 } 1070 1071 /** 1072 * Handler for on-demand connectivity scan 1073 */ forceConnectivityScan()1074 public void forceConnectivityScan() { 1075 Log.i(TAG, "forceConnectivityScan"); 1076 1077 startConnectivityScan(SCAN_IMMEDIATELY); 1078 } 1079 1080 /** 1081 * Track whether a BSSID should be enabled or disabled for QNS 1082 */ trackBssid(String bssid, boolean enable)1083 public boolean trackBssid(String bssid, boolean enable) { 1084 Log.i(TAG, "trackBssid: " + (enable ? "enable " : "disable ") + bssid); 1085 1086 boolean ret = mQualifiedNetworkSelector 1087 .enableBssidForQualityNetworkSelection(bssid, enable); 1088 1089 if (ret && !enable) { 1090 // Disabling a BSSID can happen when the AP candidate to connect to has 1091 // no capacity for new stations. We start another scan immediately so that QNS 1092 // can give us another candidate to connect to. 1093 startConnectivityScan(SCAN_IMMEDIATELY); 1094 } 1095 1096 return ret; 1097 } 1098 1099 /** 1100 * Set band preference when doing scan and making connection 1101 */ setUserPreferredBand(int band)1102 public void setUserPreferredBand(int band) { 1103 Log.i(TAG, "User band preference: " + band); 1104 1105 mQualifiedNetworkSelector.setUserPreferredBand(band); 1106 startConnectivityScan(SCAN_IMMEDIATELY); 1107 } 1108 1109 /** 1110 * Inform WiFi is enabled for connection or not 1111 */ setWifiEnabled(boolean enable)1112 public void setWifiEnabled(boolean enable) { 1113 Log.i(TAG, "Set WiFi " + (enable ? "enabled" : "disabled")); 1114 1115 mWifiEnabled = enable; 1116 1117 if (!mWifiEnabled) { 1118 stopConnectivityScan(); 1119 resetLastPeriodicSingleScanTimeStamp(); 1120 mLastConnectionAttemptBssid = null; 1121 } 1122 } 1123 1124 /** 1125 * Turn on/off the WifiConnectivityMangager at runtime 1126 */ enable(boolean enable)1127 public void enable(boolean enable) { 1128 Log.i(TAG, "Set WiFiConnectivityManager " + (enable ? "enabled" : "disabled")); 1129 1130 mWifiConnectivityManagerEnabled = enable; 1131 1132 if (!mWifiConnectivityManagerEnabled) { 1133 stopConnectivityScan(); 1134 resetLastPeriodicSingleScanTimeStamp(); 1135 mLastConnectionAttemptBssid = null; 1136 } 1137 } 1138 1139 /** 1140 * Enable/disable verbose logging 1141 */ enableVerboseLogging(int verbose)1142 public void enableVerboseLogging(int verbose) { 1143 mDbg = verbose > 0; 1144 } 1145 1146 /** 1147 * Dump the local log buffer 1148 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)1149 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1150 pw.println("Dump of WifiConnectivityManager"); 1151 pw.println("WifiConnectivityManager - Log Begin ----"); 1152 pw.println("WifiConnectivityManager - Number of connectivity attempts rate limited: " 1153 + mTotalConnectivityAttemptsRateLimited); 1154 mLocalLog.dump(fd, pw, args); 1155 pw.println("WifiConnectivityManager - Log End ----"); 1156 } 1157 1158 @VisibleForTesting getLowRssiNetworkRetryDelay()1159 int getLowRssiNetworkRetryDelay() { 1160 return mPnoScanListener.getLowRssiNetworkRetryDelay(); 1161 } 1162 1163 @VisibleForTesting getLastPeriodicSingleScanTimeStamp()1164 long getLastPeriodicSingleScanTimeStamp() { 1165 return mLastPeriodicSingleScanTimeStamp; 1166 } 1167 } 1168