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