WifiConnectivityManager.java revision 09abbe29be6e552a2531b0367bd6d29647d33767
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 17package com.android.server.wifi; 18 19import static com.android.server.wifi.WifiStateMachine.WIFI_WORK_SOURCE; 20 21import android.app.ActivityManager; 22import android.app.AlarmManager; 23import android.content.Context; 24import android.net.wifi.ScanResult; 25import android.net.wifi.WifiConfiguration; 26import android.net.wifi.WifiInfo; 27import android.net.wifi.WifiManager; 28import android.net.wifi.WifiScanner; 29import android.net.wifi.WifiScanner.PnoSettings; 30import android.net.wifi.WifiScanner.ScanSettings; 31import android.util.LocalLog; 32import android.util.Log; 33 34import com.android.internal.R; 35import com.android.server.wifi.util.ScanDetailUtil; 36 37import java.io.FileDescriptor; 38import java.io.PrintWriter; 39import java.util.ArrayList; 40import java.util.List; 41import java.util.Set; 42 43/** 44 * This class manages all the connectivity related scanning activities. 45 * 46 * When the screen is turned on or off, WiFi is connected or disconnected, 47 * or on-demand, a scan is initiatiated and the scan results are passed 48 * to QNS for it to make a recommendation on which network to connect to. 49 */ 50public class WifiConnectivityManager { 51 private static final String TAG = "WifiConnectivityManager"; 52 53 // Periodic scan interval in milli-seconds. This is the scan 54 // performed when screen is on. 55 private static final int PERIODIC_SCAN_INTERVAL_MS = 20000; // 20 seconds 56 // PNO scan interval in milli-seconds. This is the scan 57 // performed when screen is off. 58 private static final int PNO_SCAN_INTERVAL_MS = 160000; // 160 seconds 59 // Maximum number of retries when starting a scan failed 60 private static final int MAX_SCAN_RESTART_ALLOWED = 5; 61 // Number of milli-seconds to delay before retry starting 62 // a previously failed scan 63 private static final int RESTART_SCAN_DELAY_MS = 2000; // 2 seconds 64 // When in disconnected mode, a watchdog timer will be fired 65 // every WATCHDOG_INTERVAL_MS to start a single scan. This is 66 // to prevent caveat from things like PNO scan. 67 private static final int WATCHDOG_INTERVAL_MS = 1200000; // 20 minutes 68 69 // WifiStateMachine has a bunch of states. From the 70 // WifiConnectivityManager's perspective it only cares 71 // if it is in Connected state, Disconnected state or in 72 // transition between these two states. 73 public static final int WIFI_STATE_UNKNOWN = 0; 74 public static final int WIFI_STATE_CONNECTED = 1; 75 public static final int WIFI_STATE_DISCONNECTED = 2; 76 public static final int WIFI_STATE_TRANSITIONING = 3; 77 78 private final WifiStateMachine mStateMachine; 79 private final WifiScanner mScanner; 80 private final WifiConfigManager mConfigManager; 81 private final WifiInfo mWifiInfo; 82 private final WifiQualifiedNetworkSelector mQualifiedNetworkSelector; 83 private final AlarmManager mAlarmManager; 84 private final LocalLog mLocalLog = new LocalLog(ActivityManager.isLowRamDeviceStatic() 85 ? 1024 : 16384); 86 private final WifiLastResortWatchdog mWifiLastResortWatchdog; 87 private boolean mDbg = false; 88 private boolean mWifiEnabled = false; 89 private boolean mWifiConnectivityManagerEnabled = true; 90 private boolean mForceSelectNetwork = false; 91 private boolean mScreenOn = false; 92 private int mWifiState = WIFI_STATE_UNKNOWN; 93 private boolean mUntrustedConnectionAllowed = false; 94 private int mScanRestartCount = 0; 95 private int mSingleScanRestartCount = 0; 96 // Due to b/28020168, timer based single scan will be scheduled every 97 // PERIODIC_SCAN_INTERVAL_MS to provide periodic scan. 98 private boolean mNoBackgroundScan = true; 99 100 // PNO settings 101 private int mMin5GHzRssi; 102 private int mMin24GHzRssi; 103 private int mInitialScoreMax; 104 private int mCurrentConnectionBonus; 105 private int mSameNetworkBonus; 106 private int mSecureBonus; 107 private int mBand5GHzBonus; 108 109 // A helper to log debugging information in the local log buffer, which can 110 // be retrieved in bugreport. 111 private void localLog(String log) { 112 mLocalLog.log(log); 113 } 114 115 // A periodic/PNO scan will be rescheduled up to MAX_SCAN_RESTART_ALLOWED times 116 // if the start scan command failed. An timer is used here to make it a deferred retry. 117 private final AlarmManager.OnAlarmListener mRestartScanListener = 118 new AlarmManager.OnAlarmListener() { 119 public void onAlarm() { 120 startConnectivityScan(mForceSelectNetwork); 121 } 122 }; 123 124 // A single scan will be rescheduled up to MAX_SCAN_RESTART_ALLOWED times 125 // if the start scan command failed. An timer is used here to make it a deferred retry. 126 private final AlarmManager.OnAlarmListener mRestartSingleScanListener = 127 new AlarmManager.OnAlarmListener() { 128 public void onAlarm() { 129 startSingleScan(); 130 } 131 }; 132 133 // As a watchdog mechanism, a single scan will be scheduled every WATCHDOG_INTERVAL_MS 134 // if it is in the WIFI_STATE_DISCONNECTED state. 135 private final AlarmManager.OnAlarmListener mWatchdogListener = 136 new AlarmManager.OnAlarmListener() { 137 public void onAlarm() { 138 watchdogHandler(); 139 } 140 }; 141 142 // Due to b/28020168, timer based single scan will be scheduled every 143 // PERIODIC_SCAN_INTERVAL_MS to provide periodic scan. 144 private final AlarmManager.OnAlarmListener mPeriodicScanTimerListener = 145 new AlarmManager.OnAlarmListener() { 146 public void onAlarm() { 147 periodicScanTimerHandler(); 148 } 149 }; 150 151 /** 152 * Handles 'onResult' callbacks for the Periodic, Single & Pno ScanListener. 153 * Executes selection of potential network candidates, initiation of connection attempt to that 154 * network. 155 */ 156 private void handleScanResults(List<ScanDetail> scanDetails, String listenerName) { 157 localLog(listenerName + " onResults: start QNS"); 158 WifiConfiguration candidate = 159 mQualifiedNetworkSelector.selectQualifiedNetwork(mForceSelectNetwork, 160 mUntrustedConnectionAllowed, scanDetails, 161 mStateMachine.isLinkDebouncing(), mStateMachine.isConnected(), 162 mStateMachine.isDisconnected(), 163 mStateMachine.isSupplicantTransientState()); 164 mWifiLastResortWatchdog.updateAvailableNetworks( 165 mQualifiedNetworkSelector.getFilteredScanDetails()); 166 if (candidate != null) { 167 localLog(listenerName + ": QNS candidate-" + candidate.SSID); 168 connectToNetwork(candidate); 169 } 170 171 } 172 173 // Periodic scan results listener. A periodic scan is initiated when 174 // screen is on. 175 private class PeriodicScanListener implements WifiScanner.ScanListener { 176 private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>(); 177 178 public void clearScanDetails() { 179 mScanDetails.clear(); 180 } 181 182 @Override 183 public void onSuccess() { 184 localLog("PeriodicScanListener onSuccess"); 185 186 // reset the count 187 mScanRestartCount = 0; 188 } 189 190 @Override 191 public void onFailure(int reason, String description) { 192 Log.e(TAG, "PeriodicScanListener onFailure:" 193 + " reason: " + reason 194 + " description: " + description); 195 196 // reschedule the scan 197 if (mScanRestartCount++ < MAX_SCAN_RESTART_ALLOWED) { 198 scheduleDelayedConnectivityScan(); 199 } else { 200 mScanRestartCount = 0; 201 Log.e(TAG, "Failed to successfully start periodic scan for " 202 + MAX_SCAN_RESTART_ALLOWED + " times"); 203 } 204 } 205 206 @Override 207 public void onPeriodChanged(int periodInMs) { 208 localLog("PeriodicScanListener onPeriodChanged: " 209 + "actual scan period " + periodInMs + "ms"); 210 } 211 212 @Override 213 public void onResults(WifiScanner.ScanData[] results) { 214 handleScanResults(mScanDetails, "PeriodicScanListener"); 215 clearScanDetails(); 216 } 217 218 @Override 219 public void onFullResult(ScanResult fullScanResult) { 220 if (mDbg) { 221 localLog("PeriodicScanListener onFullResult: " 222 + fullScanResult.SSID + " capabilities " 223 + fullScanResult.capabilities); 224 } 225 226 mScanDetails.add(ScanDetailUtil.toScanDetail(fullScanResult)); 227 } 228 } 229 230 private final PeriodicScanListener mPeriodicScanListener = new PeriodicScanListener(); 231 232 // Single scan results listener. A single scan is initiated when 233 // Disconnected/ConnectedPNO scan found a valid network and woke up 234 // the system, or by the watchdog timer. 235 private class SingleScanListener implements WifiScanner.ScanListener { 236 private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>(); 237 238 public void clearScanDetails() { 239 mScanDetails.clear(); 240 } 241 242 @Override 243 public void onSuccess() { 244 localLog("SingleScanListener onSuccess"); 245 246 // reset the count 247 mSingleScanRestartCount = 0; 248 } 249 250 @Override 251 public void onFailure(int reason, String description) { 252 Log.e(TAG, "SingleScanListener onFailure:" 253 + " reason: " + reason 254 + " description: " + description); 255 256 // reschedule the scan 257 if (mSingleScanRestartCount++ < MAX_SCAN_RESTART_ALLOWED) { 258 scheduleDelayedSingleScan(); 259 } else { 260 mSingleScanRestartCount = 0; 261 Log.e(TAG, "Failed to successfully start single scan for " 262 + MAX_SCAN_RESTART_ALLOWED + " times"); 263 } 264 } 265 266 @Override 267 public void onPeriodChanged(int periodInMs) { 268 localLog("SingleScanListener onPeriodChanged: " 269 + "actual scan period " + periodInMs + "ms"); 270 } 271 272 @Override 273 public void onResults(WifiScanner.ScanData[] results) { 274 handleScanResults(mScanDetails, "SingleScanListener"); 275 } 276 277 @Override 278 public void onFullResult(ScanResult fullScanResult) { 279 if (mDbg) { 280 localLog("SingleScanListener onFullResult: " 281 + fullScanResult.SSID + " capabilities " 282 + fullScanResult.capabilities); 283 } 284 285 mScanDetails.add(ScanDetailUtil.toScanDetail(fullScanResult)); 286 } 287 } 288 289 // re-enable this when b/27695292 is fixed 290 // private final SingleScanListener mSingleScanListener = new SingleScanListener(); 291 292 // PNO scan results listener for both disconected and connected PNO scanning. 293 // A PNO scan is initiated when screen is off. 294 private class PnoScanListener implements WifiScanner.PnoScanListener { 295 private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>(); 296 297 public void clearScanDetails() { 298 mScanDetails.clear(); 299 } 300 301 @Override 302 public void onSuccess() { 303 localLog("PnoScanListener onSuccess"); 304 305 // reset the count 306 mScanRestartCount = 0; 307 } 308 309 @Override 310 public void onFailure(int reason, String description) { 311 Log.e(TAG, "PnoScanListener onFailure:" 312 + " reason: " + reason 313 + " description: " + description); 314 315 // reschedule the scan 316 if (mScanRestartCount++ < MAX_SCAN_RESTART_ALLOWED) { 317 scheduleDelayedConnectivityScan(); 318 } else { 319 mScanRestartCount = 0; 320 Log.e(TAG, "Failed to successfully start PNO scan for " 321 + MAX_SCAN_RESTART_ALLOWED + " times"); 322 } 323 } 324 325 @Override 326 public void onPeriodChanged(int periodInMs) { 327 localLog("PnoScanListener onPeriodChanged: " 328 + "actual scan period " + periodInMs + "ms"); 329 } 330 331 // Currently the PNO scan results doesn't include IE, 332 // which contains information required by QNS. Ignore them 333 // for now. 334 @Override 335 public void onResults(WifiScanner.ScanData[] results) { 336 } 337 338 @Override 339 public void onFullResult(ScanResult fullScanResult) { 340 } 341 342 @Override 343 public void onPnoNetworkFound(ScanResult[] results) { 344 localLog("PnoScanListener: onPnoNetworkFound: results len = " + results.length); 345 346 for (ScanResult result: results) { 347 mScanDetails.add(ScanDetailUtil.toScanDetail(result)); 348 } 349 handleScanResults(mScanDetails, "PnoScanListener"); 350 } 351 } 352 353 private final PnoScanListener mPnoScanListener = new PnoScanListener(); 354 355 /** 356 * WifiConnectivityManager constructor 357 */ 358 public WifiConnectivityManager(Context context, WifiStateMachine stateMachine, 359 WifiScanner scanner, WifiConfigManager configManager, WifiInfo wifiInfo, 360 WifiQualifiedNetworkSelector qualifiedNetworkSelector, 361 WifiInjector wifiInjector) { 362 mStateMachine = stateMachine; 363 mScanner = scanner; 364 mConfigManager = configManager; 365 mWifiInfo = wifiInfo; 366 mQualifiedNetworkSelector = qualifiedNetworkSelector; 367 mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 368 mWifiLastResortWatchdog = wifiInjector.getWifiLastResortWatchdog(); 369 370 mMin5GHzRssi = WifiQualifiedNetworkSelector.MINIMUM_5G_ACCEPT_RSSI; 371 mMin24GHzRssi = WifiQualifiedNetworkSelector.MINIMUM_2G_ACCEPT_RSSI; 372 mBand5GHzBonus = WifiQualifiedNetworkSelector.BAND_AWARD_5GHz; 373 mCurrentConnectionBonus = mConfigManager.mCurrentNetworkBoost.get(); 374 mSameNetworkBonus = context.getResources().getInteger( 375 R.integer.config_wifi_framework_SAME_BSSID_AWARD); 376 mSecureBonus = context.getResources().getInteger( 377 R.integer.config_wifi_framework_SECURITY_AWARD); 378 mInitialScoreMax = (mConfigManager.mThresholdSaturatedRssi24.get() 379 + WifiQualifiedNetworkSelector.RSSI_SCORE_OFFSET) 380 * WifiQualifiedNetworkSelector.RSSI_SCORE_SLOPE; 381 382 Log.i(TAG, "PNO settings:" + " min5GHzRssi " + mMin5GHzRssi 383 + " min24GHzRssi " + mMin24GHzRssi 384 + " currentConnectionBonus " + mCurrentConnectionBonus 385 + " sameNetworkBonus " + mSameNetworkBonus 386 + " secureNetworkBonus " + mSecureBonus 387 + " initialScoreMax " + mInitialScoreMax); 388 389 Log.i(TAG, "ConnectivityScanManager initialized "); 390 } 391 392 /** 393 * Attempt to connect to a network candidate. 394 * 395 * Based on the currently connected network, this menthod determines whether we should 396 * connect or roam to the network candidate recommended by QNS. 397 */ 398 private void connectToNetwork(WifiConfiguration candidate) { 399 ScanResult scanResultCandidate = candidate.getNetworkSelectionStatus().getCandidate(); 400 if (scanResultCandidate == null) { 401 Log.e(TAG, "connectToNetwork: bad candidate - " + candidate 402 + " scanResult: " + scanResultCandidate); 403 return; 404 } 405 406 String targetBssid = scanResultCandidate.BSSID; 407 String targetAssociationId = candidate.SSID + " : " + targetBssid; 408 if (targetBssid != null && targetBssid.equals(mWifiInfo.getBSSID())) { 409 localLog("connectToNetwork: Already connected to" + targetAssociationId); 410 return; 411 } 412 413 WifiConfiguration currentConnectedNetwork = mConfigManager 414 .getWifiConfiguration(mWifiInfo.getNetworkId()); 415 String currentAssociationId = (currentConnectedNetwork == null) ? "Disconnected" : 416 (mWifiInfo.getSSID() + " : " + mWifiInfo.getBSSID()); 417 418 if (currentConnectedNetwork != null 419 && (currentConnectedNetwork.networkId == candidate.networkId 420 || currentConnectedNetwork.isLinked(candidate))) { 421 localLog("connectToNetwork: Roaming from " + currentAssociationId + " to " 422 + targetAssociationId); 423 mStateMachine.autoRoamToNetwork(candidate.networkId, scanResultCandidate); 424 } else { 425 localLog("connectToNetwork: Reconnect from " + currentAssociationId + " to " 426 + targetAssociationId); 427 mStateMachine.autoConnectToNetwork(candidate.networkId, scanResultCandidate.BSSID); 428 } 429 } 430 431 // Helper for selecting the band for connectivity scan 432 private int getScanBand() { 433 int freqBand = mStateMachine.getFrequencyBand(); 434 if (freqBand == WifiManager.WIFI_FREQUENCY_BAND_5GHZ) { 435 return WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS; 436 } else if (freqBand == WifiManager.WIFI_FREQUENCY_BAND_2GHZ) { 437 return WifiScanner.WIFI_BAND_24_GHZ; 438 } else { 439 return WifiScanner.WIFI_BAND_BOTH_WITH_DFS; 440 } 441 } 442 443 // Watchdog timer handler 444 private void watchdogHandler() { 445 localLog("watchdogHandler"); 446 447 // Schedule the next timer and start a single scan if we are in disconnected state. 448 // Otherwise, the watchdog timer will be scheduled when entering disconnected 449 // state. 450 if (mWifiState == WIFI_STATE_DISCONNECTED) { 451 Log.i(TAG, "start a single scan from watchdogHandler"); 452 453 scheduleWatchdogTimer(); 454 startSingleScan(); 455 } 456 } 457 458 // Periodic scan timer handler 459 private void periodicScanTimerHandler() { 460 localLog("periodicScanTimerHandler"); 461 462 // Schedule the next timer and start a single scan if screen is on. 463 if (mScreenOn) { 464 schedulePeriodicScanTimer(); 465 startSingleScan(); 466 } 467 } 468 469 // Start a single scan for watchdog 470 private void startSingleScan() { 471 if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) { 472 return; 473 } 474 475 ScanSettings settings = new ScanSettings(); 476 settings.band = getScanBand(); 477 settings.reportEvents = WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT 478 | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN; 479 settings.numBssidsPerScan = 0; 480 481 //Retrieve the list of hidden networkId's to scan for. 482 Set<Integer> hiddenNetworkIds = mConfigManager.getHiddenConfiguredNetworkIds(); 483 if (hiddenNetworkIds != null && hiddenNetworkIds.size() > 0) { 484 int i = 0; 485 settings.hiddenNetworkIds = new int[hiddenNetworkIds.size()]; 486 for (Integer netId : hiddenNetworkIds) { 487 settings.hiddenNetworkIds[i++] = netId; 488 } 489 } 490 491 // re-enable this when b/27695292 is fixed 492 // mSingleScanListener.clearScanDetails(); 493 // mScanner.startScan(settings, mSingleScanListener, WIFI_WORK_SOURCE); 494 SingleScanListener singleScanListener = new SingleScanListener(); 495 mScanner.startScan(settings, singleScanListener, WIFI_WORK_SOURCE); 496 } 497 498 // Start a periodic scan when screen is on 499 private void startPeriodicScan() { 500 // Due to b/28020168, timer based single scan will be scheduled every 501 // PERIODIC_SCAN_INTERVAL_MS to provide periodic scan. 502 if (mNoBackgroundScan) { 503 startSingleScan(); 504 schedulePeriodicScanTimer(); 505 } else { 506 ScanSettings settings = new ScanSettings(); 507 settings.band = getScanBand(); 508 settings.reportEvents = WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT 509 | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN; 510 settings.numBssidsPerScan = 0; 511 settings.periodInMs = PERIODIC_SCAN_INTERVAL_MS; 512 513 mPeriodicScanListener.clearScanDetails(); 514 mScanner.startBackgroundScan(settings, mPeriodicScanListener, WIFI_WORK_SOURCE); 515 } 516 } 517 518 // Start a DisconnectedPNO scan when screen is off and Wifi is disconnected 519 private void startDisconnectedPnoScan() { 520 // Initialize PNO settings 521 PnoSettings pnoSettings = new PnoSettings(); 522 ArrayList<PnoSettings.PnoNetwork> pnoNetworkList = 523 mConfigManager.retrieveDisconnectedPnoNetworkList(); 524 int listSize = pnoNetworkList.size(); 525 526 if (listSize == 0) { 527 // No saved network 528 localLog("No saved network for starting disconnected PNO."); 529 return; 530 } 531 532 pnoSettings.networkList = new PnoSettings.PnoNetwork[listSize]; 533 pnoSettings.networkList = pnoNetworkList.toArray(pnoSettings.networkList); 534 pnoSettings.min5GHzRssi = mMin5GHzRssi; 535 pnoSettings.min24GHzRssi = mMin24GHzRssi; 536 pnoSettings.initialScoreMax = mInitialScoreMax; 537 pnoSettings.currentConnectionBonus = mCurrentConnectionBonus; 538 pnoSettings.sameNetworkBonus = mSameNetworkBonus; 539 pnoSettings.secureBonus = mSecureBonus; 540 pnoSettings.band5GHzBonus = mBand5GHzBonus; 541 542 // Initialize scan settings 543 ScanSettings scanSettings = new ScanSettings(); 544 scanSettings.band = getScanBand(); 545 scanSettings.reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH; 546 scanSettings.numBssidsPerScan = 0; 547 scanSettings.periodInMs = PNO_SCAN_INTERVAL_MS; 548 // TODO: enable exponential back off scan later to further save energy 549 // scanSettings.maxPeriodInMs = 8 * scanSettings.periodInMs; 550 551 mPnoScanListener.clearScanDetails(); 552 553 mScanner.startDisconnectedPnoScan(scanSettings, pnoSettings, mPnoScanListener); 554 } 555 556 // Start a ConnectedPNO scan when screen is off and Wifi is connected 557 private void startConnectedPnoScan() { 558 // Disable ConnectedPNO for now due to b/28020168 559 if (mNoBackgroundScan) { 560 return; 561 } 562 563 // Initialize PNO settings 564 PnoSettings pnoSettings = new PnoSettings(); 565 ArrayList<PnoSettings.PnoNetwork> pnoNetworkList = 566 mConfigManager.retrieveConnectedPnoNetworkList(); 567 int listSize = pnoNetworkList.size(); 568 569 if (listSize == 0) { 570 // No saved network 571 localLog("No saved network for starting connected PNO."); 572 return; 573 } 574 575 pnoSettings.networkList = new PnoSettings.PnoNetwork[listSize]; 576 pnoSettings.networkList = pnoNetworkList.toArray(pnoSettings.networkList); 577 pnoSettings.min5GHzRssi = mMin5GHzRssi; 578 pnoSettings.min24GHzRssi = mMin24GHzRssi; 579 pnoSettings.initialScoreMax = mInitialScoreMax; 580 pnoSettings.currentConnectionBonus = mCurrentConnectionBonus; 581 pnoSettings.sameNetworkBonus = mSameNetworkBonus; 582 pnoSettings.secureBonus = mSecureBonus; 583 pnoSettings.band5GHzBonus = mBand5GHzBonus; 584 585 // Initialize scan settings 586 ScanSettings scanSettings = new ScanSettings(); 587 scanSettings.band = getScanBand(); 588 scanSettings.reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH; 589 scanSettings.numBssidsPerScan = 0; 590 scanSettings.periodInMs = PNO_SCAN_INTERVAL_MS; 591 // TODO: enable exponential back off scan later to further save energy 592 // scanSettings.maxPeriodInMs = 8 * scanSettings.periodInMs; 593 594 mPnoScanListener.clearScanDetails(); 595 596 mScanner.startConnectedPnoScan(scanSettings, pnoSettings, mPnoScanListener); 597 } 598 599 // Set up watchdog timer 600 private void scheduleWatchdogTimer() { 601 Log.i(TAG, "scheduleWatchdogTimer"); 602 603 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 604 System.currentTimeMillis() + WATCHDOG_INTERVAL_MS, 605 "WifiConnectivityManager Schedule Watchdog Timer", 606 mWatchdogListener, null); 607 } 608 609 // Set up periodic scan timer 610 private void schedulePeriodicScanTimer() { 611 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 612 System.currentTimeMillis() + PERIODIC_SCAN_INTERVAL_MS, 613 "WifiConnectivityManager Schedule Periodic Scan Timer", 614 mPeriodicScanTimerListener, null); 615 } 616 617 // Set up timer to start a delayed single scan after RESTART_SCAN_DELAY_MS 618 private void scheduleDelayedSingleScan() { 619 localLog("scheduleDelayedSingleScan"); 620 621 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 622 System.currentTimeMillis() + RESTART_SCAN_DELAY_MS, 623 "WifiConnectivityManager Restart Single Scan", 624 mRestartSingleScanListener, null); 625 } 626 627 // Set up timer to start a delayed scan after RESTART_SCAN_DELAY_MS 628 private void scheduleDelayedConnectivityScan() { 629 localLog("scheduleDelayedConnectivityScan"); 630 631 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 632 System.currentTimeMillis() + RESTART_SCAN_DELAY_MS, 633 "WifiConnectivityManager Restart Scan", 634 mRestartScanListener, null); 635 636 } 637 638 // Start a connectivity scan. The scan method is chosen according to 639 // the current screen state and WiFi state. 640 private void startConnectivityScan(boolean forceSelectNetwork) { 641 localLog("startConnectivityScan: screenOn=" + mScreenOn 642 + " wifiState=" + mWifiState 643 + " forceSelectNetwork=" + forceSelectNetwork 644 + " wifiEnabled=" + mWifiEnabled 645 + " wifiConnectivityManagerEnabled=" 646 + mWifiConnectivityManagerEnabled); 647 648 if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) { 649 return; 650 } 651 652 // Always stop outstanding connecivity scan if there is any 653 stopConnectivityScan(); 654 655 // Don't start a connectivity scan while Wifi is in the transition 656 // between connected and disconnected states. 657 if (mWifiState != WIFI_STATE_CONNECTED && mWifiState != WIFI_STATE_DISCONNECTED) { 658 return; 659 } 660 661 mForceSelectNetwork = forceSelectNetwork; 662 663 if (mScreenOn) { 664 startPeriodicScan(); 665 } else { // screenOff 666 if (mWifiState == WIFI_STATE_CONNECTED) { 667 startConnectedPnoScan(); 668 } else { 669 startDisconnectedPnoScan(); 670 } 671 } 672 } 673 674 // Stop connectivity scan if there is any. 675 private void stopConnectivityScan() { 676 // Due to b/28020168, timer based single scan will be scheduled every 677 // PERIODIC_SCAN_INTERVAL_MS to provide periodic scan. 678 if (mNoBackgroundScan) { 679 mAlarmManager.cancel(mPeriodicScanTimerListener); 680 } else { 681 mScanner.stopBackgroundScan(mPeriodicScanListener); 682 } 683 mScanner.stopPnoScan(mPnoScanListener); 684 mScanRestartCount = 0; 685 } 686 687 /** 688 * Handler for screen state (on/off) changes 689 */ 690 public void handleScreenStateChanged(boolean screenOn) { 691 localLog("handleScreenStateChanged: screenOn=" + screenOn); 692 693 mScreenOn = screenOn; 694 695 startConnectivityScan(false); 696 } 697 698 /** 699 * Handler for WiFi state (connected/disconnected) changes 700 */ 701 public void handleConnectionStateChanged(int state) { 702 localLog("handleConnectionStateChanged: state=" + state); 703 704 mWifiState = state; 705 706 // Kick off the watchdog timer if entering disconnected state 707 if (mWifiState == WIFI_STATE_DISCONNECTED) { 708 scheduleWatchdogTimer(); 709 } 710 711 startConnectivityScan(false); 712 } 713 714 /** 715 * Handler when user toggles whether untrusted connection is allowed 716 */ 717 public void setUntrustedConnectionAllowed(boolean allowed) { 718 Log.i(TAG, "setUntrustedConnectionAllowed: allowed=" + allowed); 719 720 if (mUntrustedConnectionAllowed != allowed) { 721 mUntrustedConnectionAllowed = allowed; 722 startConnectivityScan(false); 723 } 724 } 725 726 /** 727 * Handler when user specifies a particular network to connect to 728 */ 729 public void connectToUserSelectNetwork(int netId, boolean persistent) { 730 Log.i(TAG, "connectToUserSelectNetwork: netId=" + netId 731 + " persist=" + persistent); 732 733 mQualifiedNetworkSelector.userSelectNetwork(netId, persistent); 734 735 // Initiate a scan which will trigger the connection to the user selected 736 // network when scan result is available. 737 startConnectivityScan(true); 738 } 739 740 /** 741 * Handler for on-demand connectivity scan 742 */ 743 public void forceConnectivityScan() { 744 Log.i(TAG, "forceConnectivityScan"); 745 746 startConnectivityScan(false); 747 } 748 749 /** 750 * Track whether a BSSID should be enabled or disabled for QNS 751 */ 752 public boolean trackBssid(String bssid, boolean enable) { 753 Log.i(TAG, "trackBssid: " + (enable ? "enable " : "disable ") + bssid); 754 755 boolean ret = mQualifiedNetworkSelector 756 .enableBssidForQualityNetworkSelection(bssid, enable); 757 758 if (ret && !enable) { 759 // Disabling a BSSID can happen when the AP candidate to connect to has 760 // no capacity for new stations. We start another scan immediately so that QNS 761 // can give us another candidate to connect to. 762 startConnectivityScan(false); 763 } 764 765 return ret; 766 } 767 768 /** 769 * Set band preference when doing scan and making connection 770 */ 771 public void setUserPreferredBand(int band) { 772 Log.i(TAG, "User band preference: " + band); 773 774 mQualifiedNetworkSelector.setUserPreferredBand(band); 775 startConnectivityScan(false); 776 } 777 778 /** 779 * Inform WiFi is enabled for connection or not 780 */ 781 public void setWifiEnabled(boolean enable) { 782 Log.i(TAG, "Set WiFi " + (enable ? "enabled" : "disabled")); 783 784 mWifiEnabled = enable; 785 786 if (!mWifiEnabled) { 787 stopConnectivityScan(); 788 } 789 } 790 791 /** 792 * Turn on/off the WifiConnectivityMangager at runtime 793 */ 794 public void enable(boolean enable) { 795 Log.i(TAG, "Set WiFiConnectivityManager " + (enable ? "enabled" : "disabled")); 796 797 mWifiConnectivityManagerEnabled = enable; 798 799 if (!mWifiConnectivityManagerEnabled) { 800 stopConnectivityScan(); 801 } 802 } 803 804 /** 805 * Enable/disable verbose logging 806 */ 807 public void enableVerboseLogging(int verbose) { 808 mDbg = verbose > 0; 809 } 810 811 /** 812 * Dump the local log buffer 813 */ 814 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 815 pw.println("Dump of WifiConnectivityManager"); 816 pw.println("WifiConnectivityManager - Log Begin ----"); 817 mLocalLog.dump(fd, pw, args); 818 pw.println("WifiConnectivityManager - Log End ----"); 819 } 820} 821