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