summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorRandy Pan <zpan@google.com>2016-09-02 15:15:53 -0700
committerRandy Pan <zpan@google.com>2016-09-27 10:58:45 -0700
commitf2a46f11dd92f2820e96b1b8b69b433012d6bcef (patch)
treefd1050f55dd44410678d69cb94b606585577061b /service
parentcf01af187323784ef5f033148928a0344ffe1ece (diff)
Wifi Network Selector
Set up the layout of the new Wifi Network Selector. Add the implementation of Save Network Evaluator and Exernally Scored Network Evaluator. Bug: 31089538 Test: unit tests and manual tests Merged-In: Ieb269060669df220c3d1777eb3aac3b119d4fdc1 Change-Id: Ieb269060669df220c3d1777eb3aac3b119d4fdc1
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/ExternalScoreEvaluator.java369
-rw-r--r--service/java/com/android/server/wifi/SavedNetworkEvaluator.java343
-rw-r--r--service/java/com/android/server/wifi/WifiConnectivityManager.java296
-rw-r--r--service/java/com/android/server/wifi/WifiNetworkSelector.java589
-rw-r--r--service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java1062
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachine.java19
6 files changed, 1392 insertions, 1286 deletions
diff --git a/service/java/com/android/server/wifi/ExternalScoreEvaluator.java b/service/java/com/android/server/wifi/ExternalScoreEvaluator.java
new file mode 100644
index 000000000..03d89b040
--- /dev/null
+++ b/service/java/com/android/server/wifi/ExternalScoreEvaluator.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.net.NetworkKey;
+import android.net.NetworkScoreManager;
+import android.net.WifiKey;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.os.Process;
+import android.util.LocalLog;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.server.wifi.util.ScanResultUtil;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This class is the WifiNetworkSelector.NetworkEvaluator implementation for
+ * externally scored networks.
+ */
+public class ExternalScoreEvaluator implements WifiNetworkSelector.NetworkEvaluator {
+ private static final String NAME = "WifiExternalScoreEvaluator";
+ private static final String TAG = NAME;
+ private final WifiConfigManager mWifiConfigManager;
+ private final Clock mClock;
+ private final LocalLog mLocalLog;
+ private final NetworkScoreManager mScoreManager;
+ private final WifiNetworkScoreCache mScoreCache;
+
+ ExternalScoreEvaluator(Context context, WifiConfigManager configManager, Clock clock,
+ LocalLog localLog) {
+ mWifiConfigManager = configManager;
+ mClock = clock;
+ mLocalLog = localLog;
+ mScoreManager =
+ (NetworkScoreManager) context.getSystemService(Context.NETWORK_SCORE_SERVICE);
+ if (mScoreManager != null) {
+ mScoreCache = new WifiNetworkScoreCache(context);
+ mScoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mScoreCache);
+ } else {
+ Log.e(TAG, "Couldn't get NETWORK_SCORE_SERVICE.");
+ mScoreCache = null;
+ }
+ }
+
+ private void localLog(String log) {
+ if (mLocalLog != null) {
+ mLocalLog.log(log);
+ }
+ }
+
+ /**
+ * Get the evaluator name.
+ */
+ public String getName() {
+ return NAME;
+ }
+
+ private void updateNetworkScoreCache(List<ScanDetail> scanDetails) {
+ ArrayList<NetworkKey> unscoredNetworks = new ArrayList<NetworkKey>();
+
+ for (ScanDetail scanDetail : scanDetails) {
+ ScanResult scanResult = scanDetail.getScanResult();
+
+ // Is there a score for this network? If not, request a score.
+ if (mScoreCache != null && !mScoreCache.isScoredNetwork(scanResult)) {
+ WifiKey wifiKey;
+
+ try {
+ wifiKey = new WifiKey("\"" + scanResult.SSID + "\"", scanResult.BSSID);
+ NetworkKey ntwkKey = new NetworkKey(wifiKey);
+ unscoredNetworks.add(ntwkKey);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Invalid SSID=" + scanResult.SSID + " BSSID=" + scanResult.BSSID
+ + " for network score. Skip.");
+ }
+ }
+ }
+
+ // Kick the score manager if there is any unscored network.
+ if (mScoreManager != null && unscoredNetworks.size() != 0) {
+ NetworkKey[] unscoredNetworkKeys =
+ unscoredNetworks.toArray(new NetworkKey[unscoredNetworks.size()]);
+ mScoreManager.requestScores(unscoredNetworkKeys);
+ }
+ }
+
+ /**
+ * Update the evaluator.
+ */
+ public void update(List<ScanDetail> scanDetails) {
+ updateNetworkScoreCache(scanDetails);
+ }
+
+ private boolean isPotentialEphemeralNetwork(List<WifiConfiguration> associatedConfigurations) {
+ if (associatedConfigurations == null) {
+ return true;
+ } else if (associatedConfigurations.size() == 1) {
+ // If there is more than one associated networks, it must be a passpoint network.
+ // Hence it is not a ephemeral network.
+ WifiConfiguration network = associatedConfigurations.get(0);
+ if (network.ephemeral) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private WifiConfiguration getPotentialEphemeralNetworkConfiguration(
+ List<WifiConfiguration> associatedConfigurations) {
+ if (associatedConfigurations == null) {
+ return null;
+ } else {
+ WifiConfiguration network = associatedConfigurations.get(0);
+ return network;
+ }
+ }
+
+ /**
+ * Returns the available external network score or null if no score is available.
+ *
+ * @param scanResult The scan result of the network to score.
+ * @return A valid external score if one is available or NULL.
+ */
+ @Nullable
+ Integer getNetworkScore(ScanResult scanResult, WifiNetworkScoreCache scoreCache) {
+ if (scoreCache != null && scoreCache.isScoredNetwork(scanResult)) {
+ int score = scoreCache.getNetworkScore(scanResult, false);
+ localLog(WifiNetworkSelector.toScanId(scanResult) + " has score: " + score);
+ return score;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the best candidate network according to the given ExternalScoreEvaluator.
+ */
+ @Nullable
+ WifiConfiguration getExternalScoreCandidate(ExternalScoreTracker scoreTracker,
+ WifiNetworkScoreCache scoreCache) {
+ int candidateNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
+ switch (scoreTracker.getBestCandidateType()) {
+ case ExternalScoreTracker.EXTERNAL_SCORED_UNTRUSTED_NETWORK:
+ ScanResult untrustedScanResultCandidate =
+ scoreTracker.getScanResultCandidate();
+ WifiConfiguration unTrustedNetworkCandidate =
+ ScanResultUtil.createNetworkFromScanResult(untrustedScanResultCandidate);
+
+ // Mark this config as ephemeral so it isn't persisted.
+ unTrustedNetworkCandidate.ephemeral = true;
+ if (scoreCache != null) {
+ unTrustedNetworkCandidate.meteredHint =
+ scoreCache.getMeteredHint(untrustedScanResultCandidate);
+ }
+ NetworkUpdateResult result =
+ mWifiConfigManager.addOrUpdateNetwork(unTrustedNetworkCandidate,
+ Process.WIFI_UID);
+ if (!result.isSuccess()) {
+ Log.e(TAG, "Failed to add ephemeral network");
+ break;
+ }
+ candidateNetworkId = result.getNetworkId();
+ mWifiConfigManager.setNetworkCandidateScanResult(candidateNetworkId,
+ untrustedScanResultCandidate, 0);
+ localLog(String.format("new ephemeral candidate %s network ID:%d, "
+ + "meteredHint=%b",
+ WifiNetworkSelector.toScanId(untrustedScanResultCandidate),
+ candidateNetworkId,
+ unTrustedNetworkCandidate.meteredHint));
+ break;
+
+ case ExternalScoreTracker.EXTERNAL_SCORED_SAVED_NETWORK:
+ ScanResult scanResultCandidate = scoreTracker.getScanResultCandidate();
+ candidateNetworkId = scoreTracker.getSavedConfig().networkId;
+ mWifiConfigManager.setNetworkCandidateScanResult(candidateNetworkId,
+ scanResultCandidate, 0);
+ localLog(String.format("new saved network candidate %s network ID:%d",
+ WifiNetworkSelector.toScanId(scanResultCandidate),
+ candidateNetworkId));
+ break;
+
+ case ExternalScoreTracker.EXTERNAL_SCORED_NONE:
+ localLog("did not see any good candidates.");
+ break;
+
+ default:
+ localLog("Unhandled case. No candidate selected.");
+ break;
+ }
+ return mWifiConfigManager.getConfiguredNetwork(candidateNetworkId);
+ }
+
+ /**
+ * Evaluate all the networks from the scan results and return
+ * the WifiConfiguration of the network chosen for connection.
+ *
+ * @return configuration of the chosen network;
+ * null if no network in this category is available.
+ */
+ public WifiConfiguration evaluateNetworks(List<ScanDetail> scanDetails,
+ WifiConfiguration currentNetwork, String currentBssid, boolean connected,
+ boolean untrustedNetworkAllowed,
+ List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks) {
+ if (mScoreCache == null) {
+ localLog("has no network score cache.");
+ return null;
+ }
+
+ final ExternalScoreTracker externalScoreTracker = new ExternalScoreTracker(mLocalLog);
+ ArrayList<NetworkKey> unscoredNetworks = new ArrayList<>();
+
+ for (ScanDetail scanDetail : scanDetails) {
+ ScanResult scanResult = scanDetail.getScanResult();
+
+ // One ScanResult can be associated with more than one networks, hence we calculate all
+ // the scores and use the highest one as the ScanResult's score.
+ // TODO(b/31065385): WifiConfigManager does not support passpoint networks currently.
+ // So this list has just one entry always.
+ List<WifiConfiguration> associatedConfigs = null;
+ WifiConfiguration associatedConfig =
+ mWifiConfigManager.getSavedNetworkForScanDetailAndCache(scanDetail);
+ if (associatedConfig != null) {
+ associatedConfigs =
+ new ArrayList<>(Arrays.asList(associatedConfig));
+ }
+
+ if (isPotentialEphemeralNetwork(associatedConfigs)) {
+ if (untrustedNetworkAllowed) {
+ if (!mWifiConfigManager.wasEphemeralNetworkDeleted(scanResult.SSID)) {
+ Integer score = getNetworkScore(scanResult, mScoreCache);
+ externalScoreTracker.trackUntrustedCandidate(score, scanResult);
+ if (connectableNetworks != null) {
+ connectableNetworks.add(Pair.create(scanDetail,
+ getPotentialEphemeralNetworkConfiguration(associatedConfigs)));
+ }
+ }
+ }
+ continue;
+ }
+
+ for (WifiConfiguration network : associatedConfigs) {
+ WifiConfiguration.NetworkSelectionStatus status =
+ network.getNetworkSelectionStatus();
+ status.setSeenInLastQualifiedNetworkSelection(true);
+ if (!status.isNetworkEnabled()) {
+ continue;
+ } else if (network.BSSID != null && !network.BSSID.equals("any")
+ && !network.BSSID.equals(scanResult.BSSID)) {
+ // App has specified the only BSSID to connect for this
+ // configuration. So only the matching ScanResult can be a candidate.
+ localLog("Network " + WifiNetworkSelector.toNetworkString(network)
+ + " has specified BSSID " + network.BSSID + ". Skip "
+ + scanResult.BSSID);
+ continue;
+ }
+
+ // Saved network wth an external score.
+ if (network.useExternalScores) {
+ localLog("Network " + WifiNetworkSelector.toNetworkString(network)
+ + " uses external score");
+ Integer score = getNetworkScore(scanResult, mScoreCache);
+ externalScoreTracker.trackSavedCandidate(score, network, scanResult);
+ if (connectableNetworks != null) {
+ connectableNetworks.add(Pair.create(scanDetail, network));
+ }
+ }
+ }
+ }
+
+ WifiConfiguration candidate = getExternalScoreCandidate(externalScoreTracker, mScoreCache);
+
+ if (candidate != null
+ && candidate.getNetworkSelectionStatus().getCandidate() != null) {
+ return candidate;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Used to track the network with the highest score.
+ */
+ static class ExternalScoreTracker {
+ public static final int EXTERNAL_SCORED_NONE = 0;
+ public static final int EXTERNAL_SCORED_SAVED_NETWORK = 1;
+ public static final int EXTERNAL_SCORED_UNTRUSTED_NETWORK = 2;
+
+ private int mBestCandidateType = EXTERNAL_SCORED_NONE;
+ private int mHighScore = WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
+ private WifiConfiguration mSavedConfig;
+ private ScanResult mScanResultCandidate;
+ private final LocalLog mLocalLog;
+
+ ExternalScoreTracker(LocalLog localLog) {
+ mLocalLog = localLog;
+ }
+
+ // Determines whether or not the given scan result is the best one its seen so far.
+ void trackUntrustedCandidate(@Nullable Integer score, ScanResult scanResult) {
+ if (score != null && score > mHighScore) {
+ mHighScore = score;
+ mScanResultCandidate = scanResult;
+ mBestCandidateType = EXTERNAL_SCORED_UNTRUSTED_NETWORK;
+ localLog(WifiNetworkSelector.toScanId(scanResult)
+ + " becomes the new untrusted candidate.");
+ }
+ }
+
+ // Determines whether or not the given saved network is the best one its seen so far.
+ void trackSavedCandidate(@Nullable Integer score, WifiConfiguration config,
+ ScanResult scanResult) {
+ // Always take the highest score. If there's a tie and an untrusted network is currently
+ // the best then pick the saved network.
+ if (score != null
+ && (score > mHighScore
+ || (mBestCandidateType == EXTERNAL_SCORED_UNTRUSTED_NETWORK
+ && score == mHighScore))) {
+ mHighScore = score;
+ mSavedConfig = config;
+ mScanResultCandidate = scanResult;
+ mBestCandidateType = EXTERNAL_SCORED_SAVED_NETWORK;
+ localLog(WifiNetworkSelector.toScanId(scanResult)
+ + " becomes the new externally scored saved network candidate.");
+ }
+ }
+
+ int getBestCandidateType() {
+ return mBestCandidateType;
+ }
+
+ int getHighScore() {
+ return mHighScore;
+ }
+
+ public ScanResult getScanResultCandidate() {
+ return mScanResultCandidate;
+ }
+
+ WifiConfiguration getSavedConfig() {
+ return mSavedConfig;
+ }
+
+ private void localLog(String log) {
+ if (mLocalLog != null) {
+ mLocalLog.log(log);
+ }
+ }
+ }
+}
diff --git a/service/java/com/android/server/wifi/SavedNetworkEvaluator.java b/service/java/com/android/server/wifi/SavedNetworkEvaluator.java
new file mode 100644
index 000000000..afd9b583c
--- /dev/null
+++ b/service/java/com/android/server/wifi/SavedNetworkEvaluator.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import android.content.Context;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.util.LocalLog;
+import android.util.Pair;
+
+import com.android.internal.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This class is the WifiNetworkSelector.NetworkEvaluator implementation for
+ * saved networks.
+ */
+public class SavedNetworkEvaluator implements WifiNetworkSelector.NetworkEvaluator {
+ private static final String NAME = "WifiSavedNetworkEvaluator";
+ private final WifiConfigManager mWifiConfigManager;
+ private final Clock mClock;
+ private final LocalLog mLocalLog;
+ private final int mRssiScoreSlope;
+ private final int mRssiScoreOffset;
+ private final int mSameBssidAward;
+ private final int mSameNetworkAward;
+ private final int mBand5GHzAward;
+ private final int mLastSelectionAward;
+ private final int mPasspointSecurityAward;
+ private final int mSecurityAward;
+ private final int mNoInternetPenalty;
+ private final int mThresholdSaturatedRssi24;
+
+ SavedNetworkEvaluator(Context context, WifiConfigManager configManager,
+ Clock clock, LocalLog localLog) {
+ mWifiConfigManager = configManager;
+ mClock = clock;
+ mLocalLog = localLog;
+
+ mRssiScoreSlope = context.getResources().getInteger(
+ R.integer.config_wifi_framework_RSSI_SCORE_SLOPE);
+ mRssiScoreOffset = context.getResources().getInteger(
+ R.integer.config_wifi_framework_RSSI_SCORE_OFFSET);
+ mSameBssidAward = context.getResources().getInteger(
+ R.integer.config_wifi_framework_SAME_BSSID_AWARD);
+ mSameNetworkAward = context.getResources().getInteger(
+ R.integer.config_wifi_framework_current_network_boost);
+ mLastSelectionAward = context.getResources().getInteger(
+ R.integer.config_wifi_framework_LAST_SELECTION_AWARD);
+ mPasspointSecurityAward = context.getResources().getInteger(
+ R.integer.config_wifi_framework_PASSPOINT_SECURITY_AWARD);
+ mSecurityAward = context.getResources().getInteger(
+ R.integer.config_wifi_framework_SECURITY_AWARD);
+ mBand5GHzAward = context.getResources().getInteger(
+ R.integer.config_wifi_framework_5GHz_preference_boost_factor);
+ mThresholdSaturatedRssi24 = context.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz);
+ mNoInternetPenalty = (mThresholdSaturatedRssi24 + mRssiScoreOffset)
+ * mRssiScoreSlope + mBand5GHzAward + mSameNetworkAward
+ + mSameBssidAward + mSecurityAward;
+ }
+
+ private void localLog(String log) {
+ if (mLocalLog != null) {
+ mLocalLog.log(log);
+ }
+ }
+
+ /**
+ * Get the evaluator name.
+ */
+ public String getName() {
+ return NAME;
+ }
+
+ /**
+ * Update all the saved networks' selection status
+ */
+ private void updateSavedNetworkSelectionStatus() {
+ List<WifiConfiguration> savedNetworks = mWifiConfigManager.getSavedNetworks();
+ if (savedNetworks.size() == 0) {
+ localLog("No saved networks.");
+ return;
+ }
+
+ StringBuffer sbuf = new StringBuffer("Saved Networks List: \n");
+ for (WifiConfiguration network : savedNetworks) {
+ WifiConfiguration.NetworkSelectionStatus status =
+ network.getNetworkSelectionStatus();
+
+ // If a configuration is temporarily disabled, re-enable it before trying
+ // to connect to it.
+ mWifiConfigManager.tryEnableNetwork(network.networkId);
+
+ //TODO(b/30928589): Enable "permanently" disabled networks if we are in DISCONNECTED
+ // state.
+
+ // Clear the cached candidate, score and seen.
+ mWifiConfigManager.clearNetworkCandidateScanResult(network.networkId);
+
+ sbuf.append(" ").append(WifiNetworkSelector.toNetworkString(network)).append(" ")
+ .append(" User Preferred BSSID: ").append(network.BSSID)
+ .append(" FQDN: ").append(network.FQDN).append(" ")
+ .append(status.getNetworkStatusString()).append(" Disable account: ");
+ for (int index = WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
+ index < WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX;
+ index++) {
+ sbuf.append(status.getDisableReasonCounter(index)).append(" ");
+ }
+ sbuf.append("Connect Choice: ").append(status.getConnectChoice())
+ .append(" set time: ").append(status.getConnectChoiceTimestamp())
+ .append("\n");
+ }
+ localLog(sbuf.toString());
+ }
+
+ /**
+ * Update the evaluator.
+ */
+ public void update(List<ScanDetail> scanDetails) {
+ updateSavedNetworkSelectionStatus();
+ }
+
+ private int calculateBssidScore(ScanResult scanResult, WifiConfiguration network,
+ WifiConfiguration currentNetwork, String currentBssid,
+ StringBuffer sbuf) {
+ int score = 0;
+
+ sbuf.append("[ ").append(scanResult).append("] ");
+ // Calculate the RSSI score.
+ int rssi = scanResult.level <= mThresholdSaturatedRssi24
+ ? scanResult.level : mThresholdSaturatedRssi24;
+ score += (rssi + mRssiScoreOffset) * mRssiScoreSlope;
+ sbuf.append(" RSSI score: ").append(score).append(",");
+
+ // 5GHz band bonus.
+ if (scanResult.is5GHz()) {
+ score += mBand5GHzAward;
+ sbuf.append(" 5GHz bonus: ").append(mBand5GHzAward)
+ .append(",");
+ }
+
+ // Last user selection award.
+ int lastUserSelectedNetworkId = mWifiConfigManager.getLastSelectedNetwork();
+ WifiConfiguration lastUserSelectedNetwork =
+ mWifiConfigManager.getConfiguredNetwork(lastUserSelectedNetworkId);
+ if (lastUserSelectedNetwork != null && lastUserSelectedNetworkId == network.networkId) {
+ long timeDifference = mClock.getElapsedSinceBootMillis()
+ - mWifiConfigManager.getLastSelectedTimeStamp();
+ if (timeDifference > 0) {
+ int bonus = mLastSelectionAward - (int) (timeDifference / 1000 / 60);
+ score += bonus > 0 ? bonus : 0;
+ sbuf.append(" User selected it last time ").append(timeDifference / 1000 / 60)
+ .append(" minutes ago, bonus: ").append(bonus).append(",");
+ }
+ }
+
+ // Same network award.
+ if (currentNetwork != null
+ && (network == currentNetwork || network.isLinked(currentNetwork))) {
+ score += mSameNetworkAward;
+ sbuf.append(" Same network bonus as the current one bonus: ")
+ .append(mSameNetworkAward).append(",");
+ }
+
+ // Same BSSID award.
+ if (currentBssid != null && currentBssid.equals(scanResult.BSSID)) {
+ score += mSameBssidAward;
+ sbuf.append(" Same BSSID as the current one bonus: ").append(mSameBssidAward)
+ .append(",");
+ }
+
+ // Security award.
+ if (network.isPasspoint()) {
+ score += mPasspointSecurityAward;
+ sbuf.append(" Passpoint bonus: ").append(mPasspointSecurityAward).append(",");
+ } else if (!WifiConfigurationUtil.isConfigForOpenNetwork(network)) {
+ score += mSecurityAward;
+ sbuf.append(" Secure network bonus: ").append(mSecurityAward).append(",");
+ }
+
+ // No internet penalty.
+ if (network.numNoInternetAccessReports > 0 && !network.validatedInternetAccess) {
+ score -= mNoInternetPenalty;
+ sbuf.append(" No internet penalty: -").append(mNoInternetPenalty).append(",");
+ }
+
+ sbuf.append(" ## Total score: ").append(score).append("\n");
+
+ return score;
+ }
+
+ private WifiConfiguration adjustCandidateWithUserSelection(WifiConfiguration candidate,
+ ScanResult scanResultCandidate) {
+ WifiConfiguration tempConfig = candidate;
+
+ while (tempConfig.getNetworkSelectionStatus().getConnectChoice() != null) {
+ String key = tempConfig.getNetworkSelectionStatus().getConnectChoice();
+ tempConfig = mWifiConfigManager.getConfiguredNetwork(key);
+
+ if (tempConfig != null) {
+ WifiConfiguration.NetworkSelectionStatus tempStatus =
+ tempConfig.getNetworkSelectionStatus();
+ if (tempStatus.getCandidate() != null && tempStatus.isNetworkEnabled()) {
+ scanResultCandidate = tempStatus.getCandidate();
+ candidate = tempConfig;
+ }
+ } else {
+ localLog("Connect choice: " + key + " has no corresponding saved config.");
+ break;
+ }
+ }
+ localLog("After user selection adjustment, the final candidate is:"
+ + WifiNetworkSelector.toNetworkString(candidate) + " : "
+ + scanResultCandidate.BSSID);
+ return candidate;
+ }
+
+ /**
+ * Evaluate all the networks from the scan results and return
+ * the WifiConfiguration of the network chosen for connection.
+ *
+ * @return configuration of the chosen network;
+ * null if no network in this category is available.
+ */
+ public WifiConfiguration evaluateNetworks(List<ScanDetail> scanDetails,
+ WifiConfiguration currentNetwork, String currentBssid, boolean connected,
+ boolean untrustedNetworkAllowed,
+ List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks) {
+ int highestScore = Integer.MIN_VALUE;
+ ScanResult scanResultCandidate = null;
+ WifiConfiguration candidate = null;
+ StringBuffer scoreHistory = new StringBuffer();
+
+ for (ScanDetail scanDetail : scanDetails) {
+ ScanResult scanResult = scanDetail.getScanResult();
+ int highestScoreOfScanResult = Integer.MIN_VALUE;
+ int score;
+ int candidateIdOfScanResult = WifiConfiguration.INVALID_NETWORK_ID;
+
+ // One ScanResult can be associated with more than one networks, hence we calculate all
+ // the scores and use the highest one as the ScanResult's score.
+ // TODO(b/31065385): WifiConfigManager does not support passpoint networks currently.
+ // So this list has just one entry always.
+ List<WifiConfiguration> associatedConfigurations = null;
+ WifiConfiguration associatedConfiguration =
+ mWifiConfigManager.getSavedNetworkForScanDetailAndCache(scanDetail);
+
+ if (associatedConfiguration == null) {
+ continue;
+ } else {
+ associatedConfigurations =
+ new ArrayList<>(Arrays.asList(associatedConfiguration));
+ }
+
+ for (WifiConfiguration network : associatedConfigurations) {
+ WifiConfiguration.NetworkSelectionStatus status =
+ network.getNetworkSelectionStatus();
+ status.setSeenInLastQualifiedNetworkSelection(true);
+
+ if (!status.isNetworkEnabled()) {
+ continue;
+ } else if (network.BSSID != null && !network.BSSID.equals("any")
+ && !network.BSSID.equals(scanResult.BSSID)) {
+ // App has specified the only BSSID to connect for this
+ // configuration. So only the matching ScanResult can be a candidate.
+ localLog("Network " + WifiNetworkSelector.toNetworkString(network)
+ + " has specified BSSID " + network.BSSID + ". Skip "
+ + scanResult.BSSID);
+ continue;
+ }
+
+ // If the network is marked to use external scores, leave it to the
+ // external score evaluator to handle it.
+ if (network.useExternalScores) {
+ localLog("Network " + WifiNetworkSelector.toNetworkString(network)
+ + " has external score.");
+ continue;
+ }
+
+ score = calculateBssidScore(scanResult, network, currentNetwork, currentBssid,
+ scoreHistory);
+
+ if (score > highestScoreOfScanResult) {
+ highestScoreOfScanResult = score;
+ candidateIdOfScanResult = network.networkId;
+ }
+
+ if (score > status.getCandidateScore() || (score == status.getCandidateScore()
+ && status.getCandidate() != null
+ && scanResult.level > status.getCandidate().level)) {
+ mWifiConfigManager.setNetworkCandidateScanResult(
+ candidateIdOfScanResult, scanResult, score);
+ }
+ }
+
+ if (connectableNetworks != null) {
+ connectableNetworks.add(Pair.create(scanDetail,
+ mWifiConfigManager.getConfiguredNetwork(candidateIdOfScanResult)));
+ }
+
+ if (highestScoreOfScanResult > highestScore
+ || (highestScoreOfScanResult == highestScore
+ && scanResultCandidate != null
+ && scanResult.level > scanResultCandidate.level)) {
+ highestScore = highestScoreOfScanResult;
+ scanResultCandidate = scanResult;
+ mWifiConfigManager.setNetworkCandidateScanResult(
+ candidateIdOfScanResult, scanResultCandidate, highestScore);
+ // Reload the network config with the updated info.
+ candidate = mWifiConfigManager.getConfiguredNetwork(candidateIdOfScanResult);
+ }
+ }
+
+ if (scoreHistory.length() > 0) {
+ localLog("\n" + scoreHistory.toString());
+ }
+
+ if (scanResultCandidate != null) {
+ return adjustCandidateWithUserSelection(candidate, scanResultCandidate);
+ } else {
+ localLog("did not see any good candidates.");
+ return null;
+ }
+ }
+}
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index d570f81ec..3c2971210 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -18,7 +18,6 @@ package com.android.server.wifi;
import static com.android.server.wifi.WifiStateMachine.WIFI_WORK_SOURCE;
-import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.Context;
import android.net.wifi.ScanResult;
@@ -37,8 +36,6 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wifi.util.ScanResultUtil;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
@@ -50,7 +47,8 @@ import java.util.Set;
*
* When the screen is turned on or off, WiFi is connected or disconnected,
* or on-demand, a scan is initiatiated and the scan results are passed
- * to QNS for it to make a recommendation on which network to connect to.
+ * to WifiNetworkSelector for it to make a recommendation on which network
+ * to connect to.
*/
public class WifiConnectivityManager {
public static final String WATCHDOG_TIMER_TAG =
@@ -83,8 +81,8 @@ public class WifiConnectivityManager {
// PNO scan interval in milli-seconds. This is the scan
// performed when screen is off and connected.
private static final int CONNECTED_PNO_SCAN_INTERVAL_MS = 160 * 1000; // 160 seconds
- // When a network is found by PNO scan but gets rejected by QNS due to its
- // low RSSI value, scan will be reschduled in an exponential back off manner.
+ // When a network is found by PNO scan but gets rejected by Wifi Network Selector due
+ // to its low RSSI value, scan will be reschduled in an exponential back off manner.
private static final int LOW_RSSI_NETWORK_RETRY_START_DELAY_MS = 20 * 1000; // 20 seconds
private static final int LOW_RSSI_NETWORK_RETRY_MAX_DELAY_MS = 80 * 1000; // 80 seconds
// Maximum number of retries when starting a scan failed
@@ -118,24 +116,21 @@ public class WifiConnectivityManager {
public static final int WIFI_STATE_DISCONNECTED = 2;
public static final int WIFI_STATE_TRANSITIONING = 3;
- // Due to b/28020168, timer based single scan will be scheduled
- // to provide periodic scan in an exponential backoff fashion.
- private static final boolean ENABLE_BACKGROUND_SCAN = false;
- // Flag to turn on connected PNO, when needed
- private static final boolean ENABLE_CONNECTED_PNO_SCAN = false;
+ // Saved network evaluator priority
+ private static final int SAVED_NETWORK_EVALUATOR_PRIORITY = 1;
+ private static final int EXTERNAL_SCORE_EVALUATOR_PRIORITY = 2;
private final WifiStateMachine mStateMachine;
private final WifiScanner mScanner;
private final WifiConfigManager mConfigManager;
private final WifiInfo mWifiInfo;
- private final WifiQualifiedNetworkSelector mQualifiedNetworkSelector;
+ private final WifiNetworkSelector mNetworkSelector;
private final WifiLastResortWatchdog mWifiLastResortWatchdog;
private final WifiMetrics mWifiMetrics;
private final AlarmManager mAlarmManager;
private final Handler mEventHandler;
private final Clock mClock;
- private final LocalLog mLocalLog =
- new LocalLog(ActivityManager.isLowRamDeviceStatic() ? 128 : 256);
+ private final LocalLog mLocalLog;
private final LinkedList<Long> mConnectionAttemptTimeStamps;
private boolean mDbg = false;
@@ -166,7 +161,9 @@ public class WifiConnectivityManager {
// A helper to log debugging information in the local log buffer, which can
// be retrieved in bugreport.
private void localLog(String log) {
- mLocalLog.log(log);
+ if (mLocalLog != null) {
+ mLocalLog.log(log);
+ }
}
// A periodic/PNO scan will be rescheduled up to MAX_SCAN_RESTART_ALLOWED times
@@ -216,21 +213,28 @@ public class WifiConnectivityManager {
* Executes selection of potential network candidates, initiation of connection attempt to that
* network.
*
- * @return true - if a candidate is selected by QNS
- * false - if no candidate is selected by QNS
+ * @return true - if a candidate is selected by WifiNetworkSelector
+ * false - if no candidate is selected by WifiNetworkSelector
*/
private boolean handleScanResults(List<ScanDetail> scanDetails, String listenerName) {
- localLog(listenerName + " onResults: start QNS");
+ if (mStateMachine.isLinkDebouncing() || mStateMachine.isSupplicantTransientState()) {
+ localLog(listenerName + " onResults: No network selection because linkDebouncing is "
+ + mStateMachine.isLinkDebouncing() + " and supplicantTransient is "
+ + mStateMachine.isSupplicantTransientState());
+ return false;
+ }
+
+ localLog(listenerName + " onResults: start network selection");
+
WifiConfiguration candidate =
- mQualifiedNetworkSelector.selectQualifiedNetwork(false,
- mUntrustedConnectionAllowed, mStateMachine.isLinkDebouncing(),
+ mNetworkSelector.selectNetwork(scanDetails,
mStateMachine.isConnected(), mStateMachine.isDisconnected(),
- mStateMachine.isSupplicantTransientState(), scanDetails);
+ mUntrustedConnectionAllowed);
mWifiLastResortWatchdog.updateAvailableNetworks(
- mQualifiedNetworkSelector.getFilteredScanDetails());
+ mNetworkSelector.getFilteredScanDetails());
mWifiMetrics.countScanResults(scanDetails);
if (candidate != null) {
- localLog(listenerName + ": QNS candidate-" + candidate.SSID);
+ localLog(listenerName + ": WNS candidate-" + candidate.SSID);
connectToNetwork(candidate);
return true;
} else {
@@ -238,63 +242,6 @@ public class WifiConnectivityManager {
}
}
- // Periodic scan results listener. A periodic scan is initiated when
- // screen is on.
- private class PeriodicScanListener implements WifiScanner.ScanListener {
- private List<ScanDetail> mScanDetails = new ArrayList<ScanDetail>();
-
- public void clearScanDetails() {
- mScanDetails.clear();
- }
-
- @Override
- public void onSuccess() {
- localLog("PeriodicScanListener onSuccess");
- }
-
- @Override
- public void onFailure(int reason, String description) {
- Log.e(TAG, "PeriodicScanListener onFailure:"
- + " reason: " + reason
- + " description: " + description);
-
- // reschedule the scan
- if (mScanRestartCount++ < MAX_SCAN_RESTART_ALLOWED) {
- scheduleDelayedConnectivityScan(RESTART_SCAN_DELAY_MS);
- } else {
- mScanRestartCount = 0;
- Log.e(TAG, "Failed to successfully start periodic scan for "
- + MAX_SCAN_RESTART_ALLOWED + " times");
- }
- }
-
- @Override
- public void onPeriodChanged(int periodInMs) {
- localLog("PeriodicScanListener onPeriodChanged: "
- + "actual scan period " + periodInMs + "ms");
- }
-
- @Override
- public void onResults(WifiScanner.ScanData[] results) {
- handleScanResults(mScanDetails, "PeriodicScanListener");
- clearScanDetails();
- mScanRestartCount = 0;
- }
-
- @Override
- public void onFullResult(ScanResult fullScanResult) {
- if (mDbg) {
- localLog("PeriodicScanListener onFullResult: "
- + fullScanResult.SSID + " capabilities "
- + fullScanResult.capabilities);
- }
-
- mScanDetails.add(ScanResultUtil.toScanDetail(fullScanResult));
- }
- }
-
- private final PeriodicScanListener mPeriodicScanListener = new PeriodicScanListener();
-
// All single scan results listener.
//
// Note: This is the listener for all the available single scan results,
@@ -365,7 +312,7 @@ public class WifiConnectivityManager {
private final AllSingleScanListener mAllSingleScanListener = new AllSingleScanListener();
// Single scan results listener. A single scan is initiated when
- // Disconnected/ConnectedPNO scan found a valid network and woke up
+ // DisconnectedPNO scan found a valid network and woke up
// the system, or by the watchdog timer, or to form the timer based
// periodic scan.
//
@@ -414,9 +361,6 @@ public class WifiConnectivityManager {
}
}
- // re-enable this when b/27695292 is fixed
- // private final SingleScanListener mSingleScanListener = new SingleScanListener();
-
// PNO scan results listener for both disconected and connected PNO scanning.
// A PNO scan is initiated when screen is off.
private class PnoScanListener implements WifiScanner.PnoScanListener {
@@ -429,7 +373,7 @@ public class WifiConnectivityManager {
}
// Reset to the start value when either a non-PNO scan is started or
- // QNS selects a candidate from the PNO scan results.
+ // WifiNetworkSelector selects a candidate from the PNO scan results.
public void resetLowRssiNetworkRetryDelay() {
mLowRssiNetworkRetryDelay = LOW_RSSI_NETWORK_RETRY_START_DELAY_MS;
}
@@ -467,7 +411,7 @@ public class WifiConnectivityManager {
}
// Currently the PNO scan results doesn't include IE,
- // which contains information required by QNS. Ignore them
+ // which contains information required by WifiNetworkSelector. Ignore them
// for now.
@Override
public void onResults(WifiScanner.ScanData[] results) {
@@ -491,7 +435,7 @@ public class WifiConnectivityManager {
mScanRestartCount = 0;
if (!wasConnectAttempted) {
- // The scan results were rejected by QNS due to low RSSI values
+ // The scan results were rejected by WifiNetworkSelector due to low RSSI values
if (mLowRssiNetworkRetryDelay > LOW_RSSI_NETWORK_RETRY_MAX_DELAY_MS) {
mLowRssiNetworkRetryDelay = LOW_RSSI_NETWORK_RETRY_MAX_DELAY_MS;
}
@@ -510,15 +454,16 @@ public class WifiConnectivityManager {
/**
* WifiConnectivityManager constructor
*/
- public WifiConnectivityManager(Context context, WifiStateMachine stateMachine,
+ WifiConnectivityManager(Context context, WifiStateMachine stateMachine,
WifiScanner scanner, WifiConfigManager configManager, WifiInfo wifiInfo,
- WifiQualifiedNetworkSelector qualifiedNetworkSelector,
- WifiInjector wifiInjector, Looper looper, boolean enable) {
+ WifiNetworkSelector networkSelector, WifiInjector wifiInjector, Looper looper,
+ boolean enable) {
mStateMachine = stateMachine;
mScanner = scanner;
mConfigManager = configManager;
mWifiInfo = wifiInfo;
- mQualifiedNetworkSelector = qualifiedNetworkSelector;
+ mNetworkSelector = networkSelector;
+ mLocalLog = networkSelector.getLocalLog();
mWifiLastResortWatchdog = wifiInjector.getWifiLastResortWatchdog();
mWifiMetrics = wifiInjector.getWifiMetrics();
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
@@ -526,10 +471,12 @@ public class WifiConnectivityManager {
mClock = wifiInjector.getClock();
mConnectionAttemptTimeStamps = new LinkedList<>();
- mMin5GHzRssi = WifiQualifiedNetworkSelector.MINIMUM_5G_ACCEPT_RSSI;
- mMin24GHzRssi = WifiQualifiedNetworkSelector.MINIMUM_2G_ACCEPT_RSSI;
- mBand5GHzBonus = WifiQualifiedNetworkSelector.BAND_AWARD_5GHz;
-
+ mMin5GHzRssi = context.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
+ mMin24GHzRssi = context.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
+ mBand5GHzBonus = context.getResources().getInteger(
+ R.integer.config_wifi_framework_5GHz_preference_boost_factor);
mCurrentConnectionBonus = context.getResources().getInteger(
R.integer.config_wifi_framework_current_network_boost);
mSameNetworkBonus = context.getResources().getInteger(
@@ -538,11 +485,14 @@ public class WifiConnectivityManager {
R.integer.config_wifi_framework_SECURITY_AWARD);
int thresholdSaturatedRssi24 = context.getResources().getInteger(
R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz);
- mInitialScoreMax =
- (thresholdSaturatedRssi24 + WifiQualifiedNetworkSelector.RSSI_SCORE_OFFSET)
- * WifiQualifiedNetworkSelector.RSSI_SCORE_SLOPE;
mEnableAutoJoinWhenAssociated = context.getResources().getBoolean(
R.bool.config_wifi_framework_enable_associated_network_selection);
+ mInitialScoreMax = (context.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz)
+ + context.getResources().getInteger(
+ R.integer.config_wifi_framework_RSSI_SCORE_OFFSET))
+ * context.getResources().getInteger(
+ R.integer.config_wifi_framework_RSSI_SCORE_SLOPE);
Log.i(TAG, "PNO settings:" + " min5GHzRssi " + mMin5GHzRssi
+ " min24GHzRssi " + mMin24GHzRssi
@@ -551,6 +501,17 @@ public class WifiConnectivityManager {
+ " secureNetworkBonus " + mSecureBonus
+ " initialScoreMax " + mInitialScoreMax);
+ // Register the network evaluators
+ SavedNetworkEvaluator savedNetworkEvaluator = new SavedNetworkEvaluator(context,
+ mConfigManager, mClock, mLocalLog);
+ mNetworkSelector.registerNetworkEvaluator(savedNetworkEvaluator,
+ SAVED_NETWORK_EVALUATOR_PRIORITY);
+
+ ExternalScoreEvaluator externalScoreEvaluator = new ExternalScoreEvaluator(context,
+ mConfigManager, mClock, mLocalLog);
+ mNetworkSelector.registerNetworkEvaluator(externalScoreEvaluator,
+ EXTERNAL_SCORE_EVALUATOR_PRIORITY);
+
// Register for all single scan results
mScanner.registerScanListener(mAllSingleScanListener);
@@ -601,7 +562,7 @@ public class WifiConnectivityManager {
* Attempt to connect to a network candidate.
*
* Based on the currently connected network, this menthod determines whether we should
- * connect or roam to the network candidate recommended by QNS.
+ * connect or roam to the network candidate recommended by WifiNetworkSelector.
*/
private void connectToNetwork(WifiConfiguration candidate) {
ScanResult scanResultCandidate = candidate.getNetworkSelectionStatus().getCandidate();
@@ -616,8 +577,8 @@ public class WifiConnectivityManager {
// Check if we are already connected or in the process of connecting to the target
// BSSID. mWifiInfo.mBSSID tracks the currently connected BSSID. This is checked just
- // in case the firmware automatically roamed to a BSSID different from what QNS
- // selected.
+ // in case the firmware automatically roamed to a BSSID different from what
+ // WifiNetworkSelector selected.
if (targetBssid != null
&& (targetBssid.equals(mLastConnectionAttemptBssid)
|| targetBssid.equals(mWifiInfo.getBSSID()))
@@ -703,7 +664,7 @@ public class WifiConnectivityManager {
// Otherwise, the watchdog timer will be scheduled when entering disconnected
// state.
if (mWifiState == WIFI_STATE_DISCONNECTED) {
- Log.i(TAG, "start a single scan from watchdogHandler");
+ localLog("start a single scan from watchdogHandler");
scheduleWatchdogTimer();
startSingleScan(true);
@@ -787,9 +748,6 @@ public class WifiConnectivityManager {
settings.hiddenNetworks =
hiddenNetworkList.toArray(new ScanSettings.HiddenNetwork[hiddenNetworkList.size()]);
- // re-enable this when b/27695292 is fixed
- // mSingleScanListener.clearScanDetails();
- // mScanner.startScan(settings, mSingleScanListener, WIFI_WORK_SOURCE);
SingleScanListener singleScanListener =
new SingleScanListener(isFullBandScan);
mScanner.startScan(settings, singleScanListener, WIFI_WORK_SOURCE);
@@ -806,23 +764,11 @@ public class WifiConnectivityManager {
// Due to b/28020168, timer based single scan will be scheduled
// to provide periodic scan in an exponential backoff fashion.
- if (!ENABLE_BACKGROUND_SCAN) {
- if (scanImmediately) {
- resetLastPeriodicSingleScanTimeStamp();
- }
- mPeriodicSingleScanInterval = PERIODIC_SCAN_INTERVAL_MS;
- startPeriodicSingleScan();
- } else {
- ScanSettings settings = new ScanSettings();
- settings.band = getScanBand();
- settings.reportEvents = WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT
- | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
- settings.numBssidsPerScan = 0;
- settings.periodInMs = PERIODIC_SCAN_INTERVAL_MS;
-
- mPeriodicScanListener.clearScanDetails();
- mScanner.startBackgroundScan(settings, mPeriodicScanListener, WIFI_WORK_SOURCE);
+ if (scanImmediately) {
+ resetLastPeriodicSingleScanTimeStamp();
}
+ mPeriodicSingleScanInterval = PERIODIC_SCAN_INTERVAL_MS;
+ startPeriodicSingleScan();
}
// Start a DisconnectedPNO scan when screen is off and Wifi is disconnected
@@ -856,8 +802,6 @@ public class WifiConnectivityManager {
scanSettings.reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH;
scanSettings.numBssidsPerScan = 0;
scanSettings.periodInMs = DISCONNECTED_PNO_SCAN_INTERVAL_MS;
- // TODO: enable exponential back off scan later to further save energy
- // scanSettings.maxPeriodInMs = 8 * scanSettings.periodInMs;
mPnoScanListener.clearScanDetails();
@@ -865,51 +809,7 @@ public class WifiConnectivityManager {
mPnoScanStarted = true;
}
- // Start a ConnectedPNO scan when screen is off and Wifi is connected
- private void startConnectedPnoScan() {
- // TODO(b/29503772): Need to change this interface.
- // Disable ConnectedPNO for now due to b/28020168
- if (!ENABLE_CONNECTED_PNO_SCAN) {
- return;
- }
-
- // Initialize PNO settings
- PnoSettings pnoSettings = new PnoSettings();
- List<PnoSettings.PnoNetwork> pnoNetworkList = mConfigManager.retrievePnoNetworkList();
- int listSize = pnoNetworkList.size();
-
- if (listSize == 0) {
- // No saved network
- localLog("No saved network for starting connected PNO.");
- return;
- }
-
- pnoSettings.networkList = new PnoSettings.PnoNetwork[listSize];
- pnoSettings.networkList = pnoNetworkList.toArray(pnoSettings.networkList);
- pnoSettings.min5GHzRssi = mMin5GHzRssi;
- pnoSettings.min24GHzRssi = mMin24GHzRssi;
- pnoSettings.initialScoreMax = mInitialScoreMax;
- pnoSettings.currentConnectionBonus = mCurrentConnectionBonus;
- pnoSettings.sameNetworkBonus = mSameNetworkBonus;
- pnoSettings.secureBonus = mSecureBonus;
- pnoSettings.band5GHzBonus = mBand5GHzBonus;
-
- // Initialize scan settings
- ScanSettings scanSettings = new ScanSettings();
- scanSettings.band = getScanBand();
- scanSettings.reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH;
- scanSettings.numBssidsPerScan = 0;
- scanSettings.periodInMs = CONNECTED_PNO_SCAN_INTERVAL_MS;
- // TODO: enable exponential back off scan later to further save energy
- // scanSettings.maxPeriodInMs = 8 * scanSettings.periodInMs;
-
- mPnoScanListener.clearScanDetails();
-
- mScanner.startConnectedPnoScan(scanSettings, pnoSettings, mPnoScanListener);
- mPnoScanStarted = true;
- }
-
- // Stop a PNO scan. This includes both DisconnectedPNO and ConnectedPNO scans.
+ // Stop PNO scan.
private void stopPnoScan() {
if (mPnoScanStarted) {
mScanner.stopPnoScan(mPnoScanListener);
@@ -920,7 +820,7 @@ public class WifiConnectivityManager {
// Set up watchdog timer
private void scheduleWatchdogTimer() {
- Log.i(TAG, "scheduleWatchdogTimer");
+ localLog("scheduleWatchdogTimer");
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mClock.getElapsedSinceBootMillis() + WATCHDOG_INTERVAL_MS,
@@ -994,9 +894,7 @@ public class WifiConnectivityManager {
if (mScreenOn) {
startPeriodicScan(scanImmediately);
} else { // screenOff
- if (mWifiState == WIFI_STATE_CONNECTED) {
- startConnectedPnoScan();
- } else {
+ if (mWifiState == WIFI_STATE_DISCONNECTED) {
startDisconnectedPnoScan();
}
}
@@ -1006,11 +904,7 @@ public class WifiConnectivityManager {
private void stopConnectivityScan() {
// Due to b/28020168, timer based single scan will be scheduled
// to provide periodic scan in an exponential backoff fashion.
- if (!ENABLE_BACKGROUND_SCAN) {
- cancelPeriodicScanTimer();
- } else {
- mScanner.stopBackgroundScan(mPeriodicScanListener);
- }
+ cancelPeriodicScanTimer();
stopPnoScan();
mScanRestartCount = 0;
}
@@ -1048,7 +942,7 @@ public class WifiConnectivityManager {
* Handler when user toggles whether untrusted connection is allowed
*/
public void setUntrustedConnectionAllowed(boolean allowed) {
- Log.i(TAG, "setUntrustedConnectionAllowed: allowed=" + allowed);
+ localLog("setUntrustedConnectionAllowed: allowed=" + allowed);
if (mUntrustedConnectionAllowed != allowed) {
mUntrustedConnectionAllowed = allowed;
@@ -1060,10 +954,9 @@ public class WifiConnectivityManager {
* Handler when user specifies a particular network to connect to
*/
public void setUserConnectChoice(int netId) {
- Log.i(TAG, "setUserConnectChoice: netId=" + netId);
-
- mQualifiedNetworkSelector.setUserConnectChoice(netId);
+ localLog("setUserConnectChoice: netId=" + netId);
+ mNetworkSelector.setUserConnectChoice(netId);
clearConnectionAttemptTimeStamps();
}
@@ -1071,24 +964,24 @@ public class WifiConnectivityManager {
* Handler for on-demand connectivity scan
*/
public void forceConnectivityScan() {
- Log.i(TAG, "forceConnectivityScan");
+ localLog("forceConnectivityScan");
startConnectivityScan(SCAN_IMMEDIATELY);
}
/**
- * Track whether a BSSID should be enabled or disabled for QNS
+ * Track whether a BSSID should be enabled or disabled for WifiNetworkSelector
*/
public boolean trackBssid(String bssid, boolean enable) {
- Log.i(TAG, "trackBssid: " + (enable ? "enable " : "disable ") + bssid);
+ localLog("trackBssid: " + (enable ? "enable " : "disable ") + bssid);
- boolean ret = mQualifiedNetworkSelector
- .enableBssidForQualityNetworkSelection(bssid, enable);
+ boolean ret = mNetworkSelector
+ .enableBssidForNetworkSelection(bssid, enable);
if (ret && !enable) {
// Disabling a BSSID can happen when the AP candidate to connect to has
- // no capacity for new stations. We start another scan immediately so that QNS
- // can give us another candidate to connect to.
+ // no capacity for new stations. We start another scan immediately so that
+ // WifiNetworkSelector can give us another candidate to connect to.
startConnectivityScan(SCAN_IMMEDIATELY);
}
@@ -1099,7 +992,7 @@ public class WifiConnectivityManager {
* Inform WiFi is enabled for connection or not
*/
public void setWifiEnabled(boolean enable) {
- Log.i(TAG, "Set WiFi " + (enable ? "enabled" : "disabled"));
+ localLog("Set WiFi " + (enable ? "enabled" : "disabled"));
mWifiEnabled = enable;
@@ -1108,7 +1001,7 @@ public class WifiConnectivityManager {
resetLastPeriodicSingleScanTimeStamp();
mLastConnectionAttemptBssid = null;
} else if (mWifiConnectivityManagerEnabled) {
- startConnectivityScan(SCAN_IMMEDIATELY);
+ startConnectivityScan(SCAN_IMMEDIATELY);
}
}
@@ -1116,7 +1009,7 @@ public class WifiConnectivityManager {
* Turn on/off the WifiConnectivityMangager at runtime
*/
public void enable(boolean enable) {
- Log.i(TAG, "Set WiFiConnectivityManager " + (enable ? "enabled" : "disabled"));
+ localLog("Set WiFiConnectivityManager " + (enable ? "enabled" : "disabled"));
mWifiConnectivityManagerEnabled = enable;
@@ -1125,29 +1018,10 @@ public class WifiConnectivityManager {
resetLastPeriodicSingleScanTimeStamp();
mLastConnectionAttemptBssid = null;
} else if (mWifiEnabled) {
- startConnectivityScan(SCAN_IMMEDIATELY);
+ startConnectivityScan(SCAN_IMMEDIATELY);
}
}
- /**
- * Enable/disable verbose logging
- */
- public void enableVerboseLogging(int verbose) {
- mDbg = verbose > 0;
- }
-
- /**
- * Dump the local log buffer
- */
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("Dump of WifiConnectivityManager");
- pw.println("WifiConnectivityManager - Log Begin ----");
- pw.println("WifiConnectivityManager - Number of connectivity attempts rate limited: "
- + mTotalConnectivityAttemptsRateLimited);
- mLocalLog.dump(fd, pw, args);
- pw.println("WifiConnectivityManager - Log End ----");
- }
-
@VisibleForTesting
int getLowRssiNetworkRetryDelay() {
return mPnoScanListener.getLowRssiNetworkRetryDelay();
diff --git a/service/java/com/android/server/wifi/WifiNetworkSelector.java b/service/java/com/android/server/wifi/WifiNetworkSelector.java
new file mode 100644
index 000000000..fec10eec7
--- /dev/null
+++ b/service/java/com/android/server/wifi/WifiNetworkSelector.java
@@ -0,0 +1,589 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.net.NetworkKey;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.text.TextUtils;
+import android.util.LocalLog;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class looks at all the connectivity scan results then
+ * selects a network for the phone to connect or roam to.
+ */
+public class WifiNetworkSelector {
+ private static final String TAG = "WifiNetworkSelector";
+ private static final long INVALID_TIME_STAMP = Long.MIN_VALUE;
+ // Minimum time gap between last successful network selection and a new selection
+ // attempt.
+ @VisibleForTesting
+ public static final int MINIMUM_NETWORK_SELECTION_INTERVAL_MS = 10 * 1000;
+
+ // Constants for BSSID blacklist.
+ public static final int BSSID_BLACKLIST_THRESHOLD = 3;
+ public static final int BSSID_BLACKLIST_EXPIRE_TIME_MS = 5 * 60 * 1000;
+
+ private WifiConfigManager mWifiConfigManager;
+ private WifiInfo mWifiInfo;
+ private Clock mClock;
+ private WifiConfiguration mCurrentNetwork = null;
+ private String mCurrentBssid = null;
+ private static class BssidBlacklistStatus {
+ // Number of times this BSSID has been rejected for association.
+ public int counter;
+ public boolean isBlacklisted;
+ public long blacklistedTimeStamp = INVALID_TIME_STAMP;
+ }
+ private Map<String, BssidBlacklistStatus> mBssidBlacklist =
+ new HashMap<>();
+
+ private final LocalLog mLocalLog =
+ new LocalLog(ActivityManager.isLowRamDeviceStatic() ? 256 : 512);
+ private long mLastNetworkSelectionTimeStamp = INVALID_TIME_STAMP;
+ // Buffer of filtered scan results (Scan results considered by network selection) & associated
+ // WifiConfiguration (if any).
+ private volatile List<Pair<ScanDetail, WifiConfiguration>> mConnectableNetworks =
+ new ArrayList<>();
+ private final int mThresholdQualifiedRssi24;
+ private final int mThresholdQualifiedRssi5;
+ private final int mThresholdMinimumRssi24;
+ private final int mThresholdMinimumRssi5;
+ private final boolean mEnableAutoJoinWhenAssociated;
+
+ /**
+ * WiFi Network Selector supports various types of networks. Each type can
+ * have its evaluator to choose the best WiFi network for the device to connect
+ * to. When registering a WiFi network evaluator with the WiFi Network Selector,
+ * the priority of the network must be specified, and it must be a value between
+ * 0 and (EVALUATOR_MIN_PIRORITY - 1) with 0 being the highest priority. Wifi
+ * Network Selector iterates through the registered scorers from the highest priority
+ * to the lowest till a network is selected.
+ */
+ public static final int EVALUATOR_MIN_PRIORITY = 6;
+
+ /**
+ * Maximum number of evaluators can be registered with Wifi Network Selector.
+ */
+ public static final int MAX_NUM_EVALUATORS = EVALUATOR_MIN_PRIORITY;
+
+ /**
+ * Interface for WiFi Network Evaluator
+ *
+ * A network scorer evaulates all the networks from the scan results and
+ * recommends the best network in its category to connect or roam to.
+ */
+ public interface NetworkEvaluator {
+ /**
+ * Get the evaluator name.
+ */
+ String getName();
+
+ /**
+ * Update the evaluator.
+ *
+ * Certain evaluators have to be updated with the new scan results. For example
+ * the ExternalScoreEvalutor needs to refresh its Score Cache.
+ *
+ * @param scanDetails a list of scan details constructed from the scan results
+ */
+ void update(List<ScanDetail> scanDetails);
+
+ /**
+ * Evaluate all the networks from the scan results.
+ *
+ * @param scanDetails a list of scan details constructed from the scan results
+ * @param currentNetwork configuration of the current connected network
+ * or null if disconnected
+ * @param currentBssid BSSID of the current connected network or null if
+ * disconnected
+ * @param connected a flag to indicate if WifiStateMachine is in connected
+ * state
+ * @param untrustedNetworkAllowed a flag to indidate if untrusted networks like
+ * ephemeral networks are allowed
+ * @param connectableNetworks a list of the ScanDetail and WifiConfiguration
+ * pair which is used by the WifiLastResortWatchdog
+ * @return configuration of the chosen network;
+ * null if no network in this category is available.
+ */
+ @Nullable
+ WifiConfiguration evaluateNetworks(List<ScanDetail> scanDetails,
+ WifiConfiguration currentNetwork, String currentBssid,
+ boolean connected, boolean untrustedNetworkAllowed,
+ List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks);
+ }
+
+ private final NetworkEvaluator[] mEvaluators = new NetworkEvaluator[MAX_NUM_EVALUATORS];
+
+ // A helper to log debugging information in the local log buffer, which can
+ // be retrieved in bugreport.
+ private void localLog(String log) {
+ mLocalLog.log(log);
+ }
+
+ private boolean isCurrentNetworkSufficient(WifiConfiguration network) {
+ // Currently connected?
+ if (network == null) {
+ localLog("No current connected network.");
+ return false;
+ } else {
+ localLog("Current connected network: " + network.SSID
+ + " , ID: " + network.networkId);
+ }
+
+ // Ephemeral network is not qualified.
+ if (network.ephemeral) {
+ localLog("Current network is an ephemeral one.");
+ return false;
+ }
+
+ // Open network is not qualified.
+ if (WifiConfigurationUtil.isConfigForOpenNetwork(network)) {
+ localLog("Current network is a open one.");
+ return false;
+ }
+
+ // 2.4GHz networks is not qualified.
+ if (mWifiInfo.is24GHz()) {
+ localLog("Current network is 2.4GHz.");
+ return false;
+ }
+
+ // Is the current network's singnal strength qualified? It can only
+ // be a 5GHz network if we reach here.
+ int currentRssi = mWifiInfo.getRssi();
+ if (mWifiInfo.is5GHz() && currentRssi < mThresholdQualifiedRssi5) {
+ localLog("Current network band=" + (mWifiInfo.is5GHz() ? "5GHz" : "2.4GHz")
+ + ", RSSI[" + currentRssi + "]-acceptable but not qualified.");
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean isNetworkSelectionNeeded(List<ScanDetail> scanDetails,
+ boolean connected, boolean disconnected) {
+ if (scanDetails.size() == 0) {
+ localLog("Empty connectivity scan results. Skip network selection.");
+ return false;
+ }
+
+ if (connected) {
+ // Is roaming allowed?
+ if (!mEnableAutoJoinWhenAssociated) {
+ localLog("Switching networks in connected state is not allowed."
+ + " Skip network selection.");
+ return false;
+ }
+
+ // Has it been at least the minimum interval since last network selection?
+ if (mLastNetworkSelectionTimeStamp != INVALID_TIME_STAMP) {
+ long gap = mClock.getElapsedSinceBootMillis()
+ - mLastNetworkSelectionTimeStamp;
+ if (gap < MINIMUM_NETWORK_SELECTION_INTERVAL_MS) {
+ localLog("Too short since last network selection: " + gap + " ms."
+ + " Skip network selection.");
+ return false;
+ }
+ }
+
+ if (isCurrentNetworkSufficient(mCurrentNetwork)) {
+ localLog("Current connected network already sufficient. Skip network selection.");
+ return false;
+ } else {
+ localLog("Current connected network is not sufficient.");
+ }
+ } else if (disconnected) {
+ mCurrentNetwork = null;
+ mCurrentBssid = null;
+ } else {
+ // No network selection if WifiStateMachine is in a state other than
+ // CONNECTED or DISCONNECTED.
+ localLog("WifiStateMachine is in neither CONNECTED nor DISCONNECTED state."
+ + " Skip network selection.");
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Format the given ScanResult as a scan ID for logging.
+ */
+ public static String toScanId(@Nullable ScanResult scanResult) {
+ return scanResult == null ? "NULL"
+ : String.format("%s:%s", scanResult.SSID, scanResult.BSSID);
+ }
+
+ /**
+ * Format the given WifiConfiguration as a SSID:netId string
+ */
+ public static String toNetworkString(WifiConfiguration network) {
+ if (network == null) {
+ return null;
+ }
+
+ return (network.SSID + ":" + network.networkId);
+ }
+
+ private List<ScanDetail> filterScanResults(List<ScanDetail> scanDetails) {
+ ArrayList<NetworkKey> unscoredNetworks = new ArrayList<NetworkKey>();
+ List<ScanDetail> validScanDetails = new ArrayList<ScanDetail>();
+ StringBuffer noValidSsid = new StringBuffer();
+ StringBuffer blacklistedBssid = new StringBuffer();
+ StringBuffer lowRssi = new StringBuffer();
+
+ for (ScanDetail scanDetail : scanDetails) {
+ ScanResult scanResult = scanDetail.getScanResult();
+
+ if (TextUtils.isEmpty(scanResult.SSID)) {
+ noValidSsid.append(scanResult.BSSID).append(" / ");
+ continue;
+ }
+
+ final String scanId = toScanId(scanResult);
+
+ if (isBssidDisabled(scanResult.BSSID)) {
+ blacklistedBssid.append(scanId).append(" / ");
+ continue;
+ }
+
+ // Skip network with too weak signals.
+ if ((scanResult.is24GHz() && scanResult.level
+ < mThresholdMinimumRssi24)
+ || (scanResult.is5GHz() && scanResult.level
+ < mThresholdMinimumRssi5)) {
+ lowRssi.append(scanId).append("(")
+ .append(scanResult.is24GHz() ? "2.4GHz" : "5GHz")
+ .append(")").append(scanResult.level).append(" / ");
+ continue;
+ }
+
+ validScanDetails.add(scanDetail);
+ }
+
+ if (noValidSsid.length() != 0) {
+ localLog("Networks filtered out due to invalid SSID: " + noValidSsid);
+ }
+
+ if (blacklistedBssid.length() != 0) {
+ localLog("Networks filtered out due to blacklist: " + blacklistedBssid);
+ }
+
+ if (lowRssi.length() != 0) {
+ localLog("Networks filtered out due to low signal strength: " + lowRssi);
+ }
+
+ return validScanDetails;
+ }
+
+ /**
+ * @return the list of ScanDetails scored as potential candidates by the last run of
+ * selectNetwork, this will be empty if Network selector determined no selection was
+ * needed on last run. This includes scan details of sufficient signal strength, and
+ * had an associated WifiConfiguration.
+ */
+ public List<Pair<ScanDetail, WifiConfiguration>> getFilteredScanDetails() {
+ return mConnectableNetworks;
+ }
+
+ /**
+ * This API is called when user explicitly selects a network. Currently, it is used in following
+ * cases:
+ * (1) User explicitly chooses to connect to a saved network.
+ * (2) User saves a network after adding a new network.
+ * (3) User saves a network after modifying a saved network.
+ * Following actions will be triggered:
+ * 1. If this network is disabled, we need re-enable it again.
+ * 2. This network is favored over all the other networks visible in latest network
+ * selection procedure.
+ *
+ * @param netId ID for the network chosen by the user
+ * @return true -- There is change made to connection choice of any saved network.
+ * false -- There is no change made to connection choice of any saved network.
+ */
+ public boolean setUserConnectChoice(int netId) {
+ localLog("userSelectNetwork: network ID=" + netId);
+ WifiConfiguration selected = mWifiConfigManager.getConfiguredNetwork(netId);
+
+ if (selected == null || selected.SSID == null) {
+ localLog("userSelectNetwork: Invalid configuration with nid=" + netId);
+ return false;
+ }
+
+ // Enable the network if it is disabled.
+ if (!selected.getNetworkSelectionStatus().isNetworkEnabled()) {
+ mWifiConfigManager.updateNetworkSelectionStatus(netId,
+ WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE);
+ }
+
+ boolean change = false;
+ String key = selected.configKey();
+ // This is only used for setting the connect choice timestamp for debugging purposes.
+ long currentTime = mClock.getWallClockMillis();
+ List<WifiConfiguration> savedNetworks = mWifiConfigManager.getSavedNetworks();
+
+ for (WifiConfiguration network : savedNetworks) {
+ WifiConfiguration.NetworkSelectionStatus status = network.getNetworkSelectionStatus();
+ if (network.networkId == selected.networkId) {
+ if (status.getConnectChoice() != null) {
+ localLog("Remove user selection preference of " + status.getConnectChoice()
+ + " Set Time: " + status.getConnectChoiceTimestamp() + " from "
+ + network.SSID + " : " + network.networkId);
+ mWifiConfigManager.clearNetworkConnectChoice(network.networkId);
+ change = true;
+ }
+ continue;
+ }
+
+ if (status.getSeenInLastQualifiedNetworkSelection()
+ && (status.getConnectChoice() == null
+ || !status.getConnectChoice().equals(key))) {
+ localLog("Add key: " + key + " Set Time: " + currentTime + " to "
+ + toNetworkString(network));
+ mWifiConfigManager.setNetworkConnectChoice(network.networkId, key, currentTime);
+ change = true;
+ }
+ }
+
+ return change;
+ }
+
+ /**
+ * Enable/disable a BSSID for Network Selection
+ * When an association rejection event is obtained, Network Selector will disable this
+ * BSSID but supplicant still can try to connect to this bssid. If supplicant connect to it
+ * successfully later, this bssid can be re-enabled.
+ *
+ * @param bssid the bssid to be enabled / disabled
+ * @param enable -- true enable a bssid if it has been disabled
+ * -- false disable a bssid
+ */
+ public boolean enableBssidForNetworkSelection(String bssid, boolean enable) {
+ if (enable) {
+ return (mBssidBlacklist.remove(bssid) != null);
+ } else {
+ if (bssid != null) {
+ BssidBlacklistStatus status = mBssidBlacklist.get(bssid);
+ if (status == null) {
+ // First time for this BSSID
+ BssidBlacklistStatus newStatus = new BssidBlacklistStatus();
+ newStatus.counter++;
+ mBssidBlacklist.put(bssid, newStatus);
+ } else if (!status.isBlacklisted) {
+ status.counter++;
+ if (status.counter >= BSSID_BLACKLIST_THRESHOLD) {
+ status.isBlacklisted = true;
+ status.blacklistedTimeStamp = mClock.getElapsedSinceBootMillis();
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Update the BSSID blacklist
+ *
+ * Go through the BSSID blacklist and check when a BSSID was blocked. If it
+ * has been blacklisted for BSSID_BLACKLIST_EXPIRE_TIME_MS, then re-enable it.
+ */
+ private void updateBssidBlacklist() {
+ Iterator<BssidBlacklistStatus> iter = mBssidBlacklist.values().iterator();
+ while (iter.hasNext()) {
+ BssidBlacklistStatus status = iter.next();
+ if (status != null && status.isBlacklisted) {
+ if (mClock.getElapsedSinceBootMillis() - status.blacklistedTimeStamp
+ >= BSSID_BLACKLIST_EXPIRE_TIME_MS) {
+ iter.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * Check whether a bssid is disabled
+ * @param bssid -- the bssid to check
+ */
+ private boolean isBssidDisabled(String bssid) {
+ BssidBlacklistStatus status = mBssidBlacklist.get(bssid);
+ return status == null ? false : status.isBlacklisted;
+ }
+
+ /**
+ *
+ */
+ @Nullable
+ public WifiConfiguration selectNetwork(List<ScanDetail> scanDetails,
+ boolean connected, boolean disconnected, boolean untrustedNetworkAllowed) {
+ mConnectableNetworks.clear();
+ if (scanDetails.size() == 0) {
+ localLog("Empty connectivity scan result");
+ return null;
+ }
+
+ if (mCurrentNetwork == null) {
+ mCurrentNetwork =
+ mWifiConfigManager.getConfiguredNetwork(mWifiInfo.getNetworkId());
+ }
+
+ // Always get the current BSSID from WifiInfo in case that firmware initiated
+ // roaming happened.
+ mCurrentBssid = mWifiInfo.getBSSID();
+
+ // Shall we start network selection at all?
+ if (!isNetworkSelectionNeeded(scanDetails, connected, disconnected)) {
+ return null;
+ }
+
+ // Update the registered network evaluators.
+ for (NetworkEvaluator registeredEvaluator : mEvaluators) {
+ if (registeredEvaluator != null) {
+ registeredEvaluator.update(scanDetails);
+ }
+ }
+
+ // Check if any BSSID can be freed from the blacklist.
+ updateBssidBlacklist();
+
+ // Filter out unwanted networks.
+ List<ScanDetail> filteredScanDetails = filterScanResults(scanDetails);
+ if (filteredScanDetails.size() == 0) {
+ return null;
+ }
+
+ // Go through the registered network evaluators from the highest priority
+ // one to the lowest till a network is selected.
+ WifiConfiguration selectedNetwork = null;
+ for (NetworkEvaluator registeredEvaluator : mEvaluators) {
+ if (registeredEvaluator != null) {
+ selectedNetwork = registeredEvaluator.evaluateNetworks(scanDetails,
+ mCurrentNetwork, mCurrentBssid, connected,
+ untrustedNetworkAllowed, mConnectableNetworks);
+ if (selectedNetwork != null) {
+ break;
+ }
+ }
+ }
+
+ if (selectedNetwork != null) {
+ mCurrentNetwork = selectedNetwork;
+ mCurrentBssid = selectedNetwork.getNetworkSelectionStatus().getCandidate().BSSID;
+ mLastNetworkSelectionTimeStamp = mClock.getElapsedSinceBootMillis();
+ }
+
+ return selectedNetwork;
+ }
+
+ /**
+ * Register a network evaluator
+ *
+ * @param evaluator the network evaluator to be registered
+ * @param priority a value between 0 and (SCORER_MIN_PRIORITY-1)
+ *
+ * @return true if the evaluator is successfully registered with QNS;
+ * false if failed to register the evaluator
+ */
+ public boolean registerNetworkEvaluator(NetworkEvaluator evaluator, int priority) {
+ if (priority < 0 || priority >= EVALUATOR_MIN_PRIORITY) {
+ Log.e(TAG, "Invalid network evaluator priority: " + priority);
+ return false;
+ }
+
+ if (mEvaluators[priority] != null) {
+ Log.e(TAG, "Priority " + priority + " is already registered by "
+ + mEvaluators[priority].getName());
+ return false;
+ }
+
+ mEvaluators[priority] = evaluator;
+ return true;
+ }
+
+ /**
+ * Unregister a network evaluator
+ *
+ * @param evaluator the network evaluator to be unregistered from QNS
+ *
+ * @return true if the evaluator is successfully unregistered from;
+ * false if failed to unregister the evaluator
+ */
+ public boolean unregisterNetworkEvaluator(NetworkEvaluator evaluator) {
+ for (NetworkEvaluator registeredEvaluator : mEvaluators) {
+ if (registeredEvaluator == evaluator) {
+ Log.d(TAG, "Unregistered network evaluator: " + evaluator.getName());
+ return true;
+ }
+ }
+
+ Log.e(TAG, "Couldn't unregister network evaluator: " + evaluator.getName());
+ return false;
+ }
+
+ WifiNetworkSelector(Context context, WifiConfigManager configManager,
+ WifiInfo wifiInfo, Clock clock) {
+ mWifiConfigManager = configManager;
+ mWifiInfo = wifiInfo;
+ mClock = clock;
+
+ mThresholdQualifiedRssi24 = context.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
+ mThresholdQualifiedRssi5 = context.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz);
+ mThresholdMinimumRssi24 = context.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
+ mThresholdMinimumRssi5 = context.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
+ mEnableAutoJoinWhenAssociated = context.getResources().getBoolean(
+ R.bool.config_wifi_framework_enable_associated_network_selection);
+ }
+
+ /**
+ * Retrieve the local log buffer created by WifiNetworkSelector.
+ */
+ public LocalLog getLocalLog() {
+ return mLocalLog;
+ }
+
+ /**
+ * Dump the local logs.
+ */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Dump of WifiNetworkSelector");
+ pw.println("WifiNetworkSelector - Log Begin ----");
+ mLocalLog.dump(fd, pw, args);
+ pw.println("WifiNetworkSelector - Log End ----");
+ }
+}
diff --git a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java
deleted file mode 100644
index d920273f4..000000000
--- a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java
+++ /dev/null
@@ -1,1062 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wifi;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.net.NetworkKey;
-import android.net.NetworkScoreManager;
-import android.net.WifiKey;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.Process;
-import android.text.TextUtils;
-import android.util.LocalLog;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.wifi.util.ScanResultUtil;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-/**
- * This class looks at all the connectivity scan results then
- * selects a network for the phone to connect or roam to.
- */
-public class WifiQualifiedNetworkSelector {
- private WifiConfigManager mWifiConfigManager;
- private WifiInfo mWifiInfo;
- private NetworkScoreManager mScoreManager;
- private WifiNetworkScoreCache mNetworkScoreCache;
- private Clock mClock;
- private static final String TAG = "WifiQualifiedNetworkSelector:";
- // Always enable debugging logs for now since QNS is still a new feature.
- private static final boolean FORCE_DEBUG = true;
- private boolean mDbg = FORCE_DEBUG;
- private WifiConfiguration mCurrentConnectedNetwork = null;
- private String mCurrentBssid = null;
-
- // Buffer of filtered scan results (Scan results considered by network selection) & associated
- // WifiConfiguration (if any).
- private volatile List<Pair<ScanDetail, WifiConfiguration>> mFilteredScanDetails = null;
-
- // Minimum time gap between last successful Qualified Network Selection and a new selection
- // attempt.
- private static final int MINIMUM_QUALIFIED_NETWORK_SELECTION_INTERVAL_MS = 10 * 1000;
-
- // A 2.4GHz network with RSSI value above this threshold is considered qualified. No new
- // selection attempt necessary.
- public static final int QUALIFIED_RSSI_24G_BAND = -73;
- // A 5GHz network with RSSI value above this threshold is considered qualified. No new
- // selection attempt necessary.
- public static final int QUALIFIED_RSSI_5G_BAND = -70;
- // A RSSI vaule larger than this threshold is considered saturated and switching to a
- // higher RSSI value network won't benefit the connection much.
- public static final int RSSI_SATURATION_2G_BAND = -60;
- public static final int RSSI_SATURATION_5G_BAND = -57;
- // Any RSSI value below this is considered unacceptable, and the network will be filtered out.
- public static final int MINIMUM_2G_ACCEPT_RSSI = -85;
- public static final int MINIMUM_5G_ACCEPT_RSSI = -82;
-
- // Constants for BSSID scoring formula.
- public static final int RSSI_SCORE_SLOPE = 4;
- public static final int RSSI_SCORE_OFFSET = 85;
- public static final int BAND_AWARD_5GHz = 40;
- public static final int SAME_NETWORK_AWARD = 16;
- public static final int SAME_BSSID_AWARD = 24;
- public static final int LAST_SELECTION_AWARD = 480;
- public static final int PASSPOINT_SECURITY_AWARD = 40;
- public static final int SECURITY_AWARD = 80;
-
- // BSSID blacklist parameters.
- public static final int BSSID_BLACKLIST_THRESHOLD = 3;
- public static final int BSSID_BLACKLIST_EXPIRE_TIME_MS = 5 * 60 * 1000;
-
- private final int mNoIntnetPenalty;
- private static final int INVALID_TIME_STAMP = -1;
- private long mLastQualifiedNetworkSelectionTimeStamp = INVALID_TIME_STAMP;
-
- private final LocalLog mLocalLog = new LocalLog(512);
- private int mRssiScoreSlope = RSSI_SCORE_SLOPE;
- private int mRssiScoreOffset = RSSI_SCORE_OFFSET;
- private int mSameBssidAward = SAME_BSSID_AWARD;
- private int mLastSelectionAward = LAST_SELECTION_AWARD;
- private int mPasspointSecurityAward = PASSPOINT_SECURITY_AWARD;
- private int mSecurityAward = SECURITY_AWARD;
- private final int mThresholdQualifiedRssi24;
- private final int mThresholdQualifiedRssi5;
- private final boolean mEnableAutoJoinWhenAssociated;
- private final int mBandAward5Ghz;
- private final int mCurrentNetworkBoost;
- private final int mThresholdSaturatedRssi24;
- private final int mThresholdSaturatedRssi5;
- private final int mThresholdMinimumRssi5;
- private final int mThresholdMinimumRssi24;
- private int mUserPreferedBand = WifiManager.WIFI_FREQUENCY_BAND_AUTO;
- private Map<String, BssidBlacklistStatus> mBssidBlacklist =
- new HashMap<String, BssidBlacklistStatus>();
-
- /**
- * Class that saves the blacklist status of a given BSSID.
- */
- private static class BssidBlacklistStatus {
- // Number of times this BSSID has been requested to be blacklisted.
- // Association rejection triggers such a request.
- int mCounter;
- boolean mIsBlacklisted;
- long mBlacklistedTimeStamp = INVALID_TIME_STAMP;
- }
-
- private void localLog(String log) {
- if (mDbg) {
- mLocalLog.log(log);
- }
- }
-
- private void localLoge(String log) {
- mLocalLog.log(log);
- }
-
- @VisibleForTesting
- void setWifiNetworkScoreCache(WifiNetworkScoreCache cache) {
- mNetworkScoreCache = cache;
- }
-
- /**
- * @return current target connected network
- */
- public WifiConfiguration getConnetionTargetNetwork() {
- return mCurrentConnectedNetwork;
- }
-
- /**
- * @return the list of ScanDetails scored as potential candidates by the last run of
- * selectQualifiedNetwork, this will be empty if QNS determined no selection was needed on last
- * run. This includes scan details of sufficient signal strength, and had an associated
- * WifiConfiguration.
- */
- public List<Pair<ScanDetail, WifiConfiguration>> getFilteredScanDetails() {
- return mFilteredScanDetails;
- }
-
- WifiQualifiedNetworkSelector(WifiConfigManager configManager, Context context,
- WifiInfo wifiInfo, Clock clock) {
- mWifiConfigManager = configManager;
- mWifiInfo = wifiInfo;
- mClock = clock;
- mScoreManager =
- (NetworkScoreManager) context.getSystemService(Context.NETWORK_SCORE_SERVICE);
- if (mScoreManager != null) {
- mNetworkScoreCache = new WifiNetworkScoreCache(context);
- mScoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache);
- } else {
- localLoge("Couldn't get NETWORK_SCORE_SERVICE.");
- mNetworkScoreCache = null;
- }
-
- mRssiScoreSlope = context.getResources().getInteger(
- R.integer.config_wifi_framework_RSSI_SCORE_SLOPE);
- mRssiScoreOffset = context.getResources().getInteger(
- R.integer.config_wifi_framework_RSSI_SCORE_OFFSET);
- mSameBssidAward = context.getResources().getInteger(
- R.integer.config_wifi_framework_SAME_BSSID_AWARD);
- mLastSelectionAward = context.getResources().getInteger(
- R.integer.config_wifi_framework_LAST_SELECTION_AWARD);
- mPasspointSecurityAward = context.getResources().getInteger(
- R.integer.config_wifi_framework_PASSPOINT_SECURITY_AWARD);
- mSecurityAward = context.getResources().getInteger(
- R.integer.config_wifi_framework_SECURITY_AWARD);
- mThresholdQualifiedRssi24 = context.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
- mThresholdQualifiedRssi5 = context.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz);
- mEnableAutoJoinWhenAssociated = context.getResources().getBoolean(
- R.bool.config_wifi_framework_enable_associated_network_selection);
- mBandAward5Ghz = context.getResources().getInteger(
- R.integer.config_wifi_framework_5GHz_preference_boost_factor);
- mCurrentNetworkBoost = context.getResources().getInteger(
- R.integer.config_wifi_framework_current_network_boost);
- mThresholdSaturatedRssi24 = context.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz);
- mThresholdSaturatedRssi5 = context.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz);
- mThresholdMinimumRssi5 = context.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
- mThresholdMinimumRssi24 = context.getResources().getInteger(
- R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
- mNoIntnetPenalty =
- (mThresholdSaturatedRssi24 + mRssiScoreOffset) * mRssiScoreSlope +
- mBandAward5Ghz + mCurrentNetworkBoost + mSameBssidAward + mSecurityAward;
- }
-
- void enableVerboseLogging(int verbose) {
- mDbg = verbose > 0 || FORCE_DEBUG;
- }
-
- private String getNetworkString(WifiConfiguration network) {
- if (network == null) {
- return null;
- }
-
- return (network.SSID + ":" + network.networkId);
-
- }
-
- /**
- * Check if the current connected network is already qualified so that network
- * selection from the new scan results is not necessary.
- *
- * @param currentNetwork -- current connected network
- */
- private boolean isCurrentNetworkQualified(WifiConfiguration currentNetwork) {
- if (currentNetwork == null) {
- localLog("No current connected network");
- return false;
- } else {
- localLog("Current connected network: " + currentNetwork.SSID
- + " , ID: " + currentNetwork.networkId);
- }
-
- // Ephemeral networks are not qualified.
- if (currentNetwork.ephemeral) {
- localLog("Current network is an ephemeral one");
- return false;
- }
-
- // Open networks are not qualified.
- if (WifiConfigurationUtil.isConfigForOpenNetwork(currentNetwork)) {
- localLog("Current network is a open one");
- return false;
- }
-
- // Does the current network band match the user preference?
- //
- // Note, here the check for 2.4GHz band is different from the one for 5GHz band
- // such that 5GHz band is always favored.
- // When the current network is 2.4GHz, it is considered as not qualified as long
- // as the band preference set by user is not 2.4GHz only. This gives QNS an
- // opportunity to recommend a 5GHz network if one is available.
- // When the current network is 5GHz, it's considered as not qualified only if
- // the band preference set by user is 2.4GHz only.
- if ((mWifiInfo.is24GHz() && (mUserPreferedBand != WifiManager.WIFI_FREQUENCY_BAND_2GHZ))
- || (mWifiInfo.is5GHz()
- && (mUserPreferedBand == WifiManager.WIFI_FREQUENCY_BAND_2GHZ))) {
- localLog("Current network band does not match user preference: "
- + "current network band=" + (mWifiInfo.is24GHz() ? "2.4GHz" : "5GHz")
- + ", however user preferred band=" + mUserPreferedBand);
- return false;
- }
-
- // Is the current network's singnal strength qualified?
- int currentRssi = mWifiInfo.getRssi();
- if ((mWifiInfo.is24GHz() && currentRssi < mThresholdQualifiedRssi24)
- || (mWifiInfo.is5GHz() && currentRssi < mThresholdQualifiedRssi5)) {
- localLog("Current network band=" + (mWifiInfo.is24GHz() ? "2.4GHz" : "5GHz")
- + ", RSSI[" + currentRssi + "]-acceptable but not qualified");
- return false;
- }
-
- return true;
- }
-
- /**
- * Check whether QualifiedNetworkSelection is needed.
- *
- * @param isLinkDebouncing true -- Link layer is under debouncing
- * false -- Link layer is not under debouncing
- * @param isConnected true -- device is connected to an AP currently
- * false -- device is not connected to an AP currently
- * @param isDisconnected true -- WifiStateMachine is at disconnected state
- * false -- WifiStateMachine is not at disconnected state
- * @param isSupplicantTransientState true -- supplicant is in a transient state now
- * false -- supplicant is not in a transient state now
- */
- private boolean needQualifiedNetworkSelection(boolean isLinkDebouncing, boolean isConnected,
- boolean isDisconnected, boolean isSupplicantTransientState) {
- // No Qualified Network Selection during the L2 link debouncing procedure.
- if (isLinkDebouncing) {
- localLog("No QNS during L2 debouncing");
- return false;
- }
-
- if (isConnected) {
- // Already connected. Looking for a better candidate.
-
- // Is network switching allowed in connected state?
- if (!mEnableAutoJoinWhenAssociated) {
- localLog("Switching networks in connected state is not allowed");
- return false;
- }
-
- // Do not select again if last selection is within
- // MINIMUM_QUALIFIED_NETWORK_SELECTION_INTERVAL_MS.
- if (mLastQualifiedNetworkSelectionTimeStamp != INVALID_TIME_STAMP) {
- long gap = mClock.getElapsedSinceBootMillis()
- - mLastQualifiedNetworkSelectionTimeStamp;
- if (gap < MINIMUM_QUALIFIED_NETWORK_SELECTION_INTERVAL_MS) {
- localLog("Too short from last successful Qualified Network Selection. Gap is:"
- + gap + " ms!");
- return false;
- }
- }
-
- WifiConfiguration currentNetwork =
- mWifiConfigManager.getConfiguredNetwork(mWifiInfo.getNetworkId());
- if (currentNetwork == null) {
- // WifiStateMachine in connected state but WifiInfo is not. It means there is a race
- // condition. Defer QNS until WifiStateMachine enters the disconnected state.
- //
- // TODO(b/28249371): Root cause this race condition.
- return false;
- }
-
- // Already connected to a qualified network?
- if (!isCurrentNetworkQualified(mCurrentConnectedNetwork)) {
- localLog("Current connected network is not qualified");
- return true;
- } else {
- return false;
- }
- } else if (isDisconnected) {
- mCurrentConnectedNetwork = null;
- mCurrentBssid = null;
- // Defer Qualified Network Selection if wpa_supplicant is in the transient state.
- if (isSupplicantTransientState) {
- return false;
- }
- } else {
- // Do not allow new network selection if WifiStateMachine is in a state
- // other than connected or disconnected.
- localLog("WifiStateMachine is not on connected or disconnected state");
- return false;
- }
-
- return true;
- }
-
- int calculateBssidScore(ScanResult scanResult, WifiConfiguration network,
- boolean sameNetwork, boolean sameBssid, boolean sameSelect, StringBuffer sbuf) {
-
- int score = 0;
- // Calculate the RSSI score.
- int rssi = scanResult.level <= mThresholdSaturatedRssi24
- ? scanResult.level : mThresholdSaturatedRssi24;
- score += (rssi + mRssiScoreOffset) * mRssiScoreSlope;
- sbuf.append("RSSI score: ").append(score);
-
- // 5GHz band bonus.
- if (scanResult.is5GHz()) {
- score += mBandAward5Ghz;
- sbuf.append(" 5GHz bonus: ").append(mBandAward5Ghz);
- }
-
- // Last user selection award.
- if (sameSelect) {
- long timeDifference =
- mClock.getElapsedSinceBootMillis()
- - mWifiConfigManager.getLastSelectedTimeStamp();
- if (timeDifference > 0) {
- int bonus = mLastSelectionAward - (int) (timeDifference / 1000 / 60);
- score += bonus > 0 ? bonus : 0;
- sbuf.append(" User selected it last time ").append(timeDifference / 1000 / 60)
- .append(" minutes ago, bonus: ").append(bonus);
- }
- }
-
- // Same network award.
- if (sameNetwork) {
- score += mCurrentNetworkBoost;
- sbuf.append(" Same network as the current one, bonus: ").append(mCurrentNetworkBoost);
- }
-
- // Same BSSID award.
- if (sameBssid) {
- score += mSameBssidAward;
- sbuf.append(" Same BSSID as the current one, bonus: ").append(mSameBssidAward);
- }
-
- // Security award.
- if (network.isPasspoint()) {
- score += mPasspointSecurityAward;
- sbuf.append(" Passpoint bonus: ").append(mPasspointSecurityAward);
- } else if (!WifiConfigurationUtil.isConfigForOpenNetwork(network)) {
- score += mSecurityAward;
- sbuf.append(" Secure network bonus: ").append(mSecurityAward);
- }
-
- // No internet penalty.
- if (network.numNoInternetAccessReports > 0 && !network.validatedInternetAccess) {
- score -= mNoIntnetPenalty;
- sbuf.append(" No internet penalty: -").append(mNoIntnetPenalty);
- }
-
- sbuf.append(" -- ScanResult: ").append(scanResult).append(" for network: ")
- .append(network.networkId).append(" score: ").append(score).append(" --\n");
-
- return score;
- }
-
- /**
- * Update all the saved networks' selection status
- */
- private void updateSavedNetworkSelectionStatus() {
- List<WifiConfiguration> savedNetworks = mWifiConfigManager.getSavedNetworks();
- if (savedNetworks.size() == 0) {
- localLog("no saved network");
- return;
- }
-
- StringBuffer sbuf = new StringBuffer("Saved Network List: \n");
- for (WifiConfiguration network : savedNetworks) {
- WifiConfiguration.NetworkSelectionStatus status = network.getNetworkSelectionStatus();
- // If a configuration is temporarily disabled, re-enable it before trying
- // to connect to it.
- mWifiConfigManager.tryEnableNetwork(network.networkId);
-
- // Clear the cached candidate, score and seen.
- mWifiConfigManager.clearNetworkCandidateScanResult(network.networkId);
-
- sbuf.append(" ").append(getNetworkString(network)).append(" ")
- .append(" User Preferred BSSID: ").append(network.BSSID)
- .append(" FQDN: ").append(network.FQDN).append(" ")
- .append(status.getNetworkStatusString()).append(" Disable account: ");
- for (int index = WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
- index < WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX;
- index++) {
- sbuf.append(status.getDisableReasonCounter(index)).append(" ");
- }
- sbuf.append("Connect Choice: ").append(status.getConnectChoice())
- .append(" set time: ").append(status.getConnectChoiceTimestamp())
- .append("\n");
- }
- localLog(sbuf.toString());
- }
-
- /**
- * This API is called when user/app explicitly selects a network. Currently, it is used in
- * following cases:
- * (1) User explicitly chooses to connect to a saved network.
- * (2) User saves a network after adding a new network.
- * (3) User saves a network after modifying a saved network.
- * Following actions will be triggered:
- * 1. If this network is disabled, we need re-enable it again.
- * 2. This network is favored over all the other networks visible in latest network
- * selection procedure.
- *
- * @param netId ID for the network chosen by the user
- * @return true -- There is change made to connection choice of any saved network.
- * false -- There is no change made to connection choice of any saved network.
- */
- public boolean setUserConnectChoice(int netId) {
- localLog("setUserConnectChoice: network ID=" + netId);
- WifiConfiguration selected = mWifiConfigManager.getConfiguredNetwork(netId);
- if (selected == null || selected.SSID == null) {
- localLoge("setUserConnectChoice: Invalid configuration with nid=" + netId);
- return false;
- }
-
- boolean change = false;
- String key = selected.configKey();
- // This is only used for setting the connect choice timestamp for debugging purposes.
- long currentTime = mClock.getWallClockMillis();
- List<WifiConfiguration> savedNetworks = mWifiConfigManager.getSavedNetworks();
- for (WifiConfiguration network : savedNetworks) {
- WifiConfiguration.NetworkSelectionStatus status = network.getNetworkSelectionStatus();
- if (network.networkId == selected.networkId) {
- if (status.getConnectChoice() != null) {
- localLog("Clear connection choice of " + status.getConnectChoice()
- + " Set Time: " + status.getConnectChoiceTimestamp() + " from "
- + getNetworkString(network));
- mWifiConfigManager.clearNetworkConnectChoice(network.networkId);
- change = true;
- }
- continue;
- }
-
- if (status.getSeenInLastQualifiedNetworkSelection()
- && (status.getConnectChoice() == null
- || !status.getConnectChoice().equals(key))) {
- localLog("Set connection choice of " + key + " Set Time: " + currentTime + " to "
- + getNetworkString(network));
- mWifiConfigManager.setNetworkConnectChoice(network.networkId, key, currentTime);
- change = true;
- }
- }
-
- return change;
- }
-
- /**
- * Enable/disable a BSSID for Quality Network Selection
- * When an association rejection event is obtained, Quality Network Selector will disable this
- * BSSID but supplicant still can try to connect to this bssid. If supplicant connect to it
- * successfully later, this bssid can be re-enabled.
- *
- * @param bssid the bssid to be enabled / disabled
- * @param enable -- true enable a bssid if it has been disabled
- * -- false disable a bssid
- */
- public boolean enableBssidForQualityNetworkSelection(String bssid, boolean enable) {
- if (enable) {
- return (mBssidBlacklist.remove(bssid) != null);
- } else {
- if (bssid != null) {
- BssidBlacklistStatus status = mBssidBlacklist.get(bssid);
- if (status == null) {
- // First time for this BSSID
- BssidBlacklistStatus newStatus = new BssidBlacklistStatus();
- newStatus.mCounter++;
- mBssidBlacklist.put(bssid, newStatus);
- } else if (!status.mIsBlacklisted) {
- status.mCounter++;
- if (status.mCounter >= BSSID_BLACKLIST_THRESHOLD) {
- status.mIsBlacklisted = true;
- status.mBlacklistedTimeStamp = mClock.getElapsedSinceBootMillis();
- return true;
- }
- }
- }
- }
- return false;
- }
-
- /**
- * Update the buffered BSSID blacklist
- *
- * Go through the whole buffered BSSIDs blacklist and check when the BSSIDs is blocked. If they
- * have been blacklisted for BSSID_BLACKLIST_EXPIRE_TIME_MS, re-enable them.
- */
- private void updateBssidBlacklist() {
- Iterator<BssidBlacklistStatus> iter = mBssidBlacklist.values().iterator();
- while (iter.hasNext()) {
- BssidBlacklistStatus status = iter.next();
- if (status != null && status.mIsBlacklisted) {
- if (mClock.getElapsedSinceBootMillis() - status.mBlacklistedTimeStamp
- >= BSSID_BLACKLIST_EXPIRE_TIME_MS) {
- iter.remove();
- }
- }
- }
- }
-
- /**
- * Check whether a bssid is disabled
- * @param bssid -- the bssid to check
- */
- public boolean isBssidDisabled(String bssid) {
- BssidBlacklistStatus status = mBssidBlacklist.get(bssid);
- return status == null ? false : status.mIsBlacklisted;
- }
-
- /**
- * Select the best network candidate from the new scan results for WifiConnectivityManager
- * to connect/roam to.
- *
- * @param forceSelectNetwork true -- start a qualified network selection anyway, no matter
- * the current network is already qualified or not.
- * false -- if current network is already qualified, stay connected
- * to it.
- * @param isUntrustedConnectionsAllowed connection to untrusted networks is allowed or not
- * @param isLinkDebouncing Link layer is under debouncing or not
- * @param isConnected WifiStateMachine is in the Connected state or not
- * @param isDisconnected WifiStateMachine is in the Disconnected state or not
- * @param isSupplicantTransient wpa_supplicant is in a transient state or not
- * @param scanDetails new connectivity scan results
- * @return Best network candidate identified. Null if no candidate available or we should
- * stay connected to the current network.
- */
- public WifiConfiguration selectQualifiedNetwork(boolean forceSelectNetwork,
- boolean isUntrustedConnectionsAllowed, boolean isLinkDebouncing,
- boolean isConnected, boolean isDisconnected, boolean isSupplicantTransient,
- List<ScanDetail> scanDetails) {
- localLog("==========start qualified Network Selection==========");
-
- List<Pair<ScanDetail, WifiConfiguration>> filteredScanDetails = new ArrayList<>();
-
- if (scanDetails.size() == 0) {
- localLog("Empty connectivity scan result");
- mFilteredScanDetails = filteredScanDetails;
- return null;
- }
-
- if (mCurrentConnectedNetwork == null) {
- mCurrentConnectedNetwork =
- mWifiConfigManager.getConfiguredNetwork(mWifiInfo.getNetworkId());
- }
-
- if (mCurrentBssid == null) {
- mCurrentBssid = mWifiInfo.getBSSID();
- }
-
- if (!forceSelectNetwork && !needQualifiedNetworkSelection(isLinkDebouncing, isConnected,
- isDisconnected, isSupplicantTransient)) {
- localLog("Stay connected to the current qualified network");
- mFilteredScanDetails = filteredScanDetails;
- return null;
- }
-
- int currentHighestScore = Integer.MIN_VALUE;
- ScanResult scanResultCandidate = null;
- WifiConfiguration networkCandidate = null;
- final ExternalScoreEvaluator externalScoreEvaluator =
- new ExternalScoreEvaluator(mLocalLog, mDbg);
- int lastUserSelectedNetWork = mWifiConfigManager.getLastSelectedNetwork();
- WifiConfiguration lastUserSelectedNetwork =
- mWifiConfigManager.getConfiguredNetwork(lastUserSelectedNetWork);
- if (lastUserSelectedNetwork != null) {
- localLog("Last selection is " + lastUserSelectedNetwork.SSID + " Time to now: "
- + ((mClock.getElapsedSinceBootMillis()
- - mWifiConfigManager.getLastSelectedTimeStamp()) / 1000 / 60 + " minutes"));
- }
-
- updateSavedNetworkSelectionStatus();
- updateBssidBlacklist();
-
- StringBuffer lowSignalScan = new StringBuffer();
- StringBuffer notSavedScan = new StringBuffer();
- StringBuffer noValidSsid = new StringBuffer();
- StringBuffer unwantedBand = new StringBuffer();
- StringBuffer scoreHistory = new StringBuffer();
- ArrayList<NetworkKey> unscoredNetworks = new ArrayList<NetworkKey>();
-
- // Iterate over all scan results to find the best candidate.
- for (ScanDetail scanDetail : scanDetails) {
- ScanResult scanResult = scanDetail.getScanResult();
- // Skip bad scan result.
- if (scanResult.SSID == null || TextUtils.isEmpty(scanResult.SSID)) {
- if (mDbg) {
- noValidSsid.append(scanResult.BSSID).append(" / ");
- }
- continue;
- }
-
- final String scanId = toScanId(scanResult);
- // Skip blacklisted BSSID.
- if (isBssidDisabled(scanResult.BSSID)) {
- Log.i(TAG, scanId + " is in the blacklist.");
- continue;
- }
-
- // Skip network with too weak signals.
- if ((scanResult.is24GHz() && scanResult.level < mThresholdMinimumRssi24)
- || (scanResult.is5GHz() && scanResult.level < mThresholdMinimumRssi5)) {
- if (mDbg) {
- lowSignalScan.append(scanId).append("(")
- .append(scanResult.is24GHz() ? "2.4GHz" : "5GHz")
- .append(")").append(scanResult.level).append(" / ");
- }
- continue;
- }
-
- // Skip network not matching band preference set by user.
- // WifiConnectivityManager schedules scan according to the user band prefrence. This is
- // a check for the ScanResults generated from the old settings.
- if ((scanResult.is24GHz()
- && (mUserPreferedBand == WifiManager.WIFI_FREQUENCY_BAND_5GHZ))
- || (scanResult.is5GHz()
- && (mUserPreferedBand == WifiManager.WIFI_FREQUENCY_BAND_2GHZ))) {
- if (mDbg) {
- unwantedBand.append(scanId).append("(")
- .append(scanResult.is24GHz() ? "2.4GHz" : "5GHz")
- .append(")").append(" / ");
- }
- continue;
- }
-
- // Is there a score for this network? If not, request a score.
- if (mNetworkScoreCache != null && !mNetworkScoreCache.isScoredNetwork(scanResult)) {
- WifiKey wifiKey;
- try {
- wifiKey = new WifiKey("\"" + scanResult.SSID + "\"", scanResult.BSSID);
- NetworkKey ntwkKey = new NetworkKey(wifiKey);
- // Add to the unscoredNetworks list so we can request score later
- unscoredNetworks.add(ntwkKey);
- } catch (IllegalArgumentException e) {
- Log.w(TAG, "Invalid SSID=" + scanResult.SSID + " BSSID=" + scanResult.BSSID
- + " for network score. Skip.");
- }
- }
-
- // Is this scan result from an ephemeral network?
- boolean potentiallyEphemeral = false;
- // Stores WifiConfiguration of potential connection candidates for scan result filtering
- WifiConfiguration potentialEphemeralCandidate = null;
- // TODO(b/31065385): WifiConfigManager does not support passpoint networks currently.
- // So this list has just one entry always.
- List<WifiConfiguration> associatedWifiConfigurations = null;
- WifiConfiguration associatedWifiConfiguration =
- mWifiConfigManager.getSavedNetworkForScanDetailAndCache(scanDetail);
- if (associatedWifiConfiguration != null) {
- associatedWifiConfigurations =
- new ArrayList<>(Arrays.asList(associatedWifiConfiguration));
- }
- if (associatedWifiConfigurations == null) {
- potentiallyEphemeral = true;
- if (mDbg) {
- notSavedScan.append(scanId).append(" / ");
- }
- } else if (associatedWifiConfigurations.size() == 1) {
- // If there is more than one associated network, it must be a passpoint network.
- WifiConfiguration network = associatedWifiConfigurations.get(0);
- if (network.ephemeral) {
- potentialEphemeralCandidate = network;
- potentiallyEphemeral = true;
- }
- }
-
- // Evaluate the potentially ephemeral network as a possible candidate if untrusted
- // connections are allowed and we have an external score for the scan result.
- if (potentiallyEphemeral) {
- if (isUntrustedConnectionsAllowed) {
- Integer netScore = getNetworkScore(scanResult, false);
- if (netScore != null
- && !mWifiConfigManager.wasEphemeralNetworkDeleted(scanResult.SSID)) {
- externalScoreEvaluator.evalUntrustedCandidate(netScore, scanResult);
- // scanDetail is for available ephemeral network
- filteredScanDetails.add(Pair.create(scanDetail,
- potentialEphemeralCandidate));
- }
- }
- continue;
- }
-
- // Calculate the score of each ScanResult whose associated network is not ephemeral.
- // One ScanResult can associated with more than one network, hence we calculate all
- // the scores and use the highest one as the ScanResult's score
- int highestScore = Integer.MIN_VALUE;
- int score;
- int candidateNetworkIdForThisScan = WifiConfiguration.INVALID_NETWORK_ID;
- WifiConfiguration potentialCandidate = null;
- for (WifiConfiguration network : associatedWifiConfigurations) {
- WifiConfiguration.NetworkSelectionStatus status =
- network.getNetworkSelectionStatus();
- if (potentialCandidate == null) {
- potentialCandidate = network;
- }
- if (!status.isNetworkEnabled()) {
- continue;
- } else if (network.BSSID != null && !network.BSSID.equals("any")
- && !network.BSSID.equals(scanResult.BSSID)) {
- // App has specified the only BSSID to connect for this
- // configuration. So only the matching ScanResult can be a candidate.
- localLog("Network " + getNetworkString(network) + " has specified BSSID "
- + network.BSSID + ". Skip " + scanResult.BSSID);
- continue;
- }
-
- // If the network is marked to use external scores then attempt to fetch the score.
- // These networks will not be considered alongside the other saved networks.
- if (network.useExternalScores) {
- Integer netScore = getNetworkScore(scanResult, false);
- externalScoreEvaluator.evalSavedCandidate(netScore, network, scanResult);
- continue;
- }
- boolean sameNetwork =
- mCurrentConnectedNetwork == null
- ? false
- : (mCurrentConnectedNetwork.networkId == network.networkId
- || network.isLinked(mCurrentConnectedNetwork));
- boolean sameBssid =
- mCurrentBssid == null
- ? false
- : mCurrentBssid.equals(scanResult.BSSID);
- boolean sameSelect =
- lastUserSelectedNetwork == null
- ? false
- : lastUserSelectedNetwork.networkId == network.networkId;
- score = calculateBssidScore(scanResult, network, sameNetwork, sameBssid, sameSelect,
- scoreHistory);
- if (score > highestScore) {
- highestScore = score;
- candidateNetworkIdForThisScan = network.networkId;
- potentialCandidate = network;
- }
-
- // Update the cached candidate.
- if (score > status.getCandidateScore() || (score == status.getCandidateScore()
- && status.getCandidate() != null
- && scanResult.level > status.getCandidate().level)) {
- mWifiConfigManager.setNetworkCandidateScanResult(
- candidateNetworkIdForThisScan, scanResult, score);
- }
- }
- // Create potential filteredScanDetail entry.
- filteredScanDetails.add(Pair.create(scanDetail, potentialCandidate));
-
- if (highestScore > currentHighestScore || (highestScore == currentHighestScore
- && scanResultCandidate != null
- && scanResult.level > scanResultCandidate.level)) {
- currentHighestScore = highestScore;
- scanResultCandidate = scanResult;
- mWifiConfigManager.setNetworkCandidateScanResult(
- candidateNetworkIdForThisScan, scanResultCandidate, currentHighestScore);
- // Reload the network config with the updated info.
- networkCandidate =
- mWifiConfigManager.getConfiguredNetwork(candidateNetworkIdForThisScan);
- }
- }
-
- mFilteredScanDetails = filteredScanDetails;
-
- // Kick the score manager if there is any unscored network.
- if (mScoreManager != null && unscoredNetworks.size() != 0) {
- NetworkKey[] unscoredNetworkKeys =
- unscoredNetworks.toArray(new NetworkKey[unscoredNetworks.size()]);
- mScoreManager.requestScores(unscoredNetworkKeys);
- }
-
- if (mDbg) {
- if (lowSignalScan.length() != 0) {
- localLog(lowSignalScan + " skipped due to low signal");
- }
- if (notSavedScan.length() != 0) {
- localLog(notSavedScan + " skipped due to not saved");
- }
- if (noValidSsid.length() != 0) {
- localLog(noValidSsid + " skipped due to invalid SSID");
- }
- if (unwantedBand.length() != 0) {
- localLog(unwantedBand + " skipped due to user band preference");
- }
- localLog(scoreHistory.toString());
- }
-
- // Traverse the whole user preference to choose the one user likes the most.
- if (scanResultCandidate != null) {
- WifiConfiguration tempConfig = networkCandidate;
- while (tempConfig.getNetworkSelectionStatus().getConnectChoice() != null) {
- String key = tempConfig.getNetworkSelectionStatus().getConnectChoice();
- tempConfig = mWifiConfigManager.getConfiguredNetwork(key);
- if (tempConfig != null) {
- WifiConfiguration.NetworkSelectionStatus tempStatus =
- tempConfig.getNetworkSelectionStatus();
- if (tempStatus.getCandidate() != null && tempStatus.isNetworkEnabled()) {
- scanResultCandidate = tempStatus.getCandidate();
- networkCandidate = tempConfig;
- }
- } else {
- // We should not come here in theory.
- localLoge("Connect choice: " + key + " has no corresponding saved config");
- break;
- }
- }
- localLog("After user choice adjustment, the final candidate is:"
- + getNetworkString(networkCandidate) + " : " + scanResultCandidate.BSSID);
- }
-
- // At this point none of the saved networks were good candidates so we fall back to
- // externally scored networks if any are available.
- if (scanResultCandidate == null) {
- localLog("Checking the externalScoreEvaluator for candidates...");
- networkCandidate =
- getExternalScoreCandidateNetwork(externalScoreEvaluator);
- if (networkCandidate != null) {
- scanResultCandidate = networkCandidate.getNetworkSelectionStatus().getCandidate();
- }
- }
-
- if (scanResultCandidate == null) {
- localLog("Can not find any suitable candidates");
- return null;
- }
-
- String currentAssociationId = mCurrentConnectedNetwork == null ? "Disconnected" :
- getNetworkString(mCurrentConnectedNetwork);
- String targetAssociationId = getNetworkString(networkCandidate);
- // TODO(b/31065385): In passpoint, saved configuration is initialized with a fake SSID.
- // Now update it with the real SSID from the scan result.
-
- mCurrentBssid = scanResultCandidate.BSSID;
- mCurrentConnectedNetwork = networkCandidate;
- mLastQualifiedNetworkSelectionTimeStamp = mClock.getElapsedSinceBootMillis();
- return networkCandidate;
- }
-
- /**
- * Returns the best candidate network according to the given ExternalScoreEvaluator.
- */
- @Nullable
- WifiConfiguration getExternalScoreCandidateNetwork(ExternalScoreEvaluator scoreEvaluator) {
- int candidateNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
- switch (scoreEvaluator.getBestCandidateType()) {
- case ExternalScoreEvaluator.BestCandidateType.UNTRUSTED_NETWORK:
- ScanResult untrustedScanResultCandidate =
- scoreEvaluator.getScanResultCandidate();
- WifiConfiguration unTrustedNetworkCandidate =
- ScanResultUtil.createNetworkFromScanResult(untrustedScanResultCandidate);
- // Mark this config as ephemeral so it isn't persisted.
- unTrustedNetworkCandidate.ephemeral = true;
- if (mNetworkScoreCache != null) {
- unTrustedNetworkCandidate.meteredHint =
- mNetworkScoreCache.getMeteredHint(untrustedScanResultCandidate);
- }
- NetworkUpdateResult result =
- mWifiConfigManager.addOrUpdateNetwork(
- unTrustedNetworkCandidate, Process.WIFI_UID);
- if (!result.isSuccess()) {
- Log.e(TAG, "Failed to add ephemeral network");
- break;
- }
- candidateNetworkId = result.getNetworkId();
- mWifiConfigManager.setNetworkCandidateScanResult(
- candidateNetworkId, untrustedScanResultCandidate, 0);
- localLog(String.format("new ephemeral candidate %s network ID:%d, "
- + "meteredHint=%b",
- toScanId(untrustedScanResultCandidate), candidateNetworkId,
- unTrustedNetworkCandidate.meteredHint));
- break;
-
- case ExternalScoreEvaluator.BestCandidateType.SAVED_NETWORK:
- ScanResult scanResultCandidate = scoreEvaluator.getScanResultCandidate();
- candidateNetworkId = scoreEvaluator.getSavedConfig().networkId;
- mWifiConfigManager.setNetworkCandidateScanResult(
- candidateNetworkId, scanResultCandidate, 0);
- localLog(String.format("new scored candidate %s network ID:%d",
- toScanId(scanResultCandidate), candidateNetworkId));
- break;
-
- case ExternalScoreEvaluator.BestCandidateType.NONE:
- localLog("ExternalScoreEvaluator did not see any good candidates.");
- break;
-
- default:
- localLoge("Unhandled ExternalScoreEvaluator case. No candidate selected.");
- break;
- }
- return mWifiConfigManager.getConfiguredNetwork(candidateNetworkId);
- }
-
- /**
- * Returns the available external network score or NULL if no score is available.
- *
- * @param scanResult The scan result of the network to score.
- * @param isActiveNetwork Whether or not the network is currently connected.
- * @return A valid external score if one is available or NULL.
- */
- @Nullable
- Integer getNetworkScore(ScanResult scanResult, boolean isActiveNetwork) {
- if (mNetworkScoreCache != null && mNetworkScoreCache.isScoredNetwork(scanResult)) {
- int networkScore = mNetworkScoreCache.getNetworkScore(scanResult, isActiveNetwork);
- localLog(toScanId(scanResult) + " has score: " + networkScore);
- return networkScore;
- }
- return null;
- }
-
- /**
- * Formats the given ScanResult as a scan ID for logging.
- */
- private static String toScanId(@Nullable ScanResult scanResult) {
- return scanResult == null ? "NULL"
- : String.format("%s:%s", scanResult.SSID, scanResult.BSSID);
- }
-
- // Dump the logs.
- void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("Dump of WifiQualifiedNetworkSelector");
- pw.println("WifiQualifiedNetworkSelector - Log Begin ----");
- mLocalLog.dump(fd, pw, args);
- pw.println("WifiQualifiedNetworkSelector - Log End ----");
- }
-
- /**
- * Used to track and evaluate networks that are assigned external scores.
- */
- static class ExternalScoreEvaluator {
- @Retention(RetentionPolicy.SOURCE)
- @interface BestCandidateType {
- int NONE = 0;
- int SAVED_NETWORK = 1;
- int UNTRUSTED_NETWORK = 2;
- }
- // Always set to the best known candidate.
- private @BestCandidateType int mBestCandidateType = BestCandidateType.NONE;
- private int mHighScore = WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
- private WifiConfiguration mSavedConfig;
- private ScanResult mScanResultCandidate;
- private final LocalLog mLocalLog;
- private final boolean mDbg;
-
- ExternalScoreEvaluator(LocalLog localLog, boolean dbg) {
- mLocalLog = localLog;
- mDbg = dbg;
- }
-
- // Determines whether or not the given scan result is the best one its seen so far.
- void evalUntrustedCandidate(@Nullable Integer score, ScanResult scanResult) {
- if (score != null && score > mHighScore) {
- mHighScore = score;
- mScanResultCandidate = scanResult;
- mBestCandidateType = BestCandidateType.UNTRUSTED_NETWORK;
- localLog(toScanId(scanResult) + " become the new untrusted candidate");
- }
- }
-
- // Determines whether or not the given saved network is the best one its seen so far.
- void evalSavedCandidate(@Nullable Integer score, WifiConfiguration config,
- ScanResult scanResult) {
- // Always take the highest score. If there's a tie and an untrusted network is currently
- // the best then pick the saved network.
- if (score != null
- && (score > mHighScore
- || (mBestCandidateType == BestCandidateType.UNTRUSTED_NETWORK
- && score == mHighScore))) {
- mHighScore = score;
- mSavedConfig = config;
- mScanResultCandidate = scanResult;
- mBestCandidateType = BestCandidateType.SAVED_NETWORK;
- localLog(toScanId(scanResult) + " become the new externally scored saved network "
- + "candidate");
- }
- }
-
- int getBestCandidateType() {
- return mBestCandidateType;
- }
-
- int getHighScore() {
- return mHighScore;
- }
-
- public ScanResult getScanResultCandidate() {
- return mScanResultCandidate;
- }
-
- WifiConfiguration getSavedConfig() {
- return mSavedConfig;
- }
-
- private void localLog(String log) {
- if (mDbg) {
- mLocalLog.log(log);
- }
- }
- }
-}
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index b96585ed5..69f8836fa 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -193,7 +193,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
private WifiConfigManager mWifiConfigManager;
private WifiSupplicantControl mWifiSupplicantControl;
private WifiConnectivityManager mWifiConnectivityManager;
- private WifiQualifiedNetworkSelector mWifiQualifiedNetworkSelector;
+ private WifiNetworkSelector mWifiNetworkSelector;
private INetworkManagementService mNwService;
private IWificond mWificond;
private IClientInterface mClientInterface;
@@ -879,8 +879,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mWifiDiagnostics = mWifiInjector.makeWifiDiagnostics(mWifiNative);
mWifiInfo = new WifiInfo();
- mWifiQualifiedNetworkSelector = new WifiQualifiedNetworkSelector(mWifiConfigManager,
- mContext, mWifiInfo, mWifiInjector.getClock());
+ mWifiNetworkSelector = new WifiNetworkSelector(mContext, mWifiConfigManager,
+ mWifiInfo, mWifiInjector.getClock());
mSupplicantStateTracker =
mFacade.makeSupplicantStateTracker(context, mWifiConfigManager, getHandler());
@@ -1178,10 +1178,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mWifiNative.enableVerboseLogging(verbose);
mWifiConfigManager.enableVerboseLogging(verbose);
mSupplicantStateTracker.enableVerboseLogging(verbose);
- mWifiQualifiedNetworkSelector.enableVerboseLogging(verbose);
- if (mWifiConnectivityManager != null) {
- mWifiConnectivityManager.enableVerboseLogging(verbose);
- }
}
private static final String SYSTEM_PROPERTY_LOG_CONTROL_WIFIHAL = "log.tag.WifiHAL";
@@ -2137,11 +2133,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
pw.println();
mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_USER_ACTION);
mWifiDiagnostics.dump(fd, pw, args);
- mWifiQualifiedNetworkSelector.dump(fd, pw, args);
dumpIpManager(fd, pw, args);
- if (mWifiConnectivityManager != null) {
- mWifiConnectivityManager.dump(fd, pw, args);
- }
+ mWifiNetworkSelector.dump(fd, pw, args);
}
public void handleUserSwitch(int userId) {
@@ -4169,7 +4162,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
synchronized (mWifiReqCountLock) {
mWifiConnectivityManager = new WifiConnectivityManager(mContext,
WifiStateMachine.this, mWifiScanner, mWifiConfigManager, mWifiInfo,
- mWifiQualifiedNetworkSelector, mWifiInjector,
+ mWifiNetworkSelector, mWifiInjector,
getHandler().getLooper(), hasConnectionRequests());
mWifiConnectivityManager.setUntrustedConnectionAllowed(mUntrustedReqCount > 0);
mWifiConnectivityManager.handleScreenStateChanged(mScreenOn);
@@ -6177,7 +6170,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
|| (lastRoam > 0 && lastRoam < 2000) /* unless driver is roaming */)
&& ((ScanResult.is24GHz(mWifiInfo.getFrequency())
&& mWifiInfo.getRssi() >
- WifiQualifiedNetworkSelector.QUALIFIED_RSSI_24G_BAND)
+ mThresholdQualifiedRssi5)
|| (ScanResult.is5GHz(mWifiInfo.getFrequency())
&& mWifiInfo.getRssi() >
mThresholdQualifiedRssi5))) {