WifiConnectivityManager.java revision 466158a6669d51541ce6c5c4e04a71dad36cdb4e
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.currentNetworkBoost.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.thresholdSaturatedRssi24.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 // Stop a PNO scan 531 private void stopPnoScan() { 532 // Initialize PNO settings 533 PnoSettings pnoSettings = new PnoSettings(); 534 ArrayList<PnoSettings.PnoNetwork> pnoNetworkList = 535 mConfigManager.retrieveDisconnectedPnoNetworkList(false); 536 int listSize = pnoNetworkList.size(); 537 538 pnoSettings.networkList = new PnoSettings.PnoNetwork[listSize]; 539 pnoSettings.networkList = pnoNetworkList.toArray(pnoSettings.networkList); 540 541 mScanner.stopPnoScan(pnoSettings, mPnoScanListener); 542 } 543 544 // Start a DisconnectedPNO scan when screen is off and Wifi is disconnected 545 private void startDisconnectedPnoScan() { 546 // Initialize PNO settings 547 PnoSettings pnoSettings = new PnoSettings(); 548 ArrayList<PnoSettings.PnoNetwork> pnoNetworkList = 549 mConfigManager.retrieveDisconnectedPnoNetworkList(true); 550 int listSize = pnoNetworkList.size(); 551 552 if (listSize == 0) { 553 // No saved network 554 localLog("No saved network for starting disconnected PNO."); 555 return; 556 } 557 558 pnoSettings.networkList = new PnoSettings.PnoNetwork[listSize]; 559 pnoSettings.networkList = pnoNetworkList.toArray(pnoSettings.networkList); 560 pnoSettings.min5GHzRssi = mMin5GHzRssi; 561 pnoSettings.min24GHzRssi = mMin24GHzRssi; 562 pnoSettings.initialScoreMax = mInitialScoreMax; 563 pnoSettings.currentConnectionBonus = mCurrentConnectionBonus; 564 pnoSettings.sameNetworkBonus = mSameNetworkBonus; 565 pnoSettings.secureBonus = mSecureBonus; 566 pnoSettings.band5GHzBonus = mBand5GHzBonus; 567 568 // Initialize scan settings 569 ScanSettings scanSettings = new ScanSettings(); 570 scanSettings.band = getScanBand(); 571 scanSettings.reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH; 572 scanSettings.numBssidsPerScan = 0; 573 scanSettings.periodInMs = PNO_SCAN_INTERVAL_MS; 574 // TODO: enable exponential back off scan later to further save energy 575 // scanSettings.maxPeriodInMs = 8 * scanSettings.periodInMs; 576 577 mPnoScanListener.clearScanDetails(); 578 579 mScanner.startDisconnectedPnoScan(scanSettings, pnoSettings, mPnoScanListener); 580 } 581 582 // Start a ConnectedPNO scan when screen is off and Wifi is connected 583 private void startConnectedPnoScan() { 584 // Disable ConnectedPNO for now due to b/28020168 585 if (mNoBackgroundScan) { 586 return; 587 } 588 589 // Initialize PNO settings 590 PnoSettings pnoSettings = new PnoSettings(); 591 ArrayList<PnoSettings.PnoNetwork> pnoNetworkList = 592 mConfigManager.retrieveConnectedPnoNetworkList(); 593 int listSize = pnoNetworkList.size(); 594 595 if (listSize == 0) { 596 // No saved network 597 localLog("No saved network for starting connected PNO."); 598 return; 599 } 600 601 pnoSettings.networkList = new PnoSettings.PnoNetwork[listSize]; 602 pnoSettings.networkList = pnoNetworkList.toArray(pnoSettings.networkList); 603 pnoSettings.min5GHzRssi = mMin5GHzRssi; 604 pnoSettings.min24GHzRssi = mMin24GHzRssi; 605 pnoSettings.initialScoreMax = mInitialScoreMax; 606 pnoSettings.currentConnectionBonus = mCurrentConnectionBonus; 607 pnoSettings.sameNetworkBonus = mSameNetworkBonus; 608 pnoSettings.secureBonus = mSecureBonus; 609 pnoSettings.band5GHzBonus = mBand5GHzBonus; 610 611 // Initialize scan settings 612 ScanSettings scanSettings = new ScanSettings(); 613 scanSettings.band = getScanBand(); 614 scanSettings.reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH; 615 scanSettings.numBssidsPerScan = 0; 616 scanSettings.periodInMs = PNO_SCAN_INTERVAL_MS; 617 // TODO: enable exponential back off scan later to further save energy 618 // scanSettings.maxPeriodInMs = 8 * scanSettings.periodInMs; 619 620 mPnoScanListener.clearScanDetails(); 621 622 mScanner.startConnectedPnoScan(scanSettings, pnoSettings, mPnoScanListener); 623 } 624 625 // Set up watchdog timer 626 private void scheduleWatchdogTimer() { 627 Log.i(TAG, "scheduleWatchdogTimer"); 628 629 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 630 System.currentTimeMillis() + WATCHDOG_INTERVAL_MS, 631 "WifiConnectivityManager Schedule Watchdog Timer", 632 mWatchdogListener, null); 633 } 634 635 // Set up periodic scan timer 636 private void schedulePeriodicScanTimer() { 637 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 638 System.currentTimeMillis() + PERIODIC_SCAN_INTERVAL_MS, 639 "WifiConnectivityManager Schedule Periodic Scan Timer", 640 mPeriodicScanTimerListener, null); 641 } 642 643 // Set up timer to start a delayed single scan after RESTART_SCAN_DELAY_MS 644 private void scheduleDelayedSingleScan() { 645 localLog("scheduleDelayedSingleScan"); 646 647 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 648 System.currentTimeMillis() + RESTART_SCAN_DELAY_MS, 649 "WifiConnectivityManager Restart Single Scan", 650 mRestartSingleScanListener, null); 651 } 652 653 // Set up timer to start a delayed scan after RESTART_SCAN_DELAY_MS 654 private void scheduleDelayedConnectivityScan() { 655 localLog("scheduleDelayedConnectivityScan"); 656 657 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 658 System.currentTimeMillis() + RESTART_SCAN_DELAY_MS, 659 "WifiConnectivityManager Restart Scan", 660 mRestartScanListener, null); 661 662 } 663 664 // Start a connectivity scan. The scan method is chosen according to 665 // the current screen state and WiFi state. 666 private void startConnectivityScan(boolean forceSelectNetwork) { 667 localLog("startConnectivityScan: screenOn=" + mScreenOn 668 + " wifiState=" + mWifiState 669 + " forceSelectNetwork=" + forceSelectNetwork 670 + " wifiEnabled=" + mWifiEnabled 671 + " wifiConnectivityManagerEnabled=" 672 + mWifiConnectivityManagerEnabled); 673 674 if (!mWifiEnabled || !mWifiConnectivityManagerEnabled) { 675 return; 676 } 677 678 // Always stop outstanding connecivity scan if there is any 679 stopConnectivityScan(); 680 681 // Don't start a connectivity scan while Wifi is in the transition 682 // between connected and disconnected states. 683 if (mWifiState != WIFI_STATE_CONNECTED && mWifiState != WIFI_STATE_DISCONNECTED) { 684 return; 685 } 686 687 mForceSelectNetwork = forceSelectNetwork; 688 689 if (mScreenOn) { 690 startPeriodicScan(); 691 } else { // screenOff 692 if (mWifiState == WIFI_STATE_CONNECTED) { 693 startConnectedPnoScan(); 694 } else { 695 startDisconnectedPnoScan(); 696 } 697 } 698 } 699 700 // Stop connectivity scan if there is any. 701 private void stopConnectivityScan() { 702 // Due to b/28020168, timer based single scan will be scheduled every 703 // PERIODIC_SCAN_INTERVAL_MS to provide periodic scan. 704 if (mNoBackgroundScan) { 705 mAlarmManager.cancel(mPeriodicScanTimerListener); 706 } else { 707 mScanner.stopBackgroundScan(mPeriodicScanListener); 708 } 709 stopPnoScan(); 710 mScanRestartCount = 0; 711 } 712 713 /** 714 * Handler for screen state (on/off) changes 715 */ 716 public void handleScreenStateChanged(boolean screenOn) { 717 localLog("handleScreenStateChanged: screenOn=" + screenOn); 718 719 mScreenOn = screenOn; 720 721 startConnectivityScan(false); 722 } 723 724 /** 725 * Handler for WiFi state (connected/disconnected) changes 726 */ 727 public void handleConnectionStateChanged(int state) { 728 localLog("handleConnectionStateChanged: state=" + state); 729 730 mWifiState = state; 731 732 // Kick off the watchdog timer if entering disconnected state 733 if (mWifiState == WIFI_STATE_DISCONNECTED) { 734 scheduleWatchdogTimer(); 735 } 736 737 startConnectivityScan(false); 738 } 739 740 /** 741 * Handler when user toggles whether untrusted connection is allowed 742 */ 743 public void setUntrustedConnectionAllowed(boolean allowed) { 744 Log.i(TAG, "setUntrustedConnectionAllowed: allowed=" + allowed); 745 746 if (mUntrustedConnectionAllowed != allowed) { 747 mUntrustedConnectionAllowed = allowed; 748 startConnectivityScan(false); 749 } 750 } 751 752 /** 753 * Handler when user specifies a particular network to connect to 754 */ 755 public void connectToUserSelectNetwork(int netId, boolean persistent) { 756 Log.i(TAG, "connectToUserSelectNetwork: netId=" + netId 757 + " persist=" + persistent); 758 759 mQualifiedNetworkSelector.userSelectNetwork(netId, persistent); 760 761 // Initiate a scan which will trigger the connection to the user selected 762 // network when scan result is available. 763 startConnectivityScan(true); 764 } 765 766 /** 767 * Handler for on-demand connectivity scan 768 */ 769 public void forceConnectivityScan() { 770 Log.i(TAG, "forceConnectivityScan"); 771 772 startConnectivityScan(false); 773 } 774 775 /** 776 * Track whether a BSSID should be enabled or disabled for QNS 777 */ 778 public boolean trackBssid(String bssid, boolean enable) { 779 Log.i(TAG, "trackBssid: " + (enable ? "enable " : "disable ") + bssid); 780 781 boolean ret = mQualifiedNetworkSelector 782 .enableBssidForQualityNetworkSelection(bssid, enable); 783 784 if (ret && !enable) { 785 // Disabling a BSSID can happen when the AP candidate to connect to has 786 // no capacity for new stations. We start another scan immediately so that QNS 787 // can give us another candidate to connect to. 788 startConnectivityScan(false); 789 } 790 791 return ret; 792 } 793 794 /** 795 * Set band preference when doing scan and making connection 796 */ 797 public void setUserPreferredBand(int band) { 798 Log.i(TAG, "User band preference: " + band); 799 800 mQualifiedNetworkSelector.setUserPreferredBand(band); 801 startConnectivityScan(false); 802 } 803 804 /** 805 * Inform WiFi is enabled for connection or not 806 */ 807 public void setWifiEnabled(boolean enable) { 808 Log.i(TAG, "Set WiFi " + (enable ? "enabled" : "disabled")); 809 810 mWifiEnabled = enable; 811 812 if (!mWifiEnabled) { 813 stopConnectivityScan(); 814 } 815 } 816 817 /** 818 * Turn on/off the WifiConnectivityMangager at runtime 819 */ 820 public void enable(boolean enable) { 821 Log.i(TAG, "Set WiFiConnectivityManager " + (enable ? "enabled" : "disabled")); 822 823 mWifiConnectivityManagerEnabled = enable; 824 825 if (!mWifiConnectivityManagerEnabled) { 826 stopConnectivityScan(); 827 } 828 } 829 830 /** 831 * Enable/disable verbose logging 832 */ 833 public void enableVerboseLogging(int verbose) { 834 mDbg = verbose > 0; 835 } 836 837 /** 838 * Dump the local log buffer 839 */ 840 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 841 pw.println("Dump of WifiConnectivityManager"); 842 pw.println("WifiConnectivityManager - Log Begin ----"); 843 mLocalLog.dump(fd, pw, args); 844 pw.println("WifiConnectivityManager - Log End ----"); 845 } 846} 847