summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandy Pan <zpan@google.com>2016-09-27 21:49:38 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2016-09-27 21:49:38 +0000
commit8ef24fce3bac0c107324d6f8592a1215772ab397 (patch)
tree038c66834e693f2782527042b84f3992c2886e3e
parente1103ae70435f0aac61d167aeada6f1862d5b907 (diff)
parent57c8c1165d5ea5c10cd96ea51652c11db7635302 (diff)
Merge changes from topic 'WifiNetworkSelector'
* changes: Unit tests for ExternalScoreEvaluator Unit tests for SavedNetworkEvaluator WifiNetworkSelector unit tests. WCM: unit tests Wifi Network Selector
-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
-rw-r--r--tests/wifitests/src/com/android/server/wifi/ExternalScoreEvaluatorTest.java419
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SavedNetworkEvaluatorTest.java323
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java32
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java491
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTestUtil.java367
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java2299
12 files changed, 3008 insertions, 3601 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))) {
diff --git a/tests/wifitests/src/com/android/server/wifi/ExternalScoreEvaluatorTest.java b/tests/wifitests/src/com/android/server/wifi/ExternalScoreEvaluatorTest.java
new file mode 100644
index 000000000..16bd4f8d8
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/ExternalScoreEvaluatorTest.java
@@ -0,0 +1,419 @@
+/*
+ * 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 static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_NONE;
+import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_PSK;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import android.app.test.MockAnswerUtil.AnswerWithArguments;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.INetworkScoreCache;
+import android.net.NetworkScoreManager;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.os.SystemClock;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.R;
+import com.android.server.wifi.WifiNetworkSelectorTestUtil.ScanDetailsAndWifiConfigs;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.ExternalScoreEvaluator}.
+ */
+@SmallTest
+public class ExternalScoreEvaluatorTest {
+
+ /** Sets up test. */
+ @Before
+ public void setUp() throws Exception {
+ mResource = getResource();
+ mScoreManager = getScoreManager();
+ mContext = getContext();
+ mWifiConfigManager = getWifiConfigManager();
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime());
+
+ mThresholdQualifiedRssi2G = mResource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
+ mThresholdQualifiedRssi5G = mResource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz);
+
+ mExternalScoreEvaluator = new ExternalScoreEvaluator(mContext, mWifiConfigManager,
+ mClock, null);
+ }
+
+ /** Cleans up test. */
+ @After
+ public void cleanup() {
+ validateMockitoUsage();
+ }
+
+ private ExternalScoreEvaluator mExternalScoreEvaluator;
+ private WifiConfigManager mWifiConfigManager;
+ private Context mContext;
+ private Resources mResource;
+ private NetworkScoreManager mScoreManager;
+ private WifiNetworkScoreCache mScoreCache;
+ private Clock mClock = mock(Clock.class);
+ private int mThresholdQualifiedRssi2G;
+ private int mThresholdQualifiedRssi5G;
+ private static final String TAG = "External Score Evaluator Unit Test";
+
+ NetworkScoreManager getScoreManager() {
+ NetworkScoreManager scoreManager = mock(NetworkScoreManager.class);
+
+ doAnswer(new AnswerWithArguments() {
+ public void answer(int networkType, INetworkScoreCache scoreCache) {
+ mScoreCache = (WifiNetworkScoreCache) scoreCache;
+ }}).when(scoreManager).registerNetworkScoreCache(anyInt(), anyObject());
+
+ return scoreManager;
+ }
+
+ Context getContext() {
+ Context context = mock(Context.class);
+
+ when(context.getResources()).thenReturn(mResource);
+ when(context.getSystemService(Context.NETWORK_SCORE_SERVICE)).thenReturn(mScoreManager);
+
+ return context;
+ }
+
+ Resources getResource() {
+ Resources resource = mock(Resources.class);
+
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz))
+ .thenReturn(-70);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz))
+ .thenReturn(-73);
+
+ return resource;
+ }
+
+ WifiConfigManager getWifiConfigManager() {
+ WifiConfigManager wifiConfigManager = mock(WifiConfigManager.class);
+ when(wifiConfigManager.getLastSelectedNetwork())
+ .thenReturn(WifiConfiguration.INVALID_NETWORK_ID);
+ return wifiConfigManager;
+ }
+
+
+ /**
+ * When no saved networks available, choose the available ephemeral networks
+ * if untrusted networks are allowed.
+ */
+ @Test
+ public void chooseEphemeralNetworkBecauseOfNoSavedNetwork() {
+ String[] ssids = {"\"test1\"", "\"test2\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] freqs = {2470, 2437};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[ESS]"};
+ int[] levels = {mThresholdQualifiedRssi2G + 8, mThresholdQualifiedRssi2G + 10};
+ Integer[] scores = {null, 120};
+ boolean[] meteredHints = {false, true};
+
+ List<ScanDetail> scanDetails = WifiNetworkSelectorTestUtil.buildScanDetails(
+ ssids, bssids, freqs, caps, levels, mClock);
+ WifiNetworkSelectorTestUtil.configureScoreCache(mScoreCache,
+ scanDetails, scores, meteredHints);
+
+ // No saved networks.
+ when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(any(ScanDetail.class)))
+ .thenReturn(null);
+
+ ScanResult scanResult = scanDetails.get(1).getScanResult();
+ WifiConfiguration ephemeralNetworkConfig = WifiNetworkSelectorTestUtil
+ .setupEphemeralNetwork(mWifiConfigManager, 1, scanResult, meteredHints[1]);
+
+ // Untrusted networks allowed.
+ WifiConfiguration candidate = mExternalScoreEvaluator.evaluateNetworks(scanDetails,
+ null, null, false, true, null);
+
+ WifiConfigurationTestUtil.assertConfigurationEqual(ephemeralNetworkConfig, candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ scanResult, candidate);
+ assertEquals(meteredHints[1], candidate.meteredHint);
+ }
+
+ /**
+ * When no saved networks available, choose the highest scored ephemeral networks
+ * if untrusted networks are allowed.
+ */
+ @Test
+ public void chooseHigherScoredEphemeralNetwork() {
+ String[] ssids = {"\"test1\"", "\"test2\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] freqs = {2470, 2437};
+ String[] caps = {"[ESS]", "[ESS]"};
+ int[] levels = {mThresholdQualifiedRssi2G + 8, mThresholdQualifiedRssi2G + 8};
+ Integer[] scores = {100, 120};
+ boolean[] meteredHints = {true, true};
+ ScanResult[] scanResults = new ScanResult[2];
+ WifiConfiguration[] ephemeralNetworkConfigs = new WifiConfiguration[2];
+
+ List<ScanDetail> scanDetails = WifiNetworkSelectorTestUtil.buildScanDetails(
+ ssids, bssids, freqs, caps, levels, mClock);
+ WifiNetworkSelectorTestUtil.configureScoreCache(mScoreCache,
+ scanDetails, scores, meteredHints);
+
+ // No saved networks.
+ when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(any(ScanDetail.class)))
+ .thenReturn(null);
+
+ for (int i = 0; i < 2; i++) {
+ scanResults[i] = scanDetails.get(i).getScanResult();
+ ephemeralNetworkConfigs[i] = WifiNetworkSelectorTestUtil
+ .setupEphemeralNetwork(mWifiConfigManager, i, scanResults[i], meteredHints[i]);
+ }
+
+ WifiConfiguration candidate = mExternalScoreEvaluator.evaluateNetworks(scanDetails,
+ null, null, false, true, null);
+
+ WifiConfigurationTestUtil.assertConfigurationEqual(ephemeralNetworkConfigs[1], candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ scanResults[1], candidate);
+ assertEquals(meteredHints[1], candidate.meteredHint);
+ }
+
+ /**
+ * Don't choose available ephemeral networks if no saved networks and untrusted networks
+ * are not allowed.
+ */
+ @Test
+ public void noEphemeralNetworkWhenUntrustedNetworksNotAllowed() {
+ String[] ssids = {"\"test1\"", "\"test2\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] freqs = {2470, 2437};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[ESS]"};
+ int[] levels = {mThresholdQualifiedRssi2G + 8, mThresholdQualifiedRssi2G + 10};
+ Integer[] scores = {null, 120};
+ boolean[] meteredHints = {false, true};
+
+ List<ScanDetail> scanDetails = WifiNetworkSelectorTestUtil.buildScanDetails(
+ ssids, bssids, freqs, caps, levels, mClock);
+ WifiNetworkSelectorTestUtil.configureScoreCache(mScoreCache,
+ scanDetails, scores, meteredHints);
+
+ // No saved networks.
+ when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(any(ScanDetail.class)))
+ .thenReturn(null);
+
+ ScanResult scanResult = scanDetails.get(1).getScanResult();
+ WifiConfiguration ephemeralNetworkConfig = WifiNetworkSelectorTestUtil
+ .setupEphemeralNetwork(mWifiConfigManager, 1, scanResult, meteredHints[1]);
+
+ // Untursted networks not allowed.
+ WifiConfiguration candidate = mExternalScoreEvaluator.evaluateNetworks(scanDetails,
+ null, null, false, false, null);
+
+ assertEquals("Expect null configuration", null, candidate);
+ }
+
+
+ /**
+ * Choose externally scored saved network.
+ */
+ @Test
+ public void chooseSavedNetworkWithExternalScore() {
+ String[] ssids = {"\"test1\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3"};
+ int[] freqs = {5200};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]"};
+ int[] securities = {SECURITY_PSK};
+ int[] levels = {mThresholdQualifiedRssi5G + 8};
+ Integer[] scores = {120};
+ boolean[] meteredHints = {false};
+
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
+ savedConfigs[0].useExternalScores = true;
+
+ WifiNetworkSelectorTestUtil.configureScoreCache(mScoreCache,
+ scanDetails, scores, meteredHints);
+
+ WifiConfiguration candidate = mExternalScoreEvaluator.evaluateNetworks(scanDetails,
+ null, null, false, true, null);
+
+ WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ scanDetails.get(0).getScanResult(), candidate);
+ }
+
+ /**
+ * Choose externally scored saved network with higher score.
+ */
+ @Test
+ public void chooseSavedNetworkWithHigherExternalScore() {
+ String[] ssids = {"\"test1\"", "\"test2\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] freqs = {2470, 2437};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
+ int[] securities = {SECURITY_PSK, SECURITY_PSK};
+ int[] levels = {mThresholdQualifiedRssi2G + 8, mThresholdQualifiedRssi2G + 8};
+ Integer[] scores = {100, 120};
+ boolean[] meteredHints = {false, false};
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
+ savedConfigs[0].useExternalScores = savedConfigs[1].useExternalScores = true;
+
+ WifiNetworkSelectorTestUtil.configureScoreCache(mScoreCache,
+ scanDetails, scores, meteredHints);
+
+ WifiConfiguration candidate = mExternalScoreEvaluator.evaluateNetworks(scanDetails,
+ null, null, false, true, null);
+
+ WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ scanDetails.get(1).getScanResult(), candidate);
+ }
+
+ /**
+ * Prefer externally scored saved network over untrusted network when they have
+ * the same score.
+ */
+ @Test
+ public void chooseExternallyScoredSavedNetworkOverUntrustedNetworksWithSameScore() {
+ String[] ssids = {"\"test1\"", "\"test2\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] freqs = {2470, 2437};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[ESS]"};
+ int[] securities = {SECURITY_PSK, SECURITY_NONE};
+ int[] levels = {mThresholdQualifiedRssi2G + 8, mThresholdQualifiedRssi2G + 8};
+ Integer[] scores = {120, 120};
+ boolean[] meteredHints = {false, true};
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
+ savedConfigs[0].useExternalScores = true;
+
+ WifiNetworkSelectorTestUtil.configureScoreCache(mScoreCache,
+ scanDetails, scores, meteredHints);
+
+ WifiConfiguration candidate = mExternalScoreEvaluator.evaluateNetworks(scanDetails,
+ null, null, false, true, null);
+
+ WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ scanDetails.get(0).getScanResult(), candidate);
+ }
+
+ /**
+ * Choose untrusted network when it has higher score than the externally scored
+ * saved network.
+ */
+ @Test
+ public void chooseUntrustedNetworkWithHigherScoreThanExternallyScoredSavedNetwork() {
+ // Saved network.
+ String[] savedSsids = {"\"test1\""};
+ String[] savedBssids = {"6c:f3:7f:ae:8c:f3"};
+ int[] savedFreqs = {2470};
+ String[] savedCaps = {"[WPA2-EAP-CCMP][ESS]"};
+ int[] savedSecurities = {SECURITY_PSK};
+ int[] savedLevels = {mThresholdQualifiedRssi2G + 8};
+ // Ephemeral network.
+ String[] ephemeralSsids = {"\"test2\""};
+ String[] ephemeralBssids = {"6c:f3:7f:ae:8c:f4"};
+ int[] ephemeralFreqs = {2437};
+ String[] ephemeralCaps = {"[ESS]"};
+ int[] ephemeralLevels = {mThresholdQualifiedRssi2G + 8};
+ // Ephemeral network has higher score than the saved network.
+ Integer[] scores = {100, 120};
+ boolean[] meteredHints = {false, true};
+
+ // Set up the saved network.
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(savedSsids,
+ savedBssids, savedFreqs, savedCaps, savedLevels, savedSecurities,
+ mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
+ savedConfigs[0].useExternalScores = true;
+
+ // Set up the ephemeral network.
+ scanDetails.addAll(WifiNetworkSelectorTestUtil.buildScanDetails(
+ ephemeralSsids, ephemeralBssids, ephemeralFreqs,
+ ephemeralCaps, ephemeralLevels, mClock));
+ ScanResult ephemeralScanResult = scanDetails.get(1).getScanResult();
+ WifiConfiguration ephemeralNetworkConfig = WifiNetworkSelectorTestUtil
+ .setupEphemeralNetwork(mWifiConfigManager, 1, ephemeralScanResult,
+ meteredHints[1]);
+
+ // Set up score cache for both the saved network and the ephemeral network.
+ WifiNetworkSelectorTestUtil.configureScoreCache(mScoreCache,
+ scanDetails, scores, meteredHints);
+
+ WifiConfiguration candidate = mExternalScoreEvaluator.evaluateNetworks(scanDetails,
+ null, null, false, true, null);
+
+ WifiConfigurationTestUtil.assertConfigurationEqual(ephemeralNetworkConfig, candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ ephemeralScanResult, candidate);
+ }
+
+ /**
+ * Prefer externally scored saved network over untrusted network when they have
+ * the same score.
+ */
+ @Test
+ public void nullScoredNetworks() {
+ String[] ssids = {"\"test1\"", "\"test2\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] freqs = {2470, 2437};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[ESS]"};
+ int[] securities = {SECURITY_PSK, SECURITY_NONE};
+ int[] levels = {mThresholdQualifiedRssi2G + 8, mThresholdQualifiedRssi2G + 8};
+ Integer[] scores = {null, null};
+ boolean[] meteredHints = {false, true};
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
+ savedConfigs[0].useExternalScores = true;
+
+ WifiNetworkSelectorTestUtil.configureScoreCache(mScoreCache,
+ scanDetails, scores, meteredHints);
+
+ WifiConfiguration candidate = mExternalScoreEvaluator.evaluateNetworks(scanDetails,
+ null, null, false, true, null);
+
+ assertEquals("Expect null configuration", null, candidate);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/SavedNetworkEvaluatorTest.java b/tests/wifitests/src/com/android/server/wifi/SavedNetworkEvaluatorTest.java
new file mode 100644
index 000000000..fe290cd8a
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/SavedNetworkEvaluatorTest.java
@@ -0,0 +1,323 @@
+/*
+ * 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 static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_NONE;
+import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_PSK;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.os.SystemClock;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.R;
+import com.android.server.wifi.WifiNetworkSelectorTestUtil.ScanDetailsAndWifiConfigs;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.SavedNetworkEvaluator}.
+ */
+@SmallTest
+public class SavedNetworkEvaluatorTest {
+
+ /** Sets up test. */
+ @Before
+ public void setUp() throws Exception {
+ mResource = getResource();
+ mContext = getContext();
+ mWifiConfigManager = getWifiConfigManager();
+
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime());
+
+ mThresholdMinimumRssi2G = mResource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
+ mThresholdMinimumRssi5G = mResource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
+ mThresholdQualifiedRssi2G = mResource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
+ mThresholdQualifiedRssi5G = mResource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz);
+ mThresholdSaturatedRssi2G = mResource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz);
+ mThresholdSaturatedRssi5G = mResource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz);
+
+ mSavedNetworkEvaluator = new SavedNetworkEvaluator(mContext, mWifiConfigManager,
+ mClock, null);
+ }
+
+ /** Cleans up test. */
+ @After
+ public void cleanup() {
+ validateMockitoUsage();
+ }
+
+ private SavedNetworkEvaluator mSavedNetworkEvaluator;
+ private WifiConfigManager mWifiConfigManager;
+ private Context mContext;
+ private Resources mResource;
+ private Clock mClock = mock(Clock.class);
+ private int mThresholdMinimumRssi2G;
+ private int mThresholdMinimumRssi5G;
+ private int mThresholdQualifiedRssi2G;
+ private int mThresholdQualifiedRssi5G;
+ private int mThresholdSaturatedRssi2G;
+ private int mThresholdSaturatedRssi5G;
+ private static final String TAG = "Saved Network Evaluator Unit Test";
+
+ Context getContext() {
+ Context context = mock(Context.class);
+ Resources resource = mock(Resources.class);
+
+ when(context.getResources()).thenReturn(mResource);
+ return context;
+ }
+
+ Resources getResource() {
+ Resources resource = mock(Resources.class);
+
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz))
+ .thenReturn(-70);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz))
+ .thenReturn(-73);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz))
+ .thenReturn(-70);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz))
+ .thenReturn(-73);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz))
+ .thenReturn(-82);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz))
+ .thenReturn(-85);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_RSSI_SCORE_SLOPE))
+ .thenReturn(4);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_RSSI_SCORE_OFFSET))
+ .thenReturn(85);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_SAME_BSSID_AWARD))
+ .thenReturn(24);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_SECURITY_AWARD))
+ .thenReturn(80);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_5GHz_preference_boost_factor))
+ .thenReturn(16);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_current_network_boost))
+ .thenReturn(16);
+
+ return resource;
+ }
+
+ WifiConfigManager getWifiConfigManager() {
+ WifiConfigManager wifiConfigManager = mock(WifiConfigManager.class);
+ when(wifiConfigManager.getLastSelectedNetwork())
+ .thenReturn(WifiConfiguration.INVALID_NETWORK_ID);
+ return wifiConfigManager;
+ }
+
+
+ /**
+ * Between two 2G networks, choose the one with stronger RSSI value if other conditions
+ * are the same and the RSSI values are not satuarted.
+ */
+ @Test
+ public void chooseStrongerRssi2GNetwork() {
+ String[] ssids = {"\"test1\"", "\"test2\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] freqs = {2470, 2437};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {mThresholdQualifiedRssi2G + 8, mThresholdQualifiedRssi2G + 10};
+ int[] securities = {SECURITY_PSK, SECURITY_PSK};
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
+
+ WifiConfiguration candidate = mSavedNetworkEvaluator.evaluateNetworks(scanDetails,
+ null, null, true, false, null);
+
+ ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
+ WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ chosenScanResult, candidate);
+ }
+
+ /**
+ * Between two 5G networks, choose the one with stronger RSSI value if other conditions
+ * are the same and the RSSI values are not satuarted.
+ */
+ @Test
+ public void chooseStrongerRssi5GNetwork() {
+ String[] ssids = {"\"test1\"", "\"test2\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] freqs = {5200, 5240};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {mThresholdQualifiedRssi5G + 8, mThresholdQualifiedRssi5G + 10};
+ int[] securities = {SECURITY_PSK, SECURITY_PSK};
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
+
+ WifiConfiguration candidate = mSavedNetworkEvaluator.evaluateNetworks(scanDetails,
+ null, null, true, false, null);
+
+ ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
+ WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ chosenScanResult, candidate);
+ }
+
+ /**
+ * Choose secure network over open network if other conditions are the same.
+ */
+ @Test
+ public void chooseSecureNetworkOverOpenNetwork() {
+ String[] ssids = {"\"test1\"", "\"test2\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] freqs = {5200, 5240};
+ String[] caps = {"[ESS]", "[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {mThresholdQualifiedRssi5G, mThresholdQualifiedRssi5G};
+ int[] securities = {SECURITY_NONE, SECURITY_PSK};
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
+
+ WifiConfiguration candidate = mSavedNetworkEvaluator.evaluateNetworks(scanDetails,
+ null, null, true, false, null);
+
+ ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
+ WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ chosenScanResult, candidate);
+ }
+
+ /**
+ * Choose 5G network over 2G network if other conditions are the same.
+ */
+ @Test
+ public void choose5GNetworkOver2GNetwork() {
+ String[] ssids = {"\"test1\"", "\"test2\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] freqs = {2437, 5240};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {mThresholdQualifiedRssi2G, mThresholdQualifiedRssi5G};
+ int[] securities = {SECURITY_PSK, SECURITY_PSK};
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
+
+ WifiConfiguration candidate = mSavedNetworkEvaluator.evaluateNetworks(scanDetails,
+ null, null, true, false, null);
+
+ ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
+ WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ chosenScanResult, candidate);
+ }
+
+ /**
+ * Verify that we stick to the currently connected network if the other one is
+ * just slightly better scored.
+ */
+ @Test
+ public void stickToCurrentNetwork() {
+ String[] ssids = {"\"test1\"", "\"test2\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] freqs = {5200, 5240};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
+ // test2 has slightly stronger RSSI value than test1
+ int[] levels = {mThresholdMinimumRssi5G + 2, mThresholdMinimumRssi5G + 4};
+ int[] securities = {SECURITY_PSK, SECURITY_PSK};
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
+
+ // Simuluate we are connected to SSID test1 already.
+ WifiConfiguration candidate = mSavedNetworkEvaluator.evaluateNetworks(scanDetails,
+ savedConfigs[0], null, true, false, null);
+
+ // Even though test2 has higher RSSI value, test1 is chosen because of the
+ // currently connected network bonus.
+ ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
+ WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ chosenScanResult, candidate);
+ }
+
+ /**
+ * Verify that we stick to the currently connected BSSID if the other one is
+ * just slightly better scored.
+ */
+ @Test
+ public void stickToCurrentBSSID() {
+ // Same SSID
+ String[] ssids = {"\"test1\"", "\"test1\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] freqs = {5200, 5240};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
+ // test2 has slightly stronger RSSI value than test1
+ int[] levels = {mThresholdMinimumRssi5G + 2, mThresholdMinimumRssi5G + 6};
+ int[] securities = {SECURITY_PSK, SECURITY_PSK};
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
+
+ // Simuluate we are connected to BSSID "6c:f3:7f:ae:8c:f3" already
+ WifiConfiguration candidate = mSavedNetworkEvaluator.evaluateNetworks(scanDetails,
+ null, bssids[0], true, false, null);
+
+ // Even though test2 has higher RSSI value, test1 is chosen because of the
+ // currently connected BSSID bonus.
+ ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
+ WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
index 84133acb7..c952f65ff 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
@@ -72,7 +72,7 @@ public class WifiConnectivityManagerTest {
mWifiConfigManager = mockWifiConfigManager();
mWifiInfo = getWifiInfo();
mWifiScanner = mockWifiScanner();
- mWifiQNS = mockWifiQualifiedNetworkSelector();
+ mWifiNS = mockWifiNetworkSelector();
mWifiConnectivityManager = createConnectivityManager();
mWifiConnectivityManager.setWifiEnabled(true);
when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime());
@@ -91,7 +91,7 @@ public class WifiConnectivityManagerTest {
private TestAlarmManager mAlarmManager;
private TestLooper mLooper = new TestLooper();
private WifiConnectivityManager mWifiConnectivityManager;
- private WifiQualifiedNetworkSelector mWifiQNS;
+ private WifiNetworkSelector mWifiNS;
private WifiStateMachine mWifiStateMachine;
private WifiScanner mWifiScanner;
private WifiConfigManager mWifiConfigManager;
@@ -117,10 +117,10 @@ public class WifiConnectivityManagerTest {
R.bool.config_wifi_framework_enable_associated_network_selection)).thenReturn(true);
when(resource.getInteger(
R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz))
- .thenReturn(WifiQualifiedNetworkSelector.RSSI_SATURATION_2G_BAND);
+ .thenReturn(-60);
when(resource.getInteger(
R.integer.config_wifi_framework_current_network_boost))
- .thenReturn(WifiQualifiedNetworkSelector.SAME_NETWORK_AWARD);
+ .thenReturn(16);
return resource;
}
@@ -197,8 +197,8 @@ public class WifiConnectivityManagerTest {
return stateMachine;
}
- WifiQualifiedNetworkSelector mockWifiQualifiedNetworkSelector() {
- WifiQualifiedNetworkSelector qns = mock(WifiQualifiedNetworkSelector.class);
+ WifiNetworkSelector mockWifiNetworkSelector() {
+ WifiNetworkSelector ns = mock(WifiNetworkSelector.class);
WifiConfiguration candidate = generateWifiConfig(
0, CANDIDATE_NETWORK_ID, CANDIDATE_SSID, false, true, null, null);
@@ -208,9 +208,9 @@ public class WifiConnectivityManagerTest {
candidateScanResult.BSSID = CANDIDATE_BSSID;
candidate.getNetworkSelectionStatus().setCandidate(candidateScanResult);
- when(qns.selectQualifiedNetwork(anyBoolean(), anyBoolean(), anyBoolean(),
- anyBoolean(), anyBoolean(), anyBoolean(), anyObject())).thenReturn(candidate);
- return qns;
+ when(ns.selectNetwork(anyObject(), anyBoolean(), anyBoolean(),
+ anyBoolean())).thenReturn(candidate);
+ return ns;
}
WifiInfo getWifiInfo() {
@@ -250,7 +250,7 @@ public class WifiConnectivityManagerTest {
WifiConnectivityManager createConnectivityManager() {
return new WifiConnectivityManager(mContext, mWifiStateMachine, mWifiScanner,
- mWifiConfigManager, mWifiInfo, mWifiQNS, mWifiInjector, mLooper.getLooper(), true);
+ mWifiConfigManager, mWifiInfo, mWifiNS, mWifiInjector, mLooper.getLooper(), true);
}
/**
@@ -490,9 +490,9 @@ public class WifiConnectivityManagerTest {
* because of their low RSSI values.
*/
@Test
- public void PnoRetryForLowRssiNetwork() {
- when(mWifiQNS.selectQualifiedNetwork(anyBoolean(), anyBoolean(), anyBoolean(),
- anyBoolean(), anyBoolean(), anyBoolean(), anyObject())).thenReturn(null);
+ public void pnoRetryForLowRssiNetwork() {
+ when(mWifiNS.selectNetwork(anyObject(), anyBoolean(), anyBoolean(),
+ anyBoolean())).thenReturn(null);
// Set screen to off
mWifiConnectivityManager.handleScreenStateChanged(false);
@@ -511,7 +511,7 @@ public class WifiConnectivityManagerTest {
.getLowRssiNetworkRetryDelay();
assertEquals(lowRssiNetworkRetryDelayStartValue * 2,
- lowRssiNetworkRetryDelayAfterPnoValue);
+ lowRssiNetworkRetryDelayAfterPnoValue);
}
/**
@@ -546,8 +546,8 @@ public class WifiConnectivityManagerTest {
@Test
public void watchdogBitePnoGoodIncrementsMetrics() {
// Qns returns no candidate after watchdog single scan.
- when(mWifiQNS.selectQualifiedNetwork(anyBoolean(), anyBoolean(), anyBoolean(),
- anyBoolean(), anyBoolean(), anyBoolean(), anyObject())).thenReturn(null);
+ when(mWifiNS.selectNetwork(anyObject(), anyBoolean(), anyBoolean(),
+ anyBoolean())).thenReturn(null);
// Set screen to off
mWifiConnectivityManager.handleScreenStateChanged(false);
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java
new file mode 100644
index 000000000..a03e17457
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java
@@ -0,0 +1,491 @@
+/*
+ * 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 static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_NONE;
+import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_PSK;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.NetworkScoreManager;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.os.SystemClock;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Pair;
+
+import com.android.internal.R;
+import com.android.server.wifi.WifiNetworkSelectorTestUtil.ScanDetailsAndWifiConfigs;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.WifiNetworkSelector}.
+ */
+@SmallTest
+public class WifiNetworkSelectorTest {
+
+ /** Sets up test. */
+ @Before
+ public void setUp() throws Exception {
+ mResource = getResource();
+ mContext = getContext();
+ mWifiConfigManager = getWifiConfigManager();
+ mWifiInfo = getWifiInfo();
+
+ mWifiNetworkSelector = new WifiNetworkSelector(mContext, mWifiConfigManager,
+ mWifiInfo, mClock);
+ mWifiNetworkSelector.registerNetworkEvaluator(mDummyEvaluator, 1);
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime());
+
+ mThresholdMinimumRssi2G = mResource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
+ mThresholdMinimumRssi5G = mResource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
+ mThresholdQualifiedRssi2G = mResource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
+ mThresholdQualifiedRssi5G = mResource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz);
+ }
+
+ /** Cleans up test. */
+ @After
+ public void cleanup() {
+ validateMockitoUsage();
+ }
+
+ /**
+ * All this dummy network evaluator does is to pick the very first network
+ * in the scan results.
+ */
+ public class DummyNetworkEvaluator implements WifiNetworkSelector.NetworkEvaluator {
+ private static final String NAME = "DummyNetworkEvaluator";
+ private WifiConfigManager mConfigManager;
+
+ /**
+ * Get the evaluator name.
+ */
+ public String getName() {
+ return NAME;
+ }
+
+ /**
+ * Update thee evaluator.
+ */
+ public void update(List<ScanDetail> scanDetails) {
+ }
+
+ /**
+ * Always return the first network in the scan results for connection.
+ */
+ public WifiConfiguration evaluateNetworks(List<ScanDetail> scanDetails,
+ WifiConfiguration currentNetwork, String currentBssid, boolean connected,
+ boolean untrustedNetworkAllowed,
+ List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks) {
+ ScanDetail scanDetail = scanDetails.get(0);
+ mWifiConfigManager.setNetworkCandidateScanResult(0, scanDetail.getScanResult(), 100);
+
+ return mWifiConfigManager.getSavedNetworkForScanDetailAndCache(scanDetail);
+ }
+ }
+
+ private WifiNetworkSelector mWifiNetworkSelector = null;
+ private DummyNetworkEvaluator mDummyEvaluator = new DummyNetworkEvaluator();
+ private WifiConfigManager mWifiConfigManager = null;
+ private Context mContext;
+ private Resources mResource;
+ private WifiInfo mWifiInfo;
+ private Clock mClock = mock(Clock.class);
+ private int mThresholdMinimumRssi2G;
+ private int mThresholdMinimumRssi5G;
+ private int mThresholdQualifiedRssi2G;
+ private int mThresholdQualifiedRssi5G;
+
+ Context getContext() {
+ Context context = mock(Context.class);
+ Resources resource = mock(Resources.class);
+
+ when(context.getResources()).thenReturn(mResource);
+ return context;
+ }
+
+ Resources getResource() {
+ Resources resource = mock(Resources.class);
+
+ when(resource.getBoolean(
+ R.bool.config_wifi_framework_enable_associated_network_selection)).thenReturn(true);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz))
+ .thenReturn(-70);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz))
+ .thenReturn(-73);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz))
+ .thenReturn(-82);
+ when(resource.getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz))
+ .thenReturn(-85);
+ return resource;
+ }
+
+ NetworkScoreManager getNetworkScoreManager() {
+ NetworkScoreManager networkScoreManager = mock(NetworkScoreManager.class);
+
+ return networkScoreManager;
+ }
+
+ WifiInfo getWifiInfo() {
+ WifiInfo wifiInfo = mock(WifiInfo.class);
+
+ // simulate a disconnected state
+ when(wifiInfo.is24GHz()).thenReturn(true);
+ when(wifiInfo.is5GHz()).thenReturn(false);
+ when(wifiInfo.getRssi()).thenReturn(-70);
+ when(wifiInfo.getNetworkId()).thenReturn(WifiConfiguration.INVALID_NETWORK_ID);
+ when(wifiInfo.getBSSID()).thenReturn(null);
+ return wifiInfo;
+ }
+
+ WifiConfigManager getWifiConfigManager() {
+ WifiConfigManager wifiConfigManager = mock(WifiConfigManager.class);
+ when(wifiConfigManager.getLastSelectedNetwork())
+ .thenReturn(WifiConfiguration.INVALID_NETWORK_ID);
+ return wifiConfigManager;
+ }
+
+
+ /**
+ * No network selection if scan result is empty.
+ *
+ * WifiStateMachine is in disconnected state.
+ * scanDetails is empty.
+ *
+ * Expected behavior: no network recommended by Network Selector
+ */
+ @Test
+ public void emptyScanResults() {
+ String[] ssids = new String[0];
+ String[] bssids = new String[0];
+ int[] freqs = new int[0];
+ String[] caps = new String[0];
+ int[] levels = new int[0];
+ int[] securities = new int[0];
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
+ false, true, false);
+ assertEquals("Expect null configuration", null, candidate);
+ }
+
+
+ /**
+ * No network selection if the RSSI values in scan result are too low.
+ *
+ * WifiStateMachine is in disconnected state.
+ * scanDetails contains a 2.4GHz and a 5GHz network, but both with RSSI lower than
+ * the threshold
+ *
+ * Expected behavior: no network recommended by Network Selector
+ */
+ @Test
+ public void verifyMinimumRssiThreshold() {
+ String[] ssids = {"\"test1\"", "\"test2\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] freqs = {2437, 5180};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {mThresholdMinimumRssi2G - 1, mThresholdMinimumRssi5G - 1};
+ int[] securities = {SECURITY_PSK, SECURITY_PSK};
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
+ false, true, false);
+ assertEquals("Expect null configuration", null, candidate);
+ }
+
+ /**
+ * No network selection if WiFi is connected and it is too short from last
+ * network selection.
+ *
+ * WifiStateMachine is in connected state.
+ * scanDetails contains two valid networks.
+ * Perform a network seletion right after the first one.
+ *
+ * Expected behavior: no network recommended by Network Selector
+ */
+ @Test
+ public void verifyMinimumTimeGapWhenConnected() {
+ String[] ssids = {"\"test1\"", "\"test2\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] freqs = {2437, 5180};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {mThresholdMinimumRssi2G + 1, mThresholdMinimumRssi5G + 1};
+ int[] securities = {SECURITY_PSK, SECURITY_PSK};
+
+ // Make a network selection.
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
+ false, true, false);
+
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
+ + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS - 2000);
+
+ // Do another network selection with WSM in CONNECTED state.
+ candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
+ true, false, false);
+
+ assertEquals("Expect null configuration", null, candidate);
+ }
+
+ /**
+ * Perform network selection if WiFi is disconnected even if it is too short from last
+ * network selection.
+ *
+ * WifiStateMachine is in disconnected state.
+ * scanDetails contains two valid networks.
+ * Perform a network seletion right after the first one.
+ *
+ * Expected behavior: the first network is recommended by Network Selector
+ */
+ @Test
+ public void verifyNoMinimumTimeGapWhenDisconnected() {
+ String[] ssids = {"\"test1\"", "\"test2\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] freqs = {2437, 5180};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {mThresholdMinimumRssi2G + 1, mThresholdMinimumRssi5G + 1};
+ int[] securities = {SECURITY_PSK, SECURITY_PSK};
+
+ // Make a network selection.
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
+ WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
+ false, true, false);
+
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
+ + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS - 2000);
+
+ // Do another network selection with WSM in DISCONNECTED state.
+ candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
+ false, true, false);
+
+ ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
+ WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ chosenScanResult, candidate);
+ }
+
+ /**
+ * No network selection if the currently connected on is already sufficient.
+ *
+ * WifiStateMachine is connected to a qualified (5G, secure, good RSSI) network.
+ * scanDetails contains a valid network.
+ * Perform a network seletion after the first one.
+ *
+ * Expected behavior: no network recommended by Network Selector
+ */
+ @Test
+ public void noNetworkSelectionWhenCurrentOneIsSufficient() {
+ String[] ssids = {"\"test1\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3"};
+ int[] freqs = {5180};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {mThresholdQualifiedRssi5G + 8};
+ int[] securities = {SECURITY_PSK};
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+
+ // connect to test1
+ mWifiNetworkSelector.selectNetwork(scanDetails, false, true, false);
+ when(mWifiInfo.getNetworkId()).thenReturn(0);
+ when(mWifiInfo.getBSSID()).thenReturn(bssids[0]);
+ when(mWifiInfo.is24GHz()).thenReturn(false);
+
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
+ + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS + 2000);
+
+ levels[0] = mThresholdQualifiedRssi5G + 20;
+ scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ scanDetails = scanDetailsAndConfigs.getScanDetails();
+
+ WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
+ true, false, false);
+ assertEquals("Expect null configuration", null, candidate);
+ }
+
+
+ /**
+ * New network selection is performed if the currently connected network
+ * band is 2G.
+ *
+ * WifiStateMachine is connected to a 2G network.
+ * scanDetails contains a valid networks.
+ * Perform a network seletion after the first one.
+ *
+ * Expected behavior: the first network is recommended by Network Selector
+ */
+ @Test
+ public void band2GNetworkIsNotSufficient() {
+ String[] ssids = {"\"test1\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3"};
+ int[] freqs = {2470};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {mThresholdQualifiedRssi2G + 8};
+ int[] securities = {SECURITY_PSK};
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
+
+ // connect to test1
+ mWifiNetworkSelector.selectNetwork(scanDetails, false, true, false);
+ when(mWifiInfo.getNetworkId()).thenReturn(0);
+ when(mWifiInfo.getBSSID()).thenReturn(bssids[0]);
+ when(mWifiInfo.is24GHz()).thenReturn(true);
+
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
+ + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS + 2000);
+
+ // Do another network selection.
+ WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
+ true, false, false);
+
+ ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
+ WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ chosenScanResult, candidate);
+ }
+
+
+ /**
+ * New network selection is performed if the currently connected network
+ * is a open one.
+ *
+ * WifiStateMachine is connected to a open network.
+ * scanDetails contains a valid networks.
+ * Perform a network seletion after the first one.
+ *
+ * Expected behavior: the first network is recommended by Network Selector
+ */
+ @Test
+ public void openNetworkIsNotSufficient() {
+ String[] ssids = {"\"test1\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3"};
+ int[] freqs = {5180};
+ String[] caps = {"[ESS]"};
+ int[] levels = {mThresholdQualifiedRssi5G + 8};
+ int[] securities = {SECURITY_NONE};
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
+
+ // connect to test1
+ mWifiNetworkSelector.selectNetwork(scanDetails, false, true, false);
+ when(mWifiInfo.getNetworkId()).thenReturn(0);
+ when(mWifiInfo.getBSSID()).thenReturn(bssids[0]);
+ when(mWifiInfo.is24GHz()).thenReturn(false);
+ when(mWifiInfo.is5GHz()).thenReturn(true);
+
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
+ + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS + 2000);
+
+ // Do another network selection.
+ WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
+ true, false, false);
+
+ ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
+ WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ chosenScanResult, candidate);
+ }
+
+ /**
+ * New network selection is performed if the currently connected network
+ * has low RSSI value.
+ *
+ * WifiStateMachine is connected to a low RSSI 5GHz network.
+ * scanDetails contains a valid networks.
+ * Perform a network seletion after the first one.
+ *
+ * Expected behavior: the first network is recommended by Network Selector
+ */
+ @Test
+ public void lowRssi5GNetworkIsNotSufficient() {
+ String[] ssids = {"\"test1\""};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3"};
+ int[] freqs = {5180};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {mThresholdQualifiedRssi5G - 2};
+ int[] securities = {SECURITY_PSK};
+
+ ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
+ WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
+ freqs, caps, levels, securities, mWifiConfigManager, mClock);
+ List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
+ WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
+
+ // connect to test1
+ mWifiNetworkSelector.selectNetwork(scanDetails, false, true, false);
+ when(mWifiInfo.getNetworkId()).thenReturn(0);
+ when(mWifiInfo.getBSSID()).thenReturn(bssids[0]);
+ when(mWifiInfo.is24GHz()).thenReturn(false);
+ when(mWifiInfo.is5GHz()).thenReturn(true);
+ when(mWifiInfo.getRssi()).thenReturn(levels[0]);
+
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
+ + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS + 2000);
+
+ // Do another network selection.
+ WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
+ true, false, false);
+
+ ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
+ WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
+ WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
+ chosenScanResult, candidate);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTestUtil.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTestUtil.java
new file mode 100644
index 000000000..db3aff14c
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTestUtil.java
@@ -0,0 +1,367 @@
+/*
+ * 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 static com.android.server.wifi.WifiConfigurationTestUtil.generateWifiConfig;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import android.app.test.MockAnswerUtil.AnswerWithArguments;
+import android.net.NetworkKey;
+import android.net.RssiCurve;
+import android.net.ScoredNetwork;
+import android.net.WifiKey;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
+import android.net.wifi.WifiSsid;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
+
+import com.android.server.wifi.util.ScanResultUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper for WifiNetworkSelector unit tests.
+ */
+@SmallTest
+public class WifiNetworkSelectorTestUtil {
+
+ /**
+ * A class that holds a list of scanDetail and their associated WifiConfiguration.
+ */
+ public static class ScanDetailsAndWifiConfigs {
+ List<ScanDetail> mScanDetails;
+ WifiConfiguration[] mWifiConfigs;
+
+ ScanDetailsAndWifiConfigs(List<ScanDetail> scanDetails, WifiConfiguration[] configs) {
+ mScanDetails = scanDetails;
+ mWifiConfigs = configs;
+ }
+
+ List<ScanDetail> getScanDetails() {
+ return mScanDetails;
+ }
+
+ WifiConfiguration[] getWifiConfigs() {
+ return mWifiConfigs;
+ }
+ }
+
+ /**
+ * Build a list of ScanDetail based on the caller supplied network SSID, BSSID,
+ * frequency, capability and RSSI level information. Create the corresponding
+ * WifiConfiguration for these networks and set up the mocked WifiConfigManager.
+ *
+ * @param ssids an array of SSIDs
+ * @param bssids an array of BSSIDs
+ * @param freqs an array of the network's frequency
+ * @param caps an array of the network's capability
+ * @param levels an array of the network's RSSI levels
+ * @param securities an array of the network's security setting
+ * @param wifiConfigManager the mocked WifiConfigManager
+ * @return the constructed ScanDetail list and WifiConfiguration array
+ */
+ public static ScanDetailsAndWifiConfigs setupScanDetailsAndConfigStore(String[] ssids,
+ String[] bssids, int[] freqs, String[] caps, int[] levels, int[] securities,
+ WifiConfigManager wifiConfigManager, Clock clock) {
+ List<ScanDetail> scanDetails = buildScanDetails(ssids, bssids, freqs, caps, levels, clock);
+ WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, securities);
+ prepareConfigStore(wifiConfigManager, savedConfigs);
+ scanResultLinkConfiguration(wifiConfigManager, savedConfigs, scanDetails);
+
+ return new ScanDetailsAndWifiConfigs(scanDetails, savedConfigs);
+ }
+
+ /**
+ * Verify whether the WifiConfiguration chosen by WifiNetworkSelector matches
+ * with the chosen scan result.
+ *
+ * @param chosenScanResult the chosen scan result
+ * @param chosenCandidate the chosen configuration
+ */
+ public static void verifySelectedScanResult(WifiConfigManager wifiConfigManager,
+ ScanResult chosenScanResult, WifiConfiguration chosenCandidate) {
+ verify(wifiConfigManager, atLeastOnce()).setNetworkCandidateScanResult(
+ eq(chosenCandidate.networkId), eq(chosenScanResult), anyInt());
+ }
+
+
+ /**
+ * Build a list of scanDetails based on the caller supplied network SSID, BSSID,
+ * frequency, capability and RSSI level information.
+ *
+ * @param ssids an array of SSIDs
+ * @param bssids an array of BSSIDs
+ * @param freqs an array of the network's frequency
+ * @param caps an array of the network's capability
+ * @param levels an array of the network's RSSI levels
+ * @return the constructed list of ScanDetail
+ */
+ public static List<ScanDetail> buildScanDetails(String[] ssids, String[] bssids, int[] freqs,
+ String[] caps, int[] levels, Clock clock) {
+ List<ScanDetail> scanDetailList = new ArrayList<ScanDetail>();
+
+ long timeStamp = clock.getElapsedSinceBootMillis();
+ for (int index = 0; index < ssids.length; index++) {
+ ScanDetail scanDetail = new ScanDetail(WifiSsid.createFromAsciiEncoded(ssids[index]),
+ bssids[index], caps[index], levels[index], freqs[index], timeStamp, 0);
+ scanDetailList.add(scanDetail);
+ }
+ return scanDetailList;
+ }
+
+
+ /**
+ * Generate an array of {@link android.net.wifi.WifiConfiguration} based on the caller
+ * supplied network SSID and sencurity information.
+ *
+ * @param ssids an array of SSIDs
+ * @param securities an array of the network's security setting
+ * @return the constructed array of {@link android.net.wifi.WifiConfiguration}
+ */
+ public static WifiConfiguration[] generateWifiConfigurations(String[] ssids,
+ int[] securities) {
+ if (ssids == null || securities == null || ssids.length != securities.length
+ || ssids.length == 0) {
+ return null;
+ }
+
+ WifiConfiguration[] configs = new WifiConfiguration[ssids.length];
+ for (int index = 0; index < ssids.length; index++) {
+ configs[index] = generateWifiConfig(index, 0, ssids[index], false, true, null, null,
+ securities[index]);
+ }
+
+ return configs;
+ }
+
+ /**
+ * Add the Configurations to WifiConfigManager (WifiConfigureStore can take them out according
+ * to the networkd ID) and setup the WifiConfigManager mocks for these networks.
+ * This simulates the WifiConfigManager class behaviour.
+ *
+ * @param wifiConfigManager the mocked WifiConfigManager
+ * @param configs input configuration need to be added to WifiConfigureStore
+ */
+ private static void prepareConfigStore(WifiConfigManager wifiConfigManager,
+ final WifiConfiguration[] configs) {
+ when(wifiConfigManager.getConfiguredNetwork(anyInt()))
+ .then(new AnswerWithArguments() {
+ public WifiConfiguration answer(int netId) {
+ if (netId >= 0 && netId < configs.length) {
+ return new WifiConfiguration(configs[netId]);
+ } else {
+ return null;
+ }
+ }
+ });
+ when(wifiConfigManager.getConfiguredNetwork(anyString()))
+ .then(new AnswerWithArguments() {
+ public WifiConfiguration answer(String configKey) {
+ for (int netId = 0; netId < configs.length; netId++) {
+ if (TextUtils.equals(configs[netId].configKey(), configKey)) {
+ return new WifiConfiguration(configs[netId]);
+ }
+ }
+ return null;
+ }
+ });
+ when(wifiConfigManager.getSavedNetworks())
+ .then(new AnswerWithArguments() {
+ public List<WifiConfiguration> answer() {
+ List<WifiConfiguration> savedNetworks = new ArrayList<>();
+ for (int netId = 0; netId < configs.length; netId++) {
+ savedNetworks.add(new WifiConfiguration(configs[netId]));
+ }
+ return savedNetworks;
+ }
+ });
+ when(wifiConfigManager.clearNetworkCandidateScanResult(anyInt()))
+ .then(new AnswerWithArguments() {
+ public boolean answer(int netId) {
+ if (netId >= 0 && netId < configs.length) {
+ configs[netId].getNetworkSelectionStatus().setCandidate(null);
+ configs[netId].getNetworkSelectionStatus()
+ .setCandidateScore(Integer.MIN_VALUE);
+ configs[netId].getNetworkSelectionStatus()
+ .setSeenInLastQualifiedNetworkSelection(false);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ });
+ when(wifiConfigManager.setNetworkCandidateScanResult(
+ anyInt(), any(ScanResult.class), anyInt()))
+ .then(new AnswerWithArguments() {
+ public boolean answer(int netId, ScanResult scanResult, int score) {
+ if (netId >= 0 && netId < configs.length) {
+ configs[netId].getNetworkSelectionStatus().setCandidate(scanResult);
+ configs[netId].getNetworkSelectionStatus().setCandidateScore(score);
+ configs[netId].getNetworkSelectionStatus()
+ .setSeenInLastQualifiedNetworkSelection(true);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ });
+ when(wifiConfigManager.clearNetworkConnectChoice(anyInt()))
+ .then(new AnswerWithArguments() {
+ public boolean answer(int netId) {
+ if (netId >= 0 && netId < configs.length) {
+ configs[netId].getNetworkSelectionStatus().setConnectChoice(null);
+ configs[netId].getNetworkSelectionStatus()
+ .setConnectChoiceTimestamp(
+ NetworkSelectionStatus
+ .INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ });
+ when(wifiConfigManager.setNetworkConnectChoice(anyInt(), anyString(), anyLong()))
+ .then(new AnswerWithArguments() {
+ public boolean answer(int netId, String configKey, long timestamp) {
+ if (netId >= 0 && netId < configs.length) {
+ configs[netId].getNetworkSelectionStatus().setConnectChoice(configKey);
+ configs[netId].getNetworkSelectionStatus().setConnectChoiceTimestamp(
+ timestamp);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ });
+ }
+
+
+ /**
+ * Link scan results to the saved configurations.
+ *
+ * The shorter of the 2 input params will be used to loop over so the inputs don't
+ * need to be of equal length. If there are more scan details then configs the remaining scan
+ * details will be associated with a NULL config.
+ *
+ * @param wifiConfigManager the mocked WifiConfigManager
+ * @param configs saved configurations
+ * @param scanDetails come in scan results
+ */
+ private static void scanResultLinkConfiguration(WifiConfigManager wifiConfigManager,
+ WifiConfiguration[] configs, List<ScanDetail> scanDetails) {
+ if (configs == null || scanDetails == null) {
+ return;
+ }
+
+ if (scanDetails.size() <= configs.length) {
+ for (int i = 0; i < scanDetails.size(); i++) {
+ ScanDetail scanDetail = scanDetails.get(i);
+ when(wifiConfigManager.getSavedNetworkForScanDetailAndCache(eq(scanDetail)))
+ .thenReturn(configs[i]);
+ }
+ } else {
+ for (int i = 0; i < configs.length; i++) {
+ ScanDetail scanDetail = scanDetails.get(i);
+ when(wifiConfigManager.getSavedNetworkForScanDetailAndCache(eq(scanDetail)))
+ .thenReturn(configs[i]);
+ }
+
+ // associated the remaining scan details with a NULL config.
+ for (int i = configs.length; i < scanDetails.size(); i++) {
+ when(wifiConfigManager.getSavedNetworkForScanDetailAndCache(
+ eq(scanDetails.get(i)))).thenReturn(null);
+ }
+ }
+ }
+
+
+
+ /**
+ * Configure the score cache for externally scored networks
+ *
+ * @param scoreCache Wifi network score cache to be configured
+ * @param scanDetails a list of ScanDetail
+ * @param scores scores of the networks
+ * @param meteredHints hints of if the networks are metered
+ */
+ public static void configureScoreCache(WifiNetworkScoreCache scoreCache,
+ List<ScanDetail> scanDetails, Integer[] scores, boolean[] meteredHints) {
+ List<ScoredNetwork> networks = new ArrayList<>();
+
+ for (int i = 0; i < scanDetails.size(); i++) {
+ ScanDetail scanDetail = scanDetails.get(i);
+ byte rssiScore;
+ Integer score = scores[i];
+ ScanResult scanResult = scanDetail.getScanResult();
+ WifiKey wifiKey = new WifiKey("\"" + scanResult.SSID + "\"", scanResult.BSSID);
+ NetworkKey ntwkKey = new NetworkKey(wifiKey);
+ if (scores[i] == null) {
+ rssiScore = WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
+ } else {
+ rssiScore = scores[i].byteValue();
+ }
+ RssiCurve rssiCurve = new RssiCurve(-100, 100, new byte[] {rssiScore});
+ ScoredNetwork scoredNetwork = new ScoredNetwork(ntwkKey, rssiCurve, meteredHints[i]);
+
+ networks.add(scoredNetwork);
+ }
+
+ scoreCache.updateScores(networks);
+ }
+
+ /**
+ * Setup WifiConfigManager mock for ephemeral networks.
+ *
+ * @param wifiConfigManager WifiConfigManager mock
+ * @param networkId ID of the ephemeral network
+ * @param scanResult scanResult of the ephemeral network
+ * @param meteredHint flag to indidate if the network has meteredHint
+ */
+ public static WifiConfiguration setupEphemeralNetwork(WifiConfigManager wifiConfigManager,
+ int networkId, ScanResult scanResult, boolean meteredHint) {
+ // Return the correct networkID for ephemeral network addition.
+ when(wifiConfigManager.addOrUpdateNetwork(any(WifiConfiguration.class), anyInt()))
+ .thenReturn(new NetworkUpdateResult(networkId));
+ final WifiConfiguration config = ScanResultUtil.createNetworkFromScanResult(scanResult);
+ config.networkId = networkId;
+ config.meteredHint = meteredHint;
+
+ when(wifiConfigManager.getConfiguredNetwork(eq(networkId)))
+ .then(new AnswerWithArguments() {
+ public WifiConfiguration answer(int netId) {
+ return new WifiConfiguration(config);
+ }
+ });
+ when(wifiConfigManager.setNetworkCandidateScanResult(
+ eq(networkId), any(ScanResult.class), anyInt()))
+ .then(new AnswerWithArguments() {
+ public boolean answer(int netId, ScanResult scanResult, int score) {
+ config.getNetworkSelectionStatus().setCandidate(scanResult);
+ config.getNetworkSelectionStatus().setCandidateScore(score);
+ config.getNetworkSelectionStatus()
+ .setSeenInLastQualifiedNetworkSelection(true);
+ return true;
+ }
+ });
+ return config;
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java b/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java
deleted file mode 100644
index c83400b93..000000000
--- a/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java
+++ /dev/null
@@ -1,2299 +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 static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_EAP;
-import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_NONE;
-import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_PSK;
-import static com.android.server.wifi.WifiConfigurationTestUtil.generateWifiConfig;
-
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.*;
-
-import android.app.test.MockAnswerUtil.AnswerWithArguments;
-import android.content.Context;
-import android.content.res.Resources;
-import android.net.NetworkScoreManager;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
-import android.net.wifi.WifiEnterpriseConfig;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiSsid;
-import android.os.SystemClock;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.text.TextUtils;
-import android.util.LocalLog;
-
-import com.android.internal.R;
-import com.android.server.wifi.util.ScanResultUtil;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * Unit tests for {@link com.android.server.wifi.WifiQualifiedNetworkSelector}.
- */
-@SmallTest
-public class WifiQualifiedNetworkSelectorTest {
-
- @Before
- public void setUp() throws Exception {
- mResource = getResource();
- mScoreManager = getNetworkScoreManager();
- mScoreCache = getScoreCache();
- mContext = getContext();
- mWifiConfigManager = getWifiConfigManager();
- mWifiInfo = getWifiInfo();
- mLocalLog = getLocalLog();
-
- mWifiQualifiedNetworkSelector = new WifiQualifiedNetworkSelector(mWifiConfigManager,
- mContext, mWifiInfo, mClock);
- mWifiQualifiedNetworkSelector.enableVerboseLogging(1);
- mWifiQualifiedNetworkSelector.setWifiNetworkScoreCache(mScoreCache);
- when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime());
- }
-
- @After
- public void cleanup() {
- validateMockitoUsage();
- }
-
- private WifiQualifiedNetworkSelector mWifiQualifiedNetworkSelector = null;
- private WifiConfigManager mWifiConfigManager = null;
- private Context mContext;
- private Resources mResource;
- private NetworkScoreManager mScoreManager;
- private WifiNetworkScoreCache mScoreCache;
- private WifiInfo mWifiInfo;
- private LocalLog mLocalLog;
- private Clock mClock = mock(Clock.class);
- private static final String[] DEFAULT_SSIDS = {"\"test1\"", "\"test2\""};
- private static final String[] DEFAULT_BSSIDS = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
- private static final String TAG = "QNS Unit Test";
-
- private List<ScanDetail> getScanDetails(String[] ssids, String[] bssids, int[] frequencies,
- String[] caps, int[] levels) {
- List<ScanDetail> scanDetailList = new ArrayList<ScanDetail>();
- long timeStamp = mClock.getElapsedSinceBootMillis();
- for (int index = 0; index < ssids.length; index++) {
- ScanDetail scanDetail = new ScanDetail(WifiSsid.createFromAsciiEncoded(ssids[index]),
- bssids[index], caps[index], levels[index], frequencies[index], timeStamp, 0);
- scanDetailList.add(scanDetail);
- }
- return scanDetailList;
- }
-
- Context getContext() {
- Context context = mock(Context.class);
- Resources resource = mock(Resources.class);
-
- when(context.getResources()).thenReturn(mResource);
- when(context.getSystemService(Context.NETWORK_SCORE_SERVICE)).thenReturn(mScoreManager);
- return context;
- }
-
- Resources getResource() {
- Resources resource = mock(Resources.class);
-
- when(resource.getInteger(R.integer.config_wifi_framework_SECURITY_AWARD)).thenReturn(80);
- when(resource.getInteger(R.integer.config_wifi_framework_RSSI_SCORE_OFFSET)).thenReturn(85);
- when(resource.getInteger(R.integer.config_wifi_framework_SAME_BSSID_AWARD)).thenReturn(24);
- when(resource.getInteger(R.integer.config_wifi_framework_LAST_SELECTION_AWARD))
- .thenReturn(480);
- when(resource.getInteger(R.integer.config_wifi_framework_PASSPOINT_SECURITY_AWARD))
- .thenReturn(40);
- when(resource.getInteger(R.integer.config_wifi_framework_SECURITY_AWARD)).thenReturn(80);
- when(resource.getInteger(R.integer.config_wifi_framework_RSSI_SCORE_SLOPE)).thenReturn(4);
- when(resource.getBoolean(
- R.bool.config_wifi_framework_enable_associated_network_selection)).thenReturn(true);
- when(resource.getInteger(
- R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz))
- .thenReturn(WifiQualifiedNetworkSelector.RSSI_SATURATION_2G_BAND);
- when(resource.getInteger(
- R.integer.config_wifi_framework_current_network_boost))
- .thenReturn(WifiQualifiedNetworkSelector.SAME_NETWORK_AWARD);
- when(resource.getInteger(
- R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz))
- .thenReturn(WifiQualifiedNetworkSelector.RSSI_SATURATION_2G_BAND);
- when(resource.getInteger(
- R.integer.config_wifi_framework_5GHz_preference_boost_factor))
- .thenReturn(WifiQualifiedNetworkSelector.BAND_AWARD_5GHz);
- when(resource.getInteger(
- R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz))
- .thenReturn(WifiQualifiedNetworkSelector.QUALIFIED_RSSI_5G_BAND);
- when(resource.getInteger(
- R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz))
- .thenReturn(WifiQualifiedNetworkSelector.MINIMUM_5G_ACCEPT_RSSI);
- when(resource.getInteger(
- R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz))
- .thenReturn(WifiQualifiedNetworkSelector.MINIMUM_2G_ACCEPT_RSSI);
- return resource;
- }
-
- NetworkScoreManager getNetworkScoreManager() {
- NetworkScoreManager networkScoreManager = mock(NetworkScoreManager.class);
-
- return networkScoreManager;
- }
-
- WifiNetworkScoreCache getScoreCache() {
- return mock(WifiNetworkScoreCache.class);
- }
-
- LocalLog getLocalLog() {
- return new LocalLog(0);
- }
-
- WifiInfo getWifiInfo() {
- WifiInfo wifiInfo = mock(WifiInfo.class);
-
- //simulate a disconnected state
- when(wifiInfo.is24GHz()).thenReturn(true);
- when(wifiInfo.is5GHz()).thenReturn(false);
- when(wifiInfo.getRssi()).thenReturn(-70);
- when(wifiInfo.getNetworkId()).thenReturn(WifiConfiguration.INVALID_NETWORK_ID);
- when(wifiInfo.getBSSID()).thenReturn(null);
- when(wifiInfo.getNetworkId()).thenReturn(-1);
- return wifiInfo;
- }
-
- WifiConfigManager getWifiConfigManager() {
- WifiConfigManager wifiConfigManager = mock(WifiConfigManager.class);
- when(wifiConfigManager.getLastSelectedNetwork())
- .thenReturn(WifiConfiguration.INVALID_NETWORK_ID);
- return wifiConfigManager;
- }
-
- /**
- * This API is used to generate multiple simulated saved configurations used for test
- *
- * @param ssid array of SSID of saved configuration
- * @param security array of securities of saved configuration
- * @return generated new array of configurations based on input
- */
- private WifiConfiguration[] generateWifiConfigurations(String[] ssid, int[] security) {
- if (ssid == null || security == null || ssid.length != security.length
- || ssid.length == 0) {
- return null;
- }
-
- WifiConfiguration[] configs = new WifiConfiguration[ssid.length];
- for (int index = 0; index < ssid.length; index++) {
- configs[index] = generateWifiConfig(index, 0, ssid[index], false, true, null, null,
- security[index]);
- }
-
- return configs;
- }
-
- /**
- * set configuration to a passpoint configuration
- *
- * @param config The configuration need to be set as a passipoint configuration
- */
- private void setConfigPasspoint(WifiConfiguration config) {
- config.FQDN = "android.qns.unitTest";
- config.providerFriendlyName = "android.qns.unitTest";
- WifiEnterpriseConfig enterpriseConfig = mock(WifiEnterpriseConfig.class);
- when(enterpriseConfig.getEapMethod()).thenReturn(WifiEnterpriseConfig.Eap.PEAP);
-
- }
-
- /**
- * Add the Configurations to WifiConfigManager (WifiConfigureStore can take them out according
- * to the networkd ID) and setup the WifiConfigManager mocks for these networks.
- * This simulates the WifiConfigManager class behaviour.
- *
- * @param configs input configuration need to be added to WifiConfigureStore
- */
- private void prepareConfigStore(final WifiConfiguration[] configs) {
- when(mWifiConfigManager.getConfiguredNetwork(anyInt()))
- .then(new AnswerWithArguments() {
- public WifiConfiguration answer(int netId) {
- if (netId >= 0 && netId < configs.length) {
- return new WifiConfiguration(configs[netId]);
- } else {
- return null;
- }
- }
- });
- when(mWifiConfigManager.getConfiguredNetwork(anyString()))
- .then(new AnswerWithArguments() {
- public WifiConfiguration answer(String configKey) {
- for (int netId = 0; netId < configs.length; netId++) {
- if (TextUtils.equals(configs[netId].configKey(), configKey)) {
- return new WifiConfiguration(configs[netId]);
- }
- }
- return null;
- }
- });
- when(mWifiConfigManager.getSavedNetworks())
- .then(new AnswerWithArguments() {
- public List<WifiConfiguration> answer() {
- List<WifiConfiguration> savedNetworks = new ArrayList<>();
- for (int netId = 0; netId < configs.length; netId++) {
- savedNetworks.add(new WifiConfiguration(configs[netId]));
- }
- return savedNetworks;
- }
- });
- when(mWifiConfigManager.clearNetworkCandidateScanResult(anyInt()))
- .then(new AnswerWithArguments() {
- public boolean answer(int netId) {
- if (netId >= 0 && netId < configs.length) {
- configs[netId].getNetworkSelectionStatus().setCandidate(null);
- configs[netId].getNetworkSelectionStatus()
- .setCandidateScore(Integer.MIN_VALUE);
- configs[netId].getNetworkSelectionStatus()
- .setSeenInLastQualifiedNetworkSelection(false);
- return true;
- } else {
- return false;
- }
- }
- });
- when(mWifiConfigManager.setNetworkCandidateScanResult(
- anyInt(), any(ScanResult.class), anyInt()))
- .then(new AnswerWithArguments() {
- public boolean answer(int netId, ScanResult scanResult, int score) {
- if (netId >= 0 && netId < configs.length) {
- configs[netId].getNetworkSelectionStatus().setCandidate(scanResult);
- configs[netId].getNetworkSelectionStatus().setCandidateScore(score);
- configs[netId].getNetworkSelectionStatus()
- .setSeenInLastQualifiedNetworkSelection(true);
- return true;
- } else {
- return false;
- }
- }
- });
- when(mWifiConfigManager.clearNetworkConnectChoice(anyInt()))
- .then(new AnswerWithArguments() {
- public boolean answer(int netId) {
- if (netId >= 0 && netId < configs.length) {
- configs[netId].getNetworkSelectionStatus().setConnectChoice(null);
- configs[netId].getNetworkSelectionStatus()
- .setConnectChoiceTimestamp(
- NetworkSelectionStatus
- .INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
- return true;
- } else {
- return false;
- }
- }
- });
- when(mWifiConfigManager.setNetworkConnectChoice(anyInt(), anyString(), anyLong()))
- .then(new AnswerWithArguments() {
- public boolean answer(int netId, String configKey, long timestamp) {
- if (netId >= 0 && netId < configs.length) {
- configs[netId].getNetworkSelectionStatus().setConnectChoice(configKey);
- configs[netId].getNetworkSelectionStatus().setConnectChoiceTimestamp(
- timestamp);
- return true;
- } else {
- return false;
- }
- }
- });
- }
-
- /**
- * Setup WifiConfigManager mock for the ephemeral network addition and getter/setter methods.
- */
- private WifiConfiguration setupEphemeralNetwork(
- int networkId, ScanResult scanResult, boolean meteredHint) {
- // Return the correct networkID for ephemeral network addition.
- when(mWifiConfigManager.addOrUpdateNetwork(any(WifiConfiguration.class), anyInt()))
- .thenReturn(new NetworkUpdateResult(networkId));
- final WifiConfiguration config = ScanResultUtil.createNetworkFromScanResult(scanResult);
- config.networkId = networkId;
- config.meteredHint = meteredHint;
-
-// when(mWifiConfigManager.getConfiguredNetwork(networkId))
- // .thenReturn(new WifiConfiguration(config));
-
- when(mWifiConfigManager.getConfiguredNetwork(eq(networkId)))
- .then(new AnswerWithArguments() {
- public WifiConfiguration answer(int netId) {
- return new WifiConfiguration(config);
- }
- });
- when(mWifiConfigManager.setNetworkCandidateScanResult(
- eq(networkId), any(ScanResult.class), anyInt()))
- .then(new AnswerWithArguments() {
- public boolean answer(int netId, ScanResult scanResult, int score) {
- config.getNetworkSelectionStatus().setCandidate(scanResult);
- config.getNetworkSelectionStatus().setCandidateScore(score);
- config.getNetworkSelectionStatus()
- .setSeenInLastQualifiedNetworkSelection(true);
- return true;
- }
- });
- return config;
- }
-
- /**
- * Link scan results to the saved configurations.
- *
- * The shorter of the 2 input params will be used to loop over so the inputs don't
- * need to be of equal length. If there are more scan details then configs the remaining scan
- * details will be associated with a NULL config.
- *
- * @param configs saved configurations
- * @param scanDetails come in scan results
- */
- private void scanResultLinkConfiguration(WifiConfiguration[] configs,
- List<ScanDetail> scanDetails) {
- if (scanDetails.size() <= configs.length) {
- for (int i = 0; i < scanDetails.size(); i++) {
- ScanDetail scanDetail = scanDetails.get(i);
- when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(eq(scanDetail)))
- .thenReturn(configs[i]);
- }
- } else {
- for (int i = 0; i < configs.length; i++) {
- ScanDetail scanDetail = scanDetails.get(i);
- when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(eq(scanDetail)))
- .thenReturn(configs[i]);
- }
-
- // associated the remaining scan details with a NULL config.
- for (int i = configs.length; i < scanDetails.size(); i++) {
- when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(
- eq(scanDetails.get(i)))).thenReturn(null);
- }
- }
- }
-
- private void configureScoreCache(List<ScanDetail> scanDetails, Integer[] scores,
- boolean[] meteredHints) {
- for (int i = 0; i < scanDetails.size(); i++) {
- ScanDetail scanDetail = scanDetails.get(i);
- Integer score = scores[i];
- ScanResult scanResult = scanDetail.getScanResult();
- if (score != null) {
- when(mScoreCache.isScoredNetwork(scanResult)).thenReturn(true);
- when(mScoreCache.hasScoreCurve(scanResult)).thenReturn(true);
- when(mScoreCache.getNetworkScore(eq(scanResult), anyBoolean())).thenReturn(score);
- when(mScoreCache.getNetworkScore(scanResult)).thenReturn(score);
- } else {
- when(mScoreCache.isScoredNetwork(scanResult)).thenReturn(false);
- when(mScoreCache.hasScoreCurve(scanResult)).thenReturn(false);
- when(mScoreCache.getNetworkScore(eq(scanResult), anyBoolean())).thenReturn(
- WifiNetworkScoreCache.INVALID_NETWORK_SCORE);
- when(mScoreCache.getNetworkScore(scanResult)).thenReturn(
- WifiNetworkScoreCache.INVALID_NETWORK_SCORE);
- }
- when(mScoreCache.getMeteredHint(scanResult)).thenReturn(meteredHints[i]);
- }
- }
-
- /**
- * Verify whether the chosen configuration matched with the expected chosen scan result
- *
- * @param chosenScanResult the expected chosen scan result
- * @param chosenCandidate the chosen configuration
- */
- private void verifySelectedResult(
- ScanResult chosenScanResult, WifiConfiguration chosenCandidate) {
- verify(mWifiConfigManager, atLeastOnce()).setNetworkCandidateScanResult(
- eq(chosenCandidate.networkId), eq(chosenScanResult), anyInt());
- }
-
- // QNS test under disconnected State
-
- /**
- * Case #1 choose 2GHz stronger RSSI test
- *
- * In this test. we simulate following scenario
- * WifiStateMachine is under disconnected state
- * Two networks test1, test2 are secured network
- * Both network are enabled, encrypted and at 2.4 GHz
- * test1 is with RSSI -70 test2 is with RSSI -60
- *
- * Expected behavior: test2 is chosen
- */
- @Test
- public void chooseNetworkDisconnected2GHighestRssi() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 2417};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-70, -60};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
-
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- ScanResult chosenScanResult = scanDetails.get(scanDetails.size() - 1).getScanResult();
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- WifiConfigurationTestUtil.assertConfigurationEqual(
- savedConfigs[scanDetails.size() - 1], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #2 choose 5GHz Stronger RSSI Test
- *
- * In this test. we simulate following scenario
- * WifiStateMachine is under disconnected state
- * Two networks test1, test2 are secured network
- * Both network are enabled, encrypted and at 5 GHz
- * test1 is with RSSI -70 test2 is with RSSI -60
- *
- * Expected behavior: test2 is chosen
- */
- @Test
- public void chooseNetworkDisconnected5GHighestRssi() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {5180, 5610};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-70, -60};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
-
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- ScanResult chosenScanResult = scanDetails.get(scanDetails.size() - 1).getScanResult();
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- WifiConfigurationTestUtil.assertConfigurationEqual(
- savedConfigs[scanDetails.size() - 1], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #3 5GHz over 2GHz bonus Test
- *
- * In this test. we simulate following scenario
- * WifiStateMachine is under disconnected state
- * Two networks test1, test2 are secured network
- * Both network are enabled
- * test1 is @ 2GHz with RSSI -60
- * test2 is @ 5Ghz with RSSI -65
- *
- * Expected behavior: test2 is chosen due to 5GHz bonus
- */
- @Test
- public void chooseNetworkDisconnect5GOver2GTest() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-60, -65};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- ScanResult chosenScanResult = scanDetails.get(scanDetails.size() - 1).getScanResult();
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- WifiConfigurationTestUtil.assertConfigurationEqual(
- savedConfigs[scanDetails.size() - 1], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #4 2GHz over 5GHz dur to 5GHz signal too weak test
- *
- * In this test. we simulate following scenario
- * WifiStateMachine is under disconnected state
- * Two networks test1, test2 are secured network
- * Both network are enabled
- * test1 is @ 2GHz with RSSI -60
- * test2 is @ 5Ghz with RSSI -75
- *
- * Expected behavior: test1 is chosen due to 5GHz signal is too weak (5GHz bonus can not
- * compensate)
- */
- @Test
- public void chooseNetworkDisconnect2GOver5GTest() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-60, -75};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #5 2GHz signal Saturation test
- *
- * In this test. we simulate following scenario
- * WifiStateMachine is under disconnected state
- * Two networks test1, test2 are secured network
- * Both network are enabled
- * test1 is @ 2GHz with RSSI -50
- * test2 is @ 5Ghz with RSSI -65
- *
- * Expected behavior: test2 is chosen. Although the RSSI delta here is 15 too, because 2GHz RSSI
- * saturates at -60, the real RSSI delta is only 5, which is less than 5GHz bonus
- */
- @Test
- public void chooseNetworkDisconnect2GRssiSaturationTest() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-50, -65};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- ScanResult chosenScanResult = scanDetails.get(scanDetails.size() - 1).getScanResult();
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- WifiConfigurationTestUtil.assertConfigurationEqual(
- savedConfigs[scanDetails.size() - 1], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #6 Minimum RSSI test
- *
- * In this test. we simulate following scenario
- * WifiStateMachine is under disconnected state
- * Two networks test1, test2 are secured network
- * Both network are enabled
- * test1 is @ 2GHz with RSSI -86
- * test2 is @ 5Ghz with RSSI -83
- *
- * Expected behavior: no QNS is made because both network are below the minimum threshold, null
- */
- @Test
- public void chooseNetworkMinimumRssiTest() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {WifiQualifiedNetworkSelector.MINIMUM_2G_ACCEPT_RSSI - 1,
- WifiQualifiedNetworkSelector.MINIMUM_5G_ACCEPT_RSSI - 1};
- int[] security = {SECURITY_EAP, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- assertEquals("choose the wrong SSID", null, candidate);
- }
-
- /**
- * Case #7 encrypted network over passpoint network
- *
- * In this test. we simulate following scenario
- * WifiStateMachine is under disconnected state
- * Two networks test1 is secured network, test2 are passpoint network
- * Both network are enabled and at 2.4 GHz. Both have RSSI of -70
- *
- * Expected behavior: test1 is chosen since secured network has higher priority than passpoint
- * network
- */
- @Test
- public void chooseNetworkSecurityOverPassPoint() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 2437};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[ESS]"};
- int[] levels = {-70, -70};
- int[] security = {SECURITY_EAP, SECURITY_NONE};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- setConfigPasspoint(savedConfigs[1]);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #8 passpoint network over open network
- *
- * In this test. we simulate following scenario
- * WifiStateMachine is under disconnected state
- * Two networks test1 is passpoint network, test2 is open network
- * Both network are enabled and at 2.4 GHz. Both have RSSI of -70
- *
- * Expected behavior: test1 is chosen since passpoint network has higher priority than open
- * network
- */
- @Test
- public void chooseNetworkPasspointOverOpen() {
- String[] ssids = {"\"test1\"", "\"test2\""};
- String[] bssids = {"6c:f3:7f:ae:8c:f8", "6c:f3:7f:ae:8c:f4"};
- int[] frequencies = {2437, 2437};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-70, -70};
- int[] security = {SECURITY_NONE, SECURITY_NONE};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- setConfigPasspoint(savedConfigs[0]);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #9 secure network over open network
- *
- * In this test. we simulate following scenario
- * WifiStateMachine is under disconnected state
- * Two networks test1 is secure network, test2 is open network
- * Both network are enabled and at 2.4 GHz. Both have RSSI of -70
- *
- * Expected behavior: test1 is chosen since secured network has higher priority than open
- * network
- */
- @Test
- public void chooseNetworkSecureOverOpen() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 2437};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-70, -70};
- int[] security = {SECURITY_PSK, SECURITY_NONE};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #10 first time user select a network
- *
- * In this test. we simulate following scenario
- * There are three saved networks: test1, test2 and test3. Now user select the network test3
- * check test3 has been saved in test1's and test2's ConnectChoice
- *
- * Expected behavior: test1's and test2's ConnectChoice should be test3, test3's ConnectChoice
- * should be null
- */
- @Test
- public void userSelectsNetworkForFirstTime() {
- String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\""};
- int[] security = {SECURITY_PSK, SECURITY_PSK, SECURITY_NONE};
-
- final WifiConfiguration[] configs = generateWifiConfigurations(ssids, security);
- for (WifiConfiguration network : configs) {
- NetworkSelectionStatus status = network.getNetworkSelectionStatus();
- status.setSeenInLastQualifiedNetworkSelection(true);
- }
- prepareConfigStore(configs);
-
- mWifiQualifiedNetworkSelector.setUserConnectChoice(configs.length - 1);
- String key = configs[configs.length - 1].configKey();
- for (int index = 0; index < configs.length; index++) {
- WifiConfiguration config = configs[index];
- NetworkSelectionStatus status = config.getNetworkSelectionStatus();
- if (index == configs.length - 1) {
- assertEquals("User selected network should not have prefernce over it", null,
- status.getConnectChoice());
- } else {
- assertEquals("Wrong user preference", key, status.getConnectChoice());
- }
- }
- }
-
- /**
- * Case #11 choose user selected network
- *
- * In this test, we simulate following scenario:
- * WifiStateMachine is under disconnected state
- * There are three networks: test1, test2, test3 and test3 is the user preference
- * All three networks are enabled
- * test1 is @ 2.4GHz with RSSI -50 PSK
- * test2 is @ 5Ghz with RSSI -65 PSK
- * test3 is @ 2.4GHz with RSSI -55 open
- *
- * Expected behavior: test3 is chosen since it is user selected network. It overcome all other
- * priorities
- */
- @Test
- public void chooseUserPreferredNetwork() {
- String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\""};
- int[] security = {SECURITY_PSK, SECURITY_PSK, SECURITY_NONE};
-
- final WifiConfiguration[] configs = generateWifiConfigurations(ssids, security);
- for (WifiConfiguration network : configs) {
- NetworkSelectionStatus status = network.getNetworkSelectionStatus();
- status.setSeenInLastQualifiedNetworkSelection(true);
- }
- prepareConfigStore(configs);
-
- //set user preference
- mWifiQualifiedNetworkSelector.setUserConnectChoice(ssids.length - 1);
- //Generate mocked recent scan results
- String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "6c:f3:7f:ae:8c:f5"};
- int[] frequencies = {2437, 5180, 2437};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]", "NONE"};
- int[] levels = {-50, -65, -55};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- scanResultLinkConfiguration(configs, scanDetails);
-
- ScanResult chosenScanResult = scanDetails.get(scanDetails.size() - 1).getScanResult();
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- WifiConfigurationTestUtil.assertConfigurationEqual(
- configs[scanDetails.size() - 1], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #12 enable a blacklisted BSSID
- *
- * In this test, we simulate following scenario:
- * For two Aps, BSSIDA and BSSIDB. Disable BSSIDA, then check whether BSSIDA is disabled and
- * BSSIDB is enabled. Then enable BSSIDA, check whether both BSSIDs are enabled.
- */
- @Test
- public void enableBssidTest() {
- String bssidA = "6c:f3:7f:ae:8c:f3";
- String bssidB = "6c:f3:7f:ae:8c:f4";
- //check by default these two BSSIDs should be enabled
- assertEquals("bssidA should be enabled by default",
- mWifiQualifiedNetworkSelector.isBssidDisabled(bssidA), false);
- assertEquals("bssidB should be enabled by default",
- mWifiQualifiedNetworkSelector.isBssidDisabled(bssidB), false);
-
- //disable bssidA 3 times, check whether A is dsiabled and B is still enabled
- mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(bssidA, false);
- assertEquals("bssidA should be disabled",
- mWifiQualifiedNetworkSelector.isBssidDisabled(bssidA), false);
- mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(bssidA, false);
- assertEquals("bssidA should be disabled",
- mWifiQualifiedNetworkSelector.isBssidDisabled(bssidA), false);
- mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(bssidA, false);
- assertEquals("bssidA should be disabled",
- mWifiQualifiedNetworkSelector.isBssidDisabled(bssidA), true);
- assertEquals("bssidB should still be enabled",
- mWifiQualifiedNetworkSelector.isBssidDisabled(bssidB), false);
-
- //re-enable bssidA, check whether A is dsiabled and B is still enabled
- mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(bssidA, true);
- assertEquals("bssidA should be enabled by default",
- mWifiQualifiedNetworkSelector.isBssidDisabled(bssidA), false);
- assertEquals("bssidB should be enabled by default",
- mWifiQualifiedNetworkSelector.isBssidDisabled(bssidB), false);
-
- //make sure illegal input will not cause crash
- mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(null, false);
- mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(null, true);
- }
-
- /**
- * Case #13 do not choose the BSSID has been disabled
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under disconnected state
- * Two networks test1, test2 are secured network and found in scan results
- * Both network are enabled
- * test1 is @ 2GHz with RSSI -65
- * test2 is @ 5Ghz with RSSI -50
- * test2's BSSID is disabled
- *
- * expected return test1 since test2's BSSID has been disabled
- */
- @Test
- public void networkChooseWithOneBssidDisabled() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-65, -50};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
-
- mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(bssids[1], false);
- mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(bssids[1], false);
- mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(bssids[1], false);
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #14 re-choose the disabled BSSID after it is re-enabled
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under disconnected state
- * Two networks test1, test2 are secured network and found in scan results
- * Both network are enabled
- * test1 is @ 2GHz with RSSI -65
- * test2 is @ 5Ghz with RSSI -50
- * test2's BSSID is disabled
- *
- * expected return test2 since test2's BSSID has been enabled again
- */
- @Test
- public void networkChooseWithOneBssidReenaabled() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-65, -50};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
-
- mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(bssids[1], false);
- mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(bssids[1], false);
- mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(bssids[1], false);
- //re-enable it
- mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(bssids[1], true);
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #15 re-choose the disabled BSSID after its disability has expired
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under disconnected state
- * Two networks test1, test2 are secured network and found in scan results
- * Both network are enabled
- * test1 is @ 2GHz with RSSI -65
- * test2 is @ 5Ghz with RSSI -50
- * test2's BSSID is disabled
- *
- * expected return test2 since test2's BSSID has been enabled again
- */
- @Test
- public void networkChooseWithOneBssidDisableExpire() {
- String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\""};
- String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "6c:f3:7f:ae:8c:f5"};
- int[] frequencies = {2437, 5180, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]",
- "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-65, -50, -60};
- int[] security = {SECURITY_PSK, SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
-
- for (int index = 0; index < WifiQualifiedNetworkSelector.BSSID_BLACKLIST_THRESHOLD;
- index++) {
- mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(bssids[1], false);
- mWifiQualifiedNetworkSelector.enableBssidForQualityNetworkSelection(bssids[2], false);
- }
-
- //re-enable it
- when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
- + WifiQualifiedNetworkSelector.BSSID_BLACKLIST_EXPIRE_TIME_MS);
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
- /**
- * Case #16 do not choose the SSID has been disabled
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under disconnected state
- * Two networks test1, test2 are secured network and found in scan results
- * Both network are enabled
- * test1 is @ 2GHz with RSSI -65
- * test2 is @ 5Ghz with RSSI -50
- * test2's SSID is disabled
- *
- * expected return test1 since test2's SSID has been disabled
- */
- @Test
- public void networkChooseWithOneSsidDisabled() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-65, -50};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
-
- when(mWifiConfigManager.tryEnableNetwork(anyInt())).thenReturn(true);
- savedConfigs[1].getNetworkSelectionStatus().setNetworkSelectionStatus(
- NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED);
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #17 do not make QNS is link is bouncing now
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under disconnected state and currently is under link bouncing
- * Two networks test1, test2 are secured network and found in scan results
- * Both network are enabled
- * test1 is @ 2GHz with RSSI -50
- * test2 is @ 5Ghz with RSSI -50
- *
- * expected return null
- */
- @Test
- public void noQNSWhenLinkBouncingDisconnected() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {WifiQualifiedNetworkSelector.MINIMUM_2G_ACCEPT_RSSI - 1,
- WifiQualifiedNetworkSelector.MINIMUM_5G_ACCEPT_RSSI - 1};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, true, false, true, false, scanDetails);
-
- assertEquals("choose the wrong network", null, candidate);
- }
-
- /**
- * Case #18 QNS with very short gap
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under disconnected state
- * If last QNS is made in less than MINIMUM_QUALIFIED_NETWORK_SELECTION_INTERVAL, we
- * still should make new QNS since it is disconnected now
- *
- * expect return test1 because of band bonus
- */
- @Test
- public void networkSelectionInShortGap() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-50, -65};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- //first QNS
- mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, false,
- false, true, false, scanDetails);
- //immediately second QNS
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
- ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
-
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- //Unit test for Connected State
-
- /**
- * Case #19 no QNS with very short gap when connected
- * In this test. we simulate following scenario:
- * WifiStateMachine is under connected state and test2 is connected
- * When WifiStateMachine is already in connected state, if last QNS is made in less than
- * MINIMUM_QUALIFIED_NETWORK_SELECTION_INTERVAL, no new QNS should be made
- *
- * expect return NULL
- */
- @Test
- public void noNetworkSelectionDueToShortGap() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-50, -65};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- //first QNS
- mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, false,
- false, true, false, scanDetails);
- //immediately second QNS
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, true, false, false, scanDetails);
- ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
- assertEquals("choose the wrong BSSID", null, candidate);
- }
-
- /**
- * Case #20 force QNS with very short gap under connection
- * In this test. we simulate following scenario:
- * WifiStateMachine is under connected state and test2 is connected
- * When WifiStateMachine is already in connected state, if last QNS is made in less than
- * MINIMUM_QUALIFIED_NETWORK_SELECTION_INTERVAL, no new QNS should be made. However, if we force
- * to make new QNS, QNS still will be made
- *
- * expect return test2 since it is the current connected one (bonus)
- */
- @Test
- public void forceNetworkSelectionInShortGap() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-50, -65};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- //first QNS
- mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, false,
- false, true, false, scanDetails);
- //immediately second QNS
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(true,
- false, false, true, false, false, scanDetails);
- ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
-
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #21 no QNS when connected and user do not allow switch when connected
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under connected state and test2 is connected
- * if user does not allow switch network when connected, do not make new QNS when connected
- *
- * expect return NULL
- */
- @Test
- public void noNewNetworkSelectionDuetoUserDisableSwitchWhenConnected() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-50, -65};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, true, false, false, scanDetails);
- assertEquals("choose the wrong BSSID", null, candidate);
- assertEquals("Should receive zero filteredScanDetails", 0,
- mWifiQualifiedNetworkSelector.getFilteredScanDetails().size());
- }
-
- /**
- * Case #22 no new QNS if current network is qualified already
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under connected state and test2 is connected
- * If current connected network is Qualified already, do not make new QNS
- * simulated current connected network as:
- * 5GHz, RSSI = WifiQualifiedNetworkSelector.QUALIFIED_RSSI_5G_BAND, secured
- *
- * expected return null
- */
- @Test
- public void noNewQNSCurrentNetworkQualified() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-65, WifiQualifiedNetworkSelector.QUALIFIED_RSSI_5G_BAND};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- //first time, connect to test2 due to 5GHz bonus
- mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, false,
- false, true, false, scanDetails);
- when(mWifiInfo.getNetworkId()).thenReturn(1);
- when(mWifiInfo.getBSSID()).thenReturn(bssids[1]);
- when(mWifiInfo.is24GHz()).thenReturn(false);
- when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() + 11 * 1000);
-
- levels[0] = -50; // if there is QNS, test1 will be chosen
- scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, true, false, false, scanDetails);
- assertEquals("choose the wrong BSSID", null, candidate);
- }
-
- /**
- * Case #23 No new QNS when link bouncing when connected
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under connected state and test2 is connected
- * no new QNS when link is bouncing
- *
- * expected return null
- */
- @Test
- public void noNewQNSLinkBouncing() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-70, -75};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- //first connect to test2 due to 5GHz bonus
- mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, false,
- false, true, false, scanDetails);
- when(mWifiInfo.getNetworkId()).thenReturn(1);
- when(mWifiInfo.getBSSID()).thenReturn(bssids[1]);
- when(mWifiInfo.is24GHz()).thenReturn(false);
- when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() + 11 * 1000);
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, true, true, false, false, scanDetails);
- assertEquals("choose the wrong BSSID", null, candidate);
- }
-
- /**
- * Case #24 Qualified network need to be on 5GHz
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under connected state and connected to test2
- * if current connected network is not 5GHz, then it is not qualified. We should make new QNS
- *
- * expected result: return test1
- */
- @Test
- public void currentNetworkNotQualifiedDueToBandMismatch() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 2437};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-50, -65};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- when(mWifiInfo.getNetworkId()).thenReturn(0);
- when(mWifiInfo.getBSSID()).thenReturn(bssids[0]);
- when(mWifiInfo.is24GHz()).thenReturn(true);
- //connect to config2 first
- mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, false,
- false, true, false, scanDetails);
-
- when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() + 11 * 1000);
-
- ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, true, false, false, scanDetails);
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #25 Qualified network need to be secured
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under connected state and current connects to test2. If current connected
- * network is open network, then it is not qualified. We should make new QNS selection and
- * ensure that we switch to the secure one if the RSSI is sufficiently high.
- *
- * expected result: return test1 since test1 has higher RSSI
- */
- @Test
- public void currentNetworkNotQualifiedDueToOpenNetwork() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {5400, 5400};
- String[] caps = {"[WPA2-EAP-CCMP][ESS][ESS]", "[ESS]"};
- int[] levels = {-80, -45};
- int[] security = {SECURITY_PSK, SECURITY_NONE};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- //first connect to test2 because of RSSI
- mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, false,
- false, true, false, scanDetails);
- when(mWifiInfo.getNetworkId()).thenReturn(1);
- when(mWifiInfo.getBSSID()).thenReturn(bssids[1]);
- when(mWifiInfo.is24GHz()).thenReturn(false);
- when(mWifiInfo.is5GHz()).thenReturn(true);
- when(mClock.getElapsedSinceBootMillis())
- .thenReturn(SystemClock.elapsedRealtime() + 11 * 1000);
-
- // Now increase RSSI of test1
- levels[0] = -60;
- scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, true, false, false, scanDetails);
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #26 ephemeral network can not be qualified network
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under connected state and current connected to test2
- * if current connected network is ephemeral network, then it is not qualified. We should make
- * new QNS
- *
- * expected result: return test1 (since test2 is ephemeral)
- */
- @Test
- public void currentNetworkNotQualifiedDueToEphemeral() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {5200, 5200};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-100, -50};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- savedConfigs[1].ephemeral = true;
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- //first connect to test2 since test1's RSSI is negligible
- mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, false,
- false, true, false, scanDetails);
- when(mWifiInfo.getNetworkId()).thenReturn(1);
- when(mWifiInfo.getBSSID()).thenReturn(bssids[1]);
- when(mWifiInfo.is24GHz()).thenReturn(false);
-
- levels[0] = -70;
- scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() + 11 * 1000);
-
- ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, true, false, false, scanDetails);
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #27 low signal network can not be Qualified network (5GHz)
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under connected state and current connected to test2
- * if current connected network's rssi is too low, then it is not qualified. We should
- * make new QNS
- *
- * expected result: return test1
- */
- @Test
- public void currentNetworkNotQualifiedDueToLow5GRssi() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {5200, 5200};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-80, WifiQualifiedNetworkSelector.QUALIFIED_RSSI_5G_BAND - 1};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, false,
- false, true, false, scanDetails);
- when(mWifiInfo.getNetworkId()).thenReturn(1);
- when(mWifiInfo.getBSSID()).thenReturn(bssids[1]);
- when(mWifiInfo.getRssi()).thenReturn(levels[1]);
- when(mWifiInfo.is24GHz()).thenReturn(false);
- when(mWifiInfo.is5GHz()).thenReturn(true);
-
- when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() + 11 * 1000);
- levels[0] = -60;
- scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, true, false, false, scanDetails);
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #28 low signal network can not be Qualified network (2.4GHz)
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under connected state and current connected to test2
- * if current connected network's rssi is too low, then it is not qualified. We should
- * make new QNS
- *
- * expected result: return test1
- */
- @Test
- public void currentNetworkNotQualifiedDueToLow2GRssi() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 2437};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-100, WifiQualifiedNetworkSelector.QUALIFIED_RSSI_24G_BAND - 1};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, false,
- false, true, false, scanDetails);
-
- when(mWifiInfo.getNetworkId()).thenReturn(1);
- when(mWifiInfo.getBSSID()).thenReturn(bssids[1]);
- when(mWifiInfo.getRssi()).thenReturn(levels[1]);
- when(mWifiInfo.is24GHz()).thenReturn(false);
- when(mWifiInfo.is5GHz()).thenReturn(true);
-
- levels[0] = -60;
- scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() + 11 * 1000);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, true, false, false, scanDetails);
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #29 Choose current network due to current network bonus
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under connected state and current connected to test2
- * To connect to a network which is not linked to current connected network, unless this network
- * is more than 10 db higher than current network, we should not switch. So although test2 has a
- * lower signal, we still choose test2
- *
- * expected result: return test2
- */
- @Test
- public void currentNetworkStayDueToSameNetworkBonus() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 2437};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-100, -80};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, false,
- false, true, false, scanDetails);
- when(mWifiInfo.getNetworkId()).thenReturn(1);
- when(mWifiInfo.getBSSID()).thenReturn(bssids[1]);
- when(mWifiInfo.is24GHz()).thenReturn(true);
-
- levels[0] = -80 + WifiQualifiedNetworkSelector.SAME_BSSID_AWARD / 4
- + WifiQualifiedNetworkSelector.SAME_NETWORK_AWARD / 4 - 1;
- scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() + 11 * 1000);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, true, false, false, scanDetails);
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #30 choose another network due to current network's signal is too low
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under connected state and current connected to test2
- * To connect to a network which is not linked to current connected network, if this network
- * is more than 10 db higher than current network, we should switch
- *
- * expected new result: return test1
- */
- @Test
- public void switchNetworkStayDueToCurrentNetworkRssiLow() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 2437};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-100, -80};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, false,
- false, true, false, scanDetails);
-
- when(mWifiInfo.getNetworkId()).thenReturn(1);
- when(mWifiInfo.getBSSID()).thenReturn(bssids[1]);
- when(mWifiInfo.is24GHz()).thenReturn(true);
-
- levels[0] = -80 + WifiQualifiedNetworkSelector.SAME_BSSID_AWARD / 4
- + WifiQualifiedNetworkSelector.SAME_NETWORK_AWARD / 4 + 1;
- scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() + 11 * 1000);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, true, false, false, scanDetails);
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #31 Choose current BSSID due to current BSSID bonus
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under connected state and current connected to test2
- * Linked network will be treated as same network. To connect to a network which is linked to
- * current connected network, unless this network is more than 6 db higher than current network,
- * we should not switch AP and stick to current BSSID
- *
- * expected result: return test2
- */
- @Test
- public void currentBssidStayDueToSameBSSIDBonus() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 2437};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-100, -80};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- //link two configuration
- savedConfigs[0].linkedConfigurations = new HashMap<String, Integer>();
- savedConfigs[1].linkedConfigurations = new HashMap<String, Integer>();
- savedConfigs[0].linkedConfigurations.put(savedConfigs[1].configKey(), 1);
- savedConfigs[1].linkedConfigurations.put(savedConfigs[0].configKey(), 1);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, false,
- false, true, false, scanDetails);
-
- when(mWifiInfo.getNetworkId()).thenReturn(1);
- when(mWifiInfo.getBSSID()).thenReturn(bssids[1]);
- when(mWifiInfo.is24GHz()).thenReturn(true);
-
- levels[0] = -80 + WifiQualifiedNetworkSelector.SAME_NETWORK_AWARD / 4 - 1;
- scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() + 11 * 1000);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, true, false, false, scanDetails);
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #32 Choose another BSSID due to current BSSID's rssi is too low
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is under connected state and current connected to test2
- * Linked network will be treated as same network. To connect to a network which is linked to
- * current connected network, unless this network is more than 6 db higher than current network,
- * we should not switch AP and stick to current BSSID
- *
- * expected result: return test2
- */
- @Test
- public void swithBssidDueToLowRssi() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 2437};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS][ESS]"};
- int[] levels = {-100, -80};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- //link two configuration
- savedConfigs[0].linkedConfigurations = new HashMap<String, Integer>();
- savedConfigs[1].linkedConfigurations = new HashMap<String, Integer>();
- savedConfigs[0].linkedConfigurations.put(savedConfigs[1].configKey(), 1);
- savedConfigs[1].linkedConfigurations.put(savedConfigs[0].configKey(), 1);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, false,
- false, true, false, scanDetails);
-
- when(mWifiInfo.getNetworkId()).thenReturn(1);
- when(mWifiInfo.getBSSID()).thenReturn(bssids[1]);
- when(mWifiInfo.is24GHz()).thenReturn(true);
-
- levels[0] = -80 + WifiQualifiedNetworkSelector.SAME_BSSID_AWARD / 4 + 1;
- scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime() + 11 * 1000);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, true, false, false, scanDetails);
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #33 Choose an ephemeral network with a good score because no saved networks
- * are available.
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is not connected to any network.
- * selectQualifiedNetwork() is called with 2 scan results, test1 and test2.
- * test1 is an enterprise network w/o a score.
- * test2 is an open network with a good score. Additionally it's a metered network.
- * isUntrustedConnectionsAllowed is set to true.
- *
- * expected result: return test2 with meteredHint set to True.
- */
- @Test
- public void selectQualifiedNetworkChoosesEphemeral() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {5200, 5200};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[ESS]"};
- int[] levels = {-70, -70};
- Integer[] scores = {null, 120};
- boolean[] meteredHints = {false, true};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- configureScoreCache(scanDetails, scores, meteredHints);
-
- // No saved networks.
- when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(any(ScanDetail.class)))
- .thenReturn(null);
-
- ScanResult untrustedScanResult = scanDetails.get(1).getScanResult();
- WifiConfiguration unTrustedNetworkCandidate =
- setupEphemeralNetwork(1, untrustedScanResult, meteredHints[1]);
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(
- false /* forceSelectNetwork */,
- true /* isUntrustedConnectionsAllowed */,
- false, /* isLinkDebouncing */
- false, /* isConnected */
- true, /* isDisconnected */
- false, /* isSupplicantTransient */
- scanDetails);
- WifiConfigurationTestUtil.assertConfigurationEqual(unTrustedNetworkCandidate, candidate);
- verifySelectedResult(untrustedScanResult, candidate);
- assertEquals(meteredHints[1], candidate.meteredHint);
- }
-
- /**
- * Case #34 Test Filtering of potential candidate scanDetails (Untrusted allowed)
- *
- * In this test. we simulate following scenario
- * WifiStateMachine is under disconnected state
- * test1 is @ 2GHz with RSSI -60
- * test2 is @ 5Ghz with RSSI -86, (below minimum threshold)
- * test3 is @ 5Ghz with RSSI -50, however it has no associated saved config
- * test4 is @ 2Ghz with RSSI -62, no associated config, but is Ephemeral
- *
- * Expected behavior: test1 is chosen due to 5GHz signal is too weak (5GHz bonus can not
- * compensate).
- * test1 & test4's scanDetails are returned by 'getFilteredScanDetail()'
- */
- @Test
- public void testGetFilteredScanDetailsReturnsOnlyConsideredScanDetails_untrustedAllowed() {
- String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\""};
- String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55",
- "c0:ff:ee:ee:e3:ee"};
- int[] frequencies = {2437, 5180, 5180, 2437};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]",
- "[WPA2-EAP-CCMP][ESS]"};
- int[] levels = {-60, -86, -50, -62};
- int[] security = {SECURITY_PSK, SECURITY_PSK, SECURITY_PSK, SECURITY_PSK};
- boolean[] meteredHints = {false, false, false, true};
- Integer[] scores = {null, null, null, 120};
-
- //Create all 4 scanDetails
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
-
- //Setup NetworkScoreCache for detecting ephemeral networks ("test4")
- configureScoreCache(scanDetails, scores, meteredHints);
- ScanResult untrustedScanResult = scanDetails.get(3).getScanResult();
-
- //Set up associated configs for test1 & test2
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(
- Arrays.copyOfRange(ssids, 0, 2), Arrays.copyOfRange(security, 0, 2));
- prepareConfigStore(savedConfigs);
- List<ScanDetail> savedScanDetails = new ArrayList<ScanDetail>(scanDetails.subList(0, 2));
- scanResultLinkConfiguration(savedConfigs, savedScanDetails);
-
- setupEphemeralNetwork(2, scanDetails.get(2).getScanResult(), meteredHints[2]);
- setupEphemeralNetwork(3, scanDetails.get(3).getScanResult(), meteredHints[3]);
-
- //Force mock ConfigManager to return null (and not an empty list) for "test3" & "test4"
- when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(eq(scanDetails.get(2))))
- .thenReturn(null);
- when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(eq(scanDetails.get(3))))
- .thenReturn(null);
-
- ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(
- false /* forceSelectNetwork */,
- true /* isUntrustedConnectionsAllowed */,
- false, /* isLinkDebouncing */
- false, /* isConnected */
- true, /* isDisconnected */
- false, /* isSupplicantTransient */
- scanDetails);
-
- verifySelectedResult(chosenScanResult, candidate);
- //Verify two scanDetails returned in the filteredScanDetails
- assertEquals(2, mWifiQualifiedNetworkSelector.getFilteredScanDetails().size());
- assertEquals(mWifiQualifiedNetworkSelector.getFilteredScanDetails().get(0).first.toString(),
- scanDetails.get(0).toString());
- assertEquals(mWifiQualifiedNetworkSelector.getFilteredScanDetails().get(1).first.toString(),
- scanDetails.get(3).toString());
- }
-
-
- /**
- * Case #35 Test Filtering of potential candidate scanDetails (Untrusted disallowed)
- *
- * In this test. we simulate following scenario
- * WifiStateMachine is under disconnected state
- * test1 is @ 2GHz with RSSI -60
- * test2 is @ 5Ghz with RSSI -86, (below minimum threshold)
- * test3 is @ 5Ghz with RSSI -50, however it has no associated saved config
- * test4 is @ 2Ghz with RSSI -62, no associated config, but is Ephemeral
- *
- * Expected behavior: test1 is chosen due to 5GHz signal is too weak (5GHz bonus can not
- * compensate).
- * test1 & test4's scanDetails are returned by 'getFilteredScanDetail()'
- */
- @Test
- public void testGetFilteredScanDetailsReturnsOnlyConsideredScanDetails_untrustedDisallowed() {
- String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\""};
- String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55",
- "c0:ff:ee:ee:e3:ee"};
- int[] frequencies = {2437, 5180, 5180, 2437};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]",
- "[WPA2-EAP-CCMP][ESS]"};
- int[] levels = {-60, -86, -50, -62};
- int[] security = {SECURITY_PSK, SECURITY_PSK, SECURITY_PSK, SECURITY_PSK};
- boolean[] meteredHints = {false, false, false, true};
- Integer[] scores = {null, null, null, 120};
-
- //Create all 4 scanDetails
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
-
- //Setup NetworkScoreCache for detecting ephemeral networks ("test4")
- configureScoreCache(scanDetails, scores, meteredHints);
- ScanResult untrustedScanResult = scanDetails.get(3).getScanResult();
- WifiConfiguration unTrustedNetworkCandidate =
- ScanResultUtil.createNetworkFromScanResult(untrustedScanResult);
-
- //Set up associated configs for test1 & test2
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(
- Arrays.copyOfRange(ssids, 0, 2), Arrays.copyOfRange(security, 0, 2));
- prepareConfigStore(savedConfigs);
- List<ScanDetail> savedScanDetails = new ArrayList<ScanDetail>(scanDetails.subList(0, 2));
- scanResultLinkConfiguration(savedConfigs, savedScanDetails);
-
- setupEphemeralNetwork(2, scanDetails.get(2).getScanResult(), meteredHints[2]);
- setupEphemeralNetwork(3, scanDetails.get(3).getScanResult(), meteredHints[3]);
-
- //Force mock ConfigManager to return null (and not an empty list) for "test3" & "test4"
- when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(eq(scanDetails.get(2))))
- .thenReturn(null);
- when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(eq(scanDetails.get(3))))
- .thenReturn(null);
-
- ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(
- false /* forceSelectNetwork */,
- false /* isUntrustedConnectionsAllowed */,
- false, /* isLinkDebouncing */
- false, /* isConnected */
- true, /* isDisconnected */
- false, /* isSupplicantTransient */
- scanDetails);
-
- verifySelectedResult(chosenScanResult, candidate);
- //Verify two scanDetails returned in the filteredScanDetails
- assertEquals(1, mWifiQualifiedNetworkSelector.getFilteredScanDetails().size());
- assertEquals(mWifiQualifiedNetworkSelector.getFilteredScanDetails().get(0).first.toString(),
- scanDetails.get(0).toString());
- }
-
- /**
- * Case #36 Ignore an ephemeral network if it was previously deleted.
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is not connected to any network.
- * selectQualifiedNetwork() is called with 2 scan results, test1 and test2.
- * test1 is an open network with a low score. Additionally it's a metered network.
- * test2 is an open network with a good score but was previously deleted.
- * isUntrustedConnectionsAllowed is set to true.
- *
- * expected result: return test1 with meteredHint set to True.
- */
- @Test
- public void selectQualifiedNetworkDoesNotChooseDeletedEphemeral() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {5200, 5200};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[ESS]"};
- int[] levels = {-70, -70};
- Integer[] scores = {20, 120};
- boolean[] meteredHints = {true, false};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- configureScoreCache(scanDetails, scores, meteredHints);
-
- // No saved networks.
- when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(any(ScanDetail.class)))
- .thenReturn(null);
-
- ScanResult untrustedScanResult = scanDetails.get(0).getScanResult();
- WifiConfiguration unTrustedNetworkCandidate =
- setupEphemeralNetwork(0, untrustedScanResult, meteredHints[0]);
-
- // The second scan result is for an ephemeral network which was previously deleted
- when(mWifiConfigManager
- .wasEphemeralNetworkDeleted(scanDetails.get(0).getScanResult().SSID))
- .thenReturn(false);
- when(mWifiConfigManager
- .wasEphemeralNetworkDeleted(scanDetails.get(1).getScanResult().SSID))
- .thenReturn(true);
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(
- false /* forceSelectNetwork */,
- true /* isUntrustedConnectionsAllowed */,
- false, /* isLinkDebouncing */
- false, /* isConnected */
- true, /* isDisconnected */
- false, /* isSupplicantTransient */
- scanDetails);
- WifiConfigurationTestUtil.assertConfigurationEqual(unTrustedNetworkCandidate, candidate);
- verifySelectedResult(untrustedScanResult, candidate);
- assertEquals(meteredHints[0], candidate.meteredHint);
- }
-
- /**
- * Case #37 Choose the saved config that doesn't qualify for external scoring.
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is not connected to any network.
- * selectQualifiedNetwork() is called with 2 scan results, test1 and test2.
- * test1 is a saved network.
- * test2 is a saved network with useExternalScores set to true and a very high score.
- *
- * expected result: return test1 because saved networks that don't request external scoring
- * have a higher priority.
- */
- @Test
- public void selectQualifiedNetworkPrefersSavedWithoutExternalScores() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {5200, 5200};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[ESS]"};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
- int[] levels = {-70, -70};
- Integer[] scores = {null, 120};
- boolean[] meteredHints = {false, true};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- configureScoreCache(scanDetails, scores, meteredHints);
-
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(DEFAULT_SSIDS, security);
- savedConfigs[1].useExternalScores = true; // test2 is set to use external scores.
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(
- false /* forceSelectNetwork */,
- false /* isUntrustedConnectionsAllowed */,
- false, /* isLinkDebouncing */
- false, /* isConnected */
- true, /* isDisconnected */
- false, /* isSupplicantTransient */
- scanDetails);
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(scanDetails.get(0).getScanResult(), candidate);
- }
-
- /**
- * Case #38 Choose the saved config that does qualify for external scoring when other saved
- * networks are not available.
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is not connected to any network.
- * selectQualifiedNetwork() is called with 2 scan results, test1 and test2.
- * test1 is a saved network with useExternalScores set to true and a very high score.
- * test2 is a saved network but not in range (not included in the scan results).
- *
- * expected result: return test1 because there are no better saved networks within range.
- */
- @Test
- public void selectQualifiedNetworkSelectsSavedWithExternalScores() {
- String[] ssids = {"\"test1\""};
- String[] bssids = {"6c:f3:7f:ae:8c:f3"};
- int[] frequencies = {5200};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]"};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
- int[] levels = {-70};
- Integer[] scores = {120};
- boolean[] meteredHints = {false};
-
- // Scan details only contains 1 ssid, test1.
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- configureScoreCache(scanDetails, scores, meteredHints);
-
- // The saved config contains 2 ssids, test1 & test2.
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(DEFAULT_SSIDS, security);
- savedConfigs[0].useExternalScores = true; // test1 is set to use external scores.
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(
- false /* forceSelectNetwork */,
- false /* isUntrustedConnectionsAllowed */,
- false, /* isLinkDebouncing */
- false, /* isConnected */
- true, /* isDisconnected */
- false, /* isSupplicantTransient */
- scanDetails);
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(scanDetails.get(0).getScanResult(), candidate);
- }
-
- /**
- * Case #39 Choose the saved config that does qualify for external scoring over the
- * untrusted network with the same score.
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is not connected to any network.
- * selectQualifiedNetwork() is called with 2 scan results, test1 and test2.
- * test1 is a saved network with useExternalScores set to true and the same score as test2.
- * test2 is NOT saved network but in range with a good external score.
- *
- * expected result: return test1 because the tie goes to the saved network.
- */
- @Test
- public void selectQualifiedNetworkPrefersSavedWithExternalScoresOverUntrusted() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {5200, 5200};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[ESS]"};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
- int[] levels = {-70, -70};
- Integer[] scores = {120, 120};
- boolean[] meteredHints = {false, true};
-
- // Both networks are in the scan results.
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- configureScoreCache(scanDetails, scores, meteredHints);
-
- // Set up the associated configs only for test1
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(
- Arrays.copyOfRange(ssids, 0, 1), Arrays.copyOfRange(security, 0, 1));
- savedConfigs[0].useExternalScores = true; // test1 is set to use external scores.
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- setupEphemeralNetwork(1, scanDetails.get(1).getScanResult(), meteredHints[1]);
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(
- false /* forceSelectNetwork */,
- true /* isUntrustedConnectionsAllowed */,
- false, /* isLinkDebouncing */
- false, /* isConnected */
- true, /* isDisconnected */
- false, /* isSupplicantTransient */
- scanDetails);
- WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
- verifySelectedResult(scanDetails.get(0).getScanResult(), candidate);
- }
-
- /**
- * Case #40 Choose the ephemeral config over the saved config that does qualify for external
- * scoring because the untrusted network has a higher score.
- *
- * In this test. we simulate following scenario:
- * WifiStateMachine is not connected to any network.
- * selectQualifiedNetwork() is called with 2 scan results, test1 and test2.
- * test1 is a saved network with useExternalScores set to true and a low score.
- * test2 is NOT saved network but in range with a good external score.
- *
- * expected result: return test2 because it has a better score.
- */
- @Test
- public void selectQualifiedNetworkPrefersUntrustedOverScoredSaved() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {5200, 5200};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[ESS]"};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
- int[] levels = {-70, -70};
- Integer[] scores = {10, 120};
- boolean[] meteredHints = {false, true};
-
- // Both networks are in the scan results.
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- configureScoreCache(scanDetails, scores, meteredHints);
-
- // Set up the associated configs only for test1
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(
- Arrays.copyOfRange(ssids, 0, 1), Arrays.copyOfRange(security, 0, 1));
- savedConfigs[0].useExternalScores = true; // test1 is set to use external scores.
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- ScanResult untrustedScanResult = scanDetails.get(1).getScanResult();
- WifiConfiguration unTrustedNetworkCandidate =
- setupEphemeralNetwork(1, untrustedScanResult, meteredHints[1]);
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(
- false /* forceSelectNetwork */,
- true /* isUntrustedConnectionsAllowed */,
- false, /* isLinkDebouncing */
- false, /* isConnected */
- true, /* isDisconnected */
- false, /* isSupplicantTransient */
- scanDetails);
- WifiConfigurationTestUtil.assertConfigurationEqual(unTrustedNetworkCandidate, candidate);
- verifySelectedResult(untrustedScanResult, candidate);
- }
-
-
- /**
- * Case #41 Ensure the ExternalScoreEvaluator correctly selects the untrusted network.
- *
- * In this test. we simulate following scenario:
- * The ExternalScoreEvaluator is asked to evaluate 1 untrusted network and 1 saved network.
- * The untrusted network has the higher score.
- *
- * expected result: The untrusted network is determined to be the best network.
- */
- @Test
- public void externalScoreEvaluator_untrustedIsBest() {
- WifiQualifiedNetworkSelector.ExternalScoreEvaluator evaluator =
- new WifiQualifiedNetworkSelector.ExternalScoreEvaluator(mLocalLog, true);
- ScanResult untrustedScanResult = new ScanResult();
- int untrustedScore = 100;
- evaluator.evalUntrustedCandidate(untrustedScore, untrustedScanResult);
-
- ScanResult savedScanResult = new ScanResult();
- int savedScore = 50;
- WifiConfiguration savedConfig = new WifiConfiguration();
- evaluator.evalSavedCandidate(savedScore, savedConfig, savedScanResult);
- assertEquals(WifiQualifiedNetworkSelector.ExternalScoreEvaluator
- .BestCandidateType.UNTRUSTED_NETWORK, evaluator.getBestCandidateType());
- assertEquals(untrustedScore, evaluator.getHighScore());
- assertSame(untrustedScanResult, evaluator.getScanResultCandidate());
- }
-
- /**
- * Case #42 Ensure the ExternalScoreEvaluator correctly selects the saved network.
- *
- * In this test. we simulate following scenario:
- * The ExternalScoreEvaluator is asked to evaluate 1 untrusted network and 1 saved network.
- * The saved network has the higher score.
- *
- * expected result: The saved network is determined to be the best network.
- */
- @Test
- public void externalScoreEvaluator_savedIsBest() {
- WifiQualifiedNetworkSelector.ExternalScoreEvaluator evaluator =
- new WifiQualifiedNetworkSelector.ExternalScoreEvaluator(mLocalLog, true);
- ScanResult untrustedScanResult = new ScanResult();
- int untrustedScore = 50;
- evaluator.evalUntrustedCandidate(untrustedScore, untrustedScanResult);
-
- ScanResult savedScanResult = new ScanResult();
- int savedScore = 100;
- WifiConfiguration savedConfig = new WifiConfiguration();
- evaluator.evalSavedCandidate(savedScore, savedConfig, savedScanResult);
- assertEquals(WifiQualifiedNetworkSelector.ExternalScoreEvaluator
- .BestCandidateType.SAVED_NETWORK, evaluator.getBestCandidateType());
- assertEquals(savedScore, evaluator.getHighScore());
- assertSame(savedScanResult, evaluator.getScanResultCandidate());
- }
-
- /**
- * Case #43 Ensure the ExternalScoreEvaluator correctly selects the saved network if a
- * tie occurs.
- *
- * In this test. we simulate following scenario:
- * The ExternalScoreEvaluator is asked to evaluate 1 untrusted network and 1 saved network.
- * Both networks have the same score.
- *
- * expected result: The saved network is determined to be the best network.
- */
- @Test
- public void externalScoreEvaluator_tieScores() {
- WifiQualifiedNetworkSelector.ExternalScoreEvaluator evaluator =
- new WifiQualifiedNetworkSelector.ExternalScoreEvaluator(mLocalLog, true);
- ScanResult untrustedScanResult = new ScanResult();
- int untrustedScore = 100;
- evaluator.evalUntrustedCandidate(untrustedScore, untrustedScanResult);
-
- ScanResult savedScanResult = new ScanResult();
- int savedScore = 100;
- WifiConfiguration savedConfig = new WifiConfiguration();
- evaluator.evalSavedCandidate(savedScore, savedConfig, savedScanResult);
- assertEquals(WifiQualifiedNetworkSelector.ExternalScoreEvaluator
- .BestCandidateType.SAVED_NETWORK, evaluator.getBestCandidateType());
- assertEquals(savedScore, evaluator.getHighScore());
- assertSame(savedScanResult, evaluator.getScanResultCandidate());
- }
-
- /**
- * Case #44 Ensure the ExternalScoreEvaluator correctly selects the saved network out of
- * multiple options.
- *
- * In this test. we simulate following scenario:
- * The ExternalScoreEvaluator is asked to evaluate 2 untrusted networks and 2 saved networks.
- * The high scores are equal and the low scores differ.
- *
- * expected result: The saved network is determined to be the best network.
- */
- @Test
- public void externalScoreEvaluator_multipleScores() {
- WifiQualifiedNetworkSelector.ExternalScoreEvaluator evaluator =
- new WifiQualifiedNetworkSelector.ExternalScoreEvaluator(mLocalLog, true);
- ScanResult untrustedScanResult = new ScanResult();
- int untrustedScore = 100;
- evaluator.evalUntrustedCandidate(untrustedScore, untrustedScanResult);
- evaluator.evalUntrustedCandidate(80, new ScanResult());
-
- ScanResult savedScanResult = new ScanResult();
- int savedScore = 100;
- WifiConfiguration savedConfig = new WifiConfiguration();
- evaluator.evalSavedCandidate(savedScore, savedConfig, savedScanResult);
- evaluator.evalSavedCandidate(90, new WifiConfiguration(), new ScanResult());
- assertEquals(WifiQualifiedNetworkSelector.ExternalScoreEvaluator
- .BestCandidateType.SAVED_NETWORK, evaluator.getBestCandidateType());
- assertEquals(savedScore, evaluator.getHighScore());
- assertSame(savedScanResult, evaluator.getScanResultCandidate());
- }
-
- /**
- * Case #45 Ensure the ExternalScoreEvaluator correctly handles NULL score inputs.
- *
- * In this test we simulate following scenario:
- * The ExternalScoreEvaluator is asked to evaluate both types of candidates with NULL scores.
- *
- * expected result: No crashes. The best candidate type is returned as NONE.
- */
- @Test
- public void externalScoreEvaluator_nullScores() {
- WifiQualifiedNetworkSelector.ExternalScoreEvaluator evaluator =
- new WifiQualifiedNetworkSelector.ExternalScoreEvaluator(mLocalLog, true);
- evaluator.evalUntrustedCandidate(null, new ScanResult());
- assertEquals(WifiQualifiedNetworkSelector.ExternalScoreEvaluator
- .BestCandidateType.NONE, evaluator.getBestCandidateType());
- evaluator.evalSavedCandidate(null, new WifiConfiguration(), new ScanResult());
- assertEquals(WifiQualifiedNetworkSelector.ExternalScoreEvaluator
- .BestCandidateType.NONE, evaluator.getBestCandidateType());
- }
-
- /**
- * Case #48 5GHz due to user band preference is set to AUTO
- *
- * In this test. we simulate following scenario
- * WifiStateMachine is under disconnected state
- * User band preference is set to AUTO
- * Two networks test1, test2 are secured network
- * Both network are enabled
- * test1 is @ 2GHz with RSSI -50
- * test2 is @ 5Ghz with RSSI -50
- *
- * Expected behavior: test2 is chosen due to 5G bonus and user band preference
- * is set to AUTO.
- */
- @Test
- public void chooseNetworkDisconnectUserPreferAutoBandTest() {
- String[] ssids = DEFAULT_SSIDS;
- String[] bssids = DEFAULT_BSSIDS;
- int[] frequencies = {2437, 5180};
- String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
- int[] levels = {-50, -50};
- int[] security = {SECURITY_PSK, SECURITY_PSK};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
-
- scanResultLinkConfiguration(savedConfigs, scanDetails);
- ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- verifySelectedResult(chosenScanResult, candidate);
- }
-
- /**
- * Case #49 Choose 2.4GHz BSSID with stronger RSSI value over
- * 5GHz BSSID with weaker RSSI value
- *
- * In this test. we simulate following scenario:
- * Two APs are found in scan results
- * BSSID1 is @ 5GHz with RSSI -82
- * BSSID2 is @ 2Ghz with RSSI -72
- * These two BSSIDs get exactly the same QNS score
- *
- * expect BSSID2 to be chosen as it has stronger RSSI value
- */
- @Test
- public void chooseStrongerRssiOver5GHz() {
- String[] ssids = {"\"test1\"", "\"test1\""};
- String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
- int[] frequencies = {5220, 2437};
- String[] caps = {"[ESS]", "[ESS]"};
- int[] levels = {-82, -72};
- int[] security = {SECURITY_NONE, SECURITY_NONE};
-
- List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
- WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
- prepareConfigStore(savedConfigs);
- scanResultLinkConfiguration(savedConfigs, scanDetails);
-
- ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
-
- WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
- false, false, false, true, false, scanDetails);
-
- verifySelectedResult(chosenScanResult, candidate);
- }
-}