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