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