From f14e4b8fdd949b4ba0feb63dded4d9b233859300 Mon Sep 17 00:00:00 2001 From: Amin Shaikh Date: Fri, 14 Apr 2017 15:02:09 -0700 Subject: Create ScoredNetworkEvaluator. - Bring back WifiNetworkScoreCache into the wifi framework - Replace RecommendedNetworkEvaluator with ScoredNetworkEvalutor, which is the same as the previous ExternalScoreEvaluator (ag/1865733) with some changes: * Check whether a ScanResult matches the current network by comparing the matching WifiConfiguration instead of the current bssid * Only create untrusted WifiConfigurations for open networks * Set candidate ScanResults for all WifiConfigurations - not only the final chosen WifiConfiguration * Mark newly created ephemeral WifiConfiguration as enabled for network selection * Log a maximum of one LocalLog line per round of network selection Bug: 37357981 Test: ./test/wifitests/runtests.sh Change-Id: I99da4edb371928efb7ca7a9dcd28ddaca9209da8 --- .../server/wifi/RecommendedNetworkEvaluator.java | 328 ------------ .../server/wifi/ScoredNetworkEvaluator.java | 322 ++++++++++++ .../server/wifi/WifiConnectivityManager.java | 8 +- .../java/com/android/server/wifi/WifiInjector.java | 20 +- .../wifi/RecommendedNetworkEvaluatorTest.java | 551 -------------------- .../server/wifi/ScoredNetworkEvaluatorTest.java | 577 +++++++++++++++++++++ .../server/wifi/WifiNetworkSelectorTestUtil.java | 21 +- 7 files changed, 933 insertions(+), 894 deletions(-) delete mode 100644 service/java/com/android/server/wifi/RecommendedNetworkEvaluator.java create mode 100644 service/java/com/android/server/wifi/ScoredNetworkEvaluator.java delete mode 100644 tests/wifitests/src/com/android/server/wifi/RecommendedNetworkEvaluatorTest.java create mode 100644 tests/wifitests/src/com/android/server/wifi/ScoredNetworkEvaluatorTest.java diff --git a/service/java/com/android/server/wifi/RecommendedNetworkEvaluator.java b/service/java/com/android/server/wifi/RecommendedNetworkEvaluator.java deleted file mode 100644 index 80d1501a2..000000000 --- a/service/java/com/android/server/wifi/RecommendedNetworkEvaluator.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * 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.ContentResolver; -import android.content.Context; -import android.database.ContentObserver; -import android.net.INetworkScoreCache; -import android.net.NetworkKey; -import android.net.NetworkScoreManager; -import android.net.RecommendationRequest; -import android.net.RecommendationResult; -import android.net.ScoredNetwork; -import android.net.WifiKey; -import android.net.wifi.ScanResult; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiInfo; -import android.os.Handler; -import android.os.Looper; -import android.os.Process; -import android.os.RemoteException; -import android.os.SystemClock; -import android.provider.Settings; -import android.text.TextUtils; -import android.util.ArraySet; -import android.util.LocalLog; -import android.util.LruCache; -import android.util.Pair; -import android.util.Slog; - -import com.android.server.wifi.util.ScanResultUtil; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import javax.annotation.concurrent.GuardedBy; - -/** - * {@link WifiNetworkSelector.NetworkEvaluator} implementation that uses - * {@link NetworkScoreManager#requestRecommendation(RecommendationRequest)}. - */ -public class RecommendedNetworkEvaluator implements WifiNetworkSelector.NetworkEvaluator { - private static final String TAG = "RecNetEvaluator"; - private final NetworkScoreManager mNetworkScoreManager; - private final WifiConfigManager mWifiConfigManager; - private final LocalLog mLocalLog; - private final ContentObserver mContentObserver; - private final RequestedScoreCache mRequestedScoreCache; - private boolean mNetworkRecommendationsEnabled; - - RecommendedNetworkEvaluator(final Context context, ContentResolver contentResolver, - Looper looper, final FrameworkFacade frameworkFacade, - NetworkScoreManager networkScoreManager, WifiConfigManager wifiConfigManager, - LocalLog localLog) { - mRequestedScoreCache = new RequestedScoreCache(frameworkFacade.getLongSetting( - context, Settings.Global.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS, - TimeUnit.DAYS.toMillis(1))); - mNetworkScoreManager = networkScoreManager; - mWifiConfigManager = wifiConfigManager; - mLocalLog = localLog; - mContentObserver = new ContentObserver(new Handler(looper)) { - @Override - public void onChange(boolean selfChange) { - mNetworkRecommendationsEnabled = frameworkFacade.getIntegerSetting(context, - Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0) == 1; - } - }; - frameworkFacade.registerContentObserver(context, - Settings.Global.getUriFor(Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED), - false /* notifyForDescendents */, mContentObserver); - mContentObserver.onChange(false /* unused */); - mNetworkScoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mRequestedScoreCache, - NetworkScoreManager.CACHE_FILTER_NONE); - mLocalLog.log("RecommendedNetworkEvaluator constructed. mNetworkRecommendationsEnabled: " - + mNetworkRecommendationsEnabled); - } - - @Override - public void update(List scanDetails) { - if (mNetworkRecommendationsEnabled) { - updateNetworkScoreCache(scanDetails); - } - clearNotRecommendedFlag(); - } - - private void updateNetworkScoreCache(List scanDetails) { - ArrayList unscoredNetworks = new ArrayList(); - - for (int i = 0; i < scanDetails.size(); i++) { - ScanResult scanResult = scanDetails.get(i).getScanResult(); - try { - WifiKey wifiKey = new WifiKey( - ScanResultUtil.createQuotedSSID(scanResult.SSID), scanResult.BSSID); - // Have we requested a score for this network? If not, request a score. - if (mRequestedScoreCache.shouldRequestScore(wifiKey)) { - unscoredNetworks.add(new NetworkKey(wifiKey)); - } - } catch (IllegalArgumentException e) { - mLocalLog.log("Invalid SSID=" + scanResult.SSID + " BSSID=" + scanResult.BSSID - + " for network score. Skip."); - } - } - - // Kick the score manager if there are any unscored network. - if (!unscoredNetworks.isEmpty()) { - NetworkKey[] unscoredNetworkKeys = - unscoredNetworks.toArray(new NetworkKey[unscoredNetworks.size()]); - mNetworkScoreManager.requestScores(unscoredNetworkKeys); - } - } - - private void clearNotRecommendedFlag() { - List savedNetworks = mWifiConfigManager.getSavedNetworks(); - for (int i = 0; i < savedNetworks.size(); i++) { - mWifiConfigManager.updateNetworkNotRecommended( - savedNetworks.get(i).networkId, false /* notRecommended*/); - } - } - - @Override - public WifiConfiguration evaluateNetworks(List scanDetails, - WifiConfiguration currentNetwork, String currentBssid, boolean connected, - boolean untrustedNetworkAllowed, - List> connectableNetworks) { - if (!mNetworkRecommendationsEnabled) { - mLocalLog.log("Skipping evaluateNetworks; Network recommendations disabled."); - return null; - } - Set availableConfiguredNetworks = new ArraySet<>(); - List scanResults = new ArrayList<>(); - for (int i = 0; i < scanDetails.size(); i++) { - ScanDetail scanDetail = scanDetails.get(i); - ScanResult scanResult = scanDetail.getScanResult(); - if (scanResult == null) continue; - if (mWifiConfigManager.wasEphemeralNetworkDeleted( - ScanResultUtil.createQuotedSSID(scanResult.SSID))) { - continue; - } - - final WifiConfiguration configuredNetwork = - mWifiConfigManager.getSavedNetworkForScanDetailAndCache(scanDetail); - - scanResult.untrusted = configuredNetwork == null || configuredNetwork.ephemeral; - - if (!untrustedNetworkAllowed && scanResult.untrusted) { - continue; - } - - if (configuredNetwork != null) { - if (!configuredNetwork.getNetworkSelectionStatus().isNetworkEnabled()) { - continue; - } - availableConfiguredNetworks.add(configuredNetwork); - } - scanResults.add(scanResult); - // Track potential connectable networks for the watchdog. - if (connectableNetworks != null) { - connectableNetworks.add(Pair.create(scanDetail, configuredNetwork)); - } - } - - if (scanResults.isEmpty()) { - return null; - } - - ScanResult[] scanResultArray = scanResults.toArray(new ScanResult[scanResults.size()]); - WifiConfiguration[] availableConfigsArray = availableConfiguredNetworks - .toArray(new WifiConfiguration[availableConfiguredNetworks.size()]); - int lastSelectedNetworkId = mWifiConfigManager.getLastSelectedNetwork(); - long lastSelectedNetworkTimestamp = mWifiConfigManager.getLastSelectedTimeStamp(); - RecommendationRequest request = new RecommendationRequest.Builder() - .setScanResults(scanResultArray) - .setConnectedWifiConfig(currentNetwork) - .setConnectableConfigs(availableConfigsArray) - .setLastSelectedNetwork(lastSelectedNetworkId, lastSelectedNetworkTimestamp) - // TODO: pass in currently recommended network - .build(); - RecommendationResult result = mNetworkScoreManager.requestRecommendation(request); - if (result == null) { - // Recommendation provider could not be reached. - return null; - } - - if (result.getWifiConfiguration() == null) { - // Recommendation provider recommended not connecting to any network. - for (int i = 0; i < availableConfigsArray.length; i++) { - if (availableConfigsArray[i].getNetworkSelectionStatus().isNetworkEnabled()) { - mWifiConfigManager.updateNetworkNotRecommended( - availableConfigsArray[i].networkId, true /* notRecommended*/); - } - } - return null; - } - - WifiConfiguration recommendedConfig = result.getWifiConfiguration(); - ScanDetail matchingScanDetail = findMatchingScanDetail(scanDetails, recommendedConfig); - if (matchingScanDetail == null) { - Slog.e(TAG, "Could not match WifiConfiguration to a ScanDetail."); - return null; - } - ScanResult matchingScanResult = matchingScanDetail.getScanResult(); - - // Look for a matching saved config. This can be null for ephemeral networks. - final WifiConfiguration existingConfig = - mWifiConfigManager.getSavedNetworkForScanDetailAndCache(matchingScanDetail); - - final int networkId; - if (existingConfig == null) { // attempt to add a new ephemeral network. - networkId = addEphemeralNetwork(recommendedConfig, matchingScanResult); - if (networkId == WifiConfiguration.INVALID_NETWORK_ID) { - return null; - } - } else { // Use the existing config - networkId = existingConfig.networkId; - } - mWifiConfigManager.setNetworkCandidateScanResult(networkId, - matchingScanResult, 0 /* score */); - return mWifiConfigManager.getConfiguredNetwork(networkId); - } - - private static ScanDetail findMatchingScanDetail(List scanDetails, - WifiConfiguration wifiConfiguration) { - String ssid = WifiInfo.removeDoubleQuotes(wifiConfiguration.SSID); - String bssid = wifiConfiguration.BSSID; - boolean ignoreBssid = TextUtils.isEmpty(bssid) || "any".equals(bssid); - for (int i = 0; i < scanDetails.size(); i++) { - final ScanDetail scanDetail = scanDetails.get(i); - if (ssid.equals(scanDetail.getSSID()) - && (ignoreBssid || bssid.equals(scanDetail.getBSSIDString()))) { - return scanDetail; - } - } - - return null; - } - - private int addEphemeralNetwork(WifiConfiguration wifiConfiguration, ScanResult scanResult) { - if (wifiConfiguration.allowedKeyManagement.isEmpty()) { - ScanResultUtil.setAllowedKeyManagementFromScanResult(scanResult, - wifiConfiguration); - } - wifiConfiguration.ephemeral = true; - wifiConfiguration.BSSID = null; - NetworkUpdateResult networkUpdateResult = mWifiConfigManager - .addOrUpdateNetwork(wifiConfiguration, Process.WIFI_UID); - if (networkUpdateResult.isSuccess()) { - return networkUpdateResult.getNetworkId(); - } - mLocalLog.log("Failed to add ephemeral network for networkId: " - + WifiNetworkSelector.toScanId(scanResult)); - return WifiConfiguration.INVALID_NETWORK_ID; - } - - @Override - public String getName() { - return TAG; - } - - /** Cache for scores that have already been requested. */ - static class RequestedScoreCache extends INetworkScoreCache.Stub { - /** Number entries to be stored in the {@link LruCache} of requested {@link WifiKey}s. */ - private static final int MAX_CACHE_SIZE = 1000; - - private final long mCacheExpiryMillis; - @GuardedBy("mCache") - private final LruCache mCache = new LruCache<>(MAX_CACHE_SIZE); - @GuardedBy("mCache") - private long mCacheCreationTime; - - RequestedScoreCache(long cacheExpiryMillis) { - mCacheExpiryMillis = cacheExpiryMillis; - } - - /** Returns whether a score should be requested for a given {@code wifiKey}. */ - public boolean shouldRequestScore(WifiKey wifiKey) { - long nowMillis = SystemClock.elapsedRealtime(); - long oldestUsableCacheTimeMillis = nowMillis - mCacheExpiryMillis; - synchronized (mCache) { - if (mCacheCreationTime < oldestUsableCacheTimeMillis) { - mCache.evictAll(); - mCacheCreationTime = nowMillis; - } - boolean shouldRequest = mCache.get(wifiKey) == null; - mCache.put(wifiKey, this); // Update access time for wifiKey. - return shouldRequest; - } - } - - @Override - public void updateScores(List networks) throws RemoteException {} - - @Override - public void clearScores() throws RemoteException { - synchronized (mCache) { - mCache.evictAll(); - mCacheCreationTime = 0; - } - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - writer.println("RequestedScoreCache:"); - writer.println("mCacheExpiryMillis: " + mCacheExpiryMillis); - synchronized (mCache) { - writer.println("mCacheCreationTime: " + mCacheCreationTime); - writer.println("mCache size: " + mCache.size()); - } - } - } -} diff --git a/service/java/com/android/server/wifi/ScoredNetworkEvaluator.java b/service/java/com/android/server/wifi/ScoredNetworkEvaluator.java new file mode 100644 index 000000000..483da9936 --- /dev/null +++ b/service/java/com/android/server/wifi/ScoredNetworkEvaluator.java @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2017 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.database.ContentObserver; +import android.net.NetworkKey; +import android.net.NetworkScoreManager; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiNetworkScoreCache; +import android.os.Handler; +import android.os.Looper; +import android.os.Process; +import android.provider.Settings; +import android.text.TextUtils; +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.List; + +/** + * {@link WifiNetworkSelector.NetworkEvaluator} implementation that uses scores obtained by + * {@link NetworkScoreManager#requestScores(NetworkKey[])} to make network connection decisions. + */ +public class ScoredNetworkEvaluator implements WifiNetworkSelector.NetworkEvaluator { + private static final String TAG = "ScoredNetworkEvaluator"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private final NetworkScoreManager mNetworkScoreManager; + private final WifiConfigManager mWifiConfigManager; + private final LocalLog mLocalLog; + private final ContentObserver mContentObserver; + private boolean mNetworkRecommendationsEnabled; + private WifiNetworkScoreCache mScoreCache; + + ScoredNetworkEvaluator(final Context context, Looper looper, + final FrameworkFacade frameworkFacade, NetworkScoreManager networkScoreManager, + WifiConfigManager wifiConfigManager, LocalLog localLog, + WifiNetworkScoreCache wifiNetworkScoreCache) { + mScoreCache = wifiNetworkScoreCache; + mNetworkScoreManager = networkScoreManager; + mWifiConfigManager = wifiConfigManager; + mLocalLog = localLog; + mContentObserver = new ContentObserver(new Handler(looper)) { + @Override + public void onChange(boolean selfChange) { + mNetworkRecommendationsEnabled = frameworkFacade.getIntegerSetting(context, + Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0) == 1; + } + }; + frameworkFacade.registerContentObserver(context, + Settings.Global.getUriFor(Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED), + false /* notifyForDescendents */, mContentObserver); + mContentObserver.onChange(false /* unused */); + mLocalLog.log("ScoredNetworkEvaluator constructed. mNetworkRecommendationsEnabled: " + + mNetworkRecommendationsEnabled); + } + + @Override + public void update(List scanDetails) { + if (mNetworkRecommendationsEnabled) { + updateNetworkScoreCache(scanDetails); + } + } + + private void updateNetworkScoreCache(List scanDetails) { + ArrayList unscoredNetworks = new ArrayList(); + for (int i = 0; i < scanDetails.size(); i++) { + ScanResult scanResult = scanDetails.get(i).getScanResult(); + NetworkKey networkKey = NetworkKey.createFromScanResult(scanResult); + if (networkKey != null) { + // Is there a ScoredNetwork for this ScanResult? If not, request a score. + if (mScoreCache.getScoredNetwork(networkKey) == null) { + unscoredNetworks.add(networkKey); + } + } + } + + // Kick the score manager if there are any unscored network. + if (!unscoredNetworks.isEmpty()) { + NetworkKey[] unscoredNetworkKeys = + unscoredNetworks.toArray(new NetworkKey[unscoredNetworks.size()]); + mNetworkScoreManager.requestScores(unscoredNetworkKeys); + } + } + + @Override + public WifiConfiguration evaluateNetworks(List scanDetails, + WifiConfiguration currentNetwork, String currentBssid, boolean connected, + boolean untrustedNetworkAllowed, + List> connectableNetworks) { + if (!mNetworkRecommendationsEnabled) { + mLocalLog.log("Skipping evaluateNetworks; Network recommendations disabled."); + return null; + } + + final ScoreTracker scoreTracker = new ScoreTracker(); + for (int i = 0; i < scanDetails.size(); i++) { + ScanDetail scanDetail = scanDetails.get(i); + ScanResult scanResult = scanDetail.getScanResult(); + if (scanResult == null) continue; + if (mWifiConfigManager.wasEphemeralNetworkDeleted( + ScanResultUtil.createQuotedSSID(scanResult.SSID))) { + debugLog("Ignoring disabled ephemeral SSID: " + scanResult.SSID); + continue; + } + final WifiConfiguration configuredNetwork = + mWifiConfigManager.getSavedNetworkForScanDetailAndCache(scanDetail); + boolean untrustedScanResult = configuredNetwork == null || configuredNetwork.ephemeral; + + if (!untrustedNetworkAllowed && untrustedScanResult) { + continue; + } + + // Track scan results for open wifi networks + if (configuredNetwork == null) { + if (ScanResultUtil.isScanResultForOpenNetwork(scanResult)) { + scoreTracker.trackUntrustedCandidate(scanResult); + } + continue; + } + + // Ignore non-ephemeral and non-externally scored networks + if (!configuredNetwork.ephemeral && !configuredNetwork.useExternalScores) { + continue; + } + + // Ignore externally scored or ephemeral networks that have been disabled for selection + if (!configuredNetwork.getNetworkSelectionStatus().isNetworkEnabled()) { + debugLog("Ignoring disabled SSID: " + configuredNetwork.SSID); + continue; + } + + // TODO(b/37485956): consider applying a boost for networks with only the same SSID + boolean isCurrentNetwork = currentNetwork != null + && currentNetwork.networkId == configuredNetwork.networkId + && TextUtils.equals(currentBssid, scanResult.BSSID); + if (configuredNetwork.ephemeral) { + scoreTracker.trackUntrustedCandidate( + scanResult, configuredNetwork, isCurrentNetwork); + } else { + scoreTracker.trackExternallyScoredCandidate( + scanResult, configuredNetwork, isCurrentNetwork); + } + if (connectableNetworks != null) { + connectableNetworks.add(Pair.create(scanDetail, configuredNetwork)); + } + } + + return scoreTracker.getCandidateConfiguration(); + } + + /** Used to track the network with the highest score. */ + class ScoreTracker { + private static final int EXTERNAL_SCORED_NONE = 0; + private static final int EXTERNAL_SCORED_SAVED_NETWORK = 1; + private static final int EXTERNAL_SCORED_UNTRUSTED_NETWORK = 2; + + private int mBestCandidateType = EXTERNAL_SCORED_NONE; + private int mHighScore = WifiNetworkScoreCache.INVALID_NETWORK_SCORE; + private WifiConfiguration mEphemeralConfig; + private WifiConfiguration mSavedConfig; + private ScanResult mScanResultCandidate; + + /** + * Returns the available external network score or null if no score is available. + * + * @param scanResult The scan result of the network to score. + * @param isCurrentNetwork Flag which indicates whether this is the current network. + * @return A valid external score if one is available or NULL. + */ + @Nullable + private Integer getNetworkScore(ScanResult scanResult, boolean isCurrentNetwork) { + if (mScoreCache.isScoredNetwork(scanResult)) { + int score = mScoreCache.getNetworkScore(scanResult, isCurrentNetwork); + if (DEBUG) { + mLocalLog.log(WifiNetworkSelector.toScanId(scanResult) + " has score: " + + score + " isCurrentNetwork network: " + isCurrentNetwork); + } + return score; + } + return null; + } + + /** Track an untrusted {@link ScanResult}. */ + void trackUntrustedCandidate(ScanResult scanResult) { + Integer score = getNetworkScore(scanResult, false /* isCurrentNetwork */); + if (score != null && score > mHighScore) { + mHighScore = score; + mScanResultCandidate = scanResult; + mBestCandidateType = EXTERNAL_SCORED_UNTRUSTED_NETWORK; + debugLog(WifiNetworkSelector.toScanId(scanResult) + + " becomes the new untrusted candidate."); + } + } + + /** + * Track an untrusted {@link ScanResult} that already has a corresponding + * ephemeral {@link WifiConfiguration}. + */ + void trackUntrustedCandidate( + ScanResult scanResult, WifiConfiguration config, boolean isCurrentNetwork) { + Integer score = getNetworkScore(scanResult, isCurrentNetwork); + if (score != null && score > mHighScore) { + mHighScore = score; + mScanResultCandidate = scanResult; + mBestCandidateType = EXTERNAL_SCORED_UNTRUSTED_NETWORK; + mEphemeralConfig = config; + mWifiConfigManager.setNetworkCandidateScanResult(config.networkId, scanResult, 0); + debugLog(WifiNetworkSelector.toScanId(scanResult) + + " becomes the new untrusted candidate."); + } + } + + /** Tracks a saved network that has been marked with useExternalScores */ + void trackExternallyScoredCandidate( + ScanResult scanResult, WifiConfiguration config, boolean isCurrentNetwork) { + // Always take the highest score. If there's a tie and an untrusted network is currently + // the best then pick the saved network. + Integer score = getNetworkScore(scanResult, isCurrentNetwork); + if (score != null + && (score > mHighScore + || (mBestCandidateType == EXTERNAL_SCORED_UNTRUSTED_NETWORK + && score == mHighScore))) { + mHighScore = score; + mSavedConfig = config; + mScanResultCandidate = scanResult; + mBestCandidateType = EXTERNAL_SCORED_SAVED_NETWORK; + mWifiConfigManager.setNetworkCandidateScanResult(config.networkId, scanResult, 0); + debugLog(WifiNetworkSelector.toScanId(scanResult) + + " becomes the new externally scored saved network candidate."); + } + } + + /** Returns the best candidate network tracked by this {@link ScoreTracker}. */ + @Nullable + WifiConfiguration getCandidateConfiguration() { + int candidateNetworkId = WifiConfiguration.INVALID_NETWORK_ID; + switch (mBestCandidateType) { + case ScoreTracker.EXTERNAL_SCORED_UNTRUSTED_NETWORK: + if (mEphemeralConfig != null) { + candidateNetworkId = mEphemeralConfig.networkId; + mLocalLog.log(String.format("existing ephemeral candidate %s network ID:%d" + + ", meteredHint=%b", + WifiNetworkSelector.toScanId(mScanResultCandidate), + candidateNetworkId, + mEphemeralConfig.meteredHint)); + break; + } + + mEphemeralConfig = + ScanResultUtil.createNetworkFromScanResult(mScanResultCandidate); + // Mark this config as ephemeral so it isn't persisted. + mEphemeralConfig.ephemeral = true; + mEphemeralConfig.meteredHint = mScoreCache.getMeteredHint(mScanResultCandidate); + NetworkUpdateResult result = + mWifiConfigManager.addOrUpdateNetwork(mEphemeralConfig, + Process.WIFI_UID); + if (!result.isSuccess()) { + mLocalLog.log("Failed to add ephemeral network"); + break; + } + if (!mWifiConfigManager.updateNetworkSelectionStatus(result.getNetworkId(), + WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE)) { + mLocalLog.log("Failed to make ephemeral network selectable"); + break; + } + candidateNetworkId = result.getNetworkId(); + mWifiConfigManager.setNetworkCandidateScanResult(candidateNetworkId, + mScanResultCandidate, 0); + mLocalLog.log(String.format("new ephemeral candidate %s network ID:%d, " + + "meteredHint=%b", + WifiNetworkSelector.toScanId(mScanResultCandidate), + candidateNetworkId, + mEphemeralConfig.meteredHint)); + break; + case ScoreTracker.EXTERNAL_SCORED_SAVED_NETWORK: + candidateNetworkId = mSavedConfig.networkId; + mLocalLog.log(String.format("new saved network candidate %s network ID:%d", + WifiNetworkSelector.toScanId(mScanResultCandidate), + candidateNetworkId)); + break; + case ScoreTracker.EXTERNAL_SCORED_NONE: + default: + mLocalLog.log("ScoredNetworkEvaluator did not see any good candidates."); + break; + } + return mWifiConfigManager.getConfiguredNetwork(candidateNetworkId); + } + } + + private void debugLog(String msg) { + if (DEBUG) { + mLocalLog.log(msg); + } + } + + @Override + public String getName() { + return TAG; + } +} diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java index bd00b3f5b..010c6b294 100644 --- a/service/java/com/android/server/wifi/WifiConnectivityManager.java +++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java @@ -124,7 +124,7 @@ public class WifiConnectivityManager { // Saved network evaluator priority private static final int SAVED_NETWORK_EVALUATOR_PRIORITY = 1; private static final int PASSPOINT_NETWORK_EVALUATOR_PRIORITY = 2; - private static final int RECOMMENDED_NETWORK_EVALUATOR_PRIORITY = 3; + private static final int SCORED_NETWORK_EVALUATOR_PRIORITY = 3; // Log tag for this class private static final String TAG = "WifiConnectivityManager"; @@ -512,7 +512,7 @@ public class WifiConnectivityManager { Looper looper, Clock clock, LocalLog localLog, boolean enable, FrameworkFacade frameworkFacade, SavedNetworkEvaluator savedNetworkEvaluator, - RecommendedNetworkEvaluator recommendedNetworkEvaluator, + ScoredNetworkEvaluator scoredNetworkEvaluator, PasspointNetworkEvaluator passpointNetworkEvaluator) { mStateMachine = stateMachine; mScanner = scanner; @@ -569,8 +569,8 @@ public class WifiConnectivityManager { mNetworkSelector.registerNetworkEvaluator(passpointNetworkEvaluator, PASSPOINT_NETWORK_EVALUATOR_PRIORITY); } - mNetworkSelector.registerNetworkEvaluator(recommendedNetworkEvaluator, - RECOMMENDED_NETWORK_EVALUATOR_PRIORITY); + mNetworkSelector.registerNetworkEvaluator(scoredNetworkEvaluator, + SCORED_NETWORK_EVALUATOR_PRIORITY); // Register for all single scan results mScanner.registerScanListener(mAllSingleScanListener); diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index c86bf1b93..758aed468 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -18,12 +18,14 @@ package com.android.server.wifi; import android.app.ActivityManager; import android.content.Context; +import android.net.NetworkKey; import android.net.NetworkScoreManager; import android.net.wifi.IApInterface; import android.net.wifi.IWifiScanner; import android.net.wifi.IWificond; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; +import android.net.wifi.WifiNetworkScoreCache; import android.net.wifi.WifiScanner; import android.os.BatteryStats; import android.os.HandlerThread; @@ -106,7 +108,8 @@ public class WifiInjector { private final WifiNetworkSelector mWifiNetworkSelector; private final SavedNetworkEvaluator mSavedNetworkEvaluator; private final PasspointNetworkEvaluator mPasspointNetworkEvaluator; - private final RecommendedNetworkEvaluator mRecommendedNetworkEvaluator; + private final ScoredNetworkEvaluator mScoredNetworkEvaluator; + private final WifiNetworkScoreCache mWifiNetworkScoreCache; private final NetworkScoreManager mNetworkScoreManager; private WifiScanner mWifiScanner; private final WifiPermissionsWrapper mWifiPermissionsWrapper; @@ -140,6 +143,9 @@ public class WifiInjector { mSettingsStore = new WifiSettingsStore(mContext); mWifiPermissionsWrapper = new WifiPermissionsWrapper(mContext); mNetworkScoreManager = mContext.getSystemService(NetworkScoreManager.class); + mWifiNetworkScoreCache = new WifiNetworkScoreCache(mContext); + mNetworkScoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, + mWifiNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE); mWifiPermissionsUtil = new WifiPermissionsUtil(mWifiPermissionsWrapper, mContext, mSettingsStore, UserManager.get(mContext), mNetworkScoreManager, this); mBatteryStats = IBatteryStats.Stub.asInterface(mFrameworkFacade.getService( @@ -198,11 +204,11 @@ public class WifiInjector { mConnectivityLocalLog = new LocalLog(ActivityManager.isLowRamDeviceStatic() ? 256 : 512); mWifiNetworkSelector = new WifiNetworkSelector(mContext, mWifiConfigManager, mClock, mConnectivityLocalLog); - mSavedNetworkEvaluator = new SavedNetworkEvaluator(mContext, mWifiConfigManager, mClock, - mConnectivityLocalLog, mWifiConnectivityHelper); - mRecommendedNetworkEvaluator = new RecommendedNetworkEvaluator(context, - context.getContentResolver(), wifiStateMachineLooper, mFrameworkFacade, - mNetworkScoreManager, mWifiConfigManager, mConnectivityLocalLog); + mSavedNetworkEvaluator = new SavedNetworkEvaluator(mContext, + mWifiConfigManager, mClock, mConnectivityLocalLog, mWifiConnectivityHelper); + mScoredNetworkEvaluator = new ScoredNetworkEvaluator(context, wifiStateMachineLooper, + mFrameworkFacade, mNetworkScoreManager, mWifiConfigManager, mConnectivityLocalLog, + mWifiNetworkScoreCache); mSimAccessor = new SIMAccessor(mContext); mPasspointManager = new PasspointManager(mContext, mWifiNative, mWifiKeyStore, mClock, mSimAccessor, new PasspointObjectFactory(), mWifiConfigManager, mWifiConfigStore); @@ -409,7 +415,7 @@ public class WifiInjector { mWifiConfigManager, wifiInfo, mWifiNetworkSelector, mWifiConnectivityHelper, mWifiLastResortWatchdog, mWifiMetrics, mWifiStateMachineHandlerThread.getLooper(), mClock, mConnectivityLocalLog, hasConnectionRequests, mFrameworkFacade, - mSavedNetworkEvaluator, mRecommendedNetworkEvaluator, mPasspointNetworkEvaluator); + mSavedNetworkEvaluator, mScoredNetworkEvaluator, mPasspointNetworkEvaluator); } public WifiPermissionsUtil getWifiPermissionsUtil() { diff --git a/tests/wifitests/src/com/android/server/wifi/RecommendedNetworkEvaluatorTest.java b/tests/wifitests/src/com/android/server/wifi/RecommendedNetworkEvaluatorTest.java deleted file mode 100644 index ef4f0a3fe..000000000 --- a/tests/wifitests/src/com/android/server/wifi/RecommendedNetworkEvaluatorTest.java +++ /dev/null @@ -1,551 +0,0 @@ -/* - * 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 junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.*; - -import android.content.ContentResolver; -import android.content.Context; -import android.database.ContentObserver; -import android.net.NetworkKey; -import android.net.NetworkScoreManager; -import android.net.RecommendationRequest; -import android.net.RecommendationResult; -import android.net.Uri; -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.os.Looper; -import android.os.Process; -import android.provider.Settings; -import android.test.suitebuilder.annotation.SmallTest; -import android.util.ArraySet; -import android.util.LocalLog; -import android.util.Pair; - -import com.android.server.wifi.util.ScanResultUtil; - -import com.google.android.collect.Lists; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -/** - * Unit tests for {@link RecommendedNetworkEvaluator}. - */ -@SmallTest -public class RecommendedNetworkEvaluatorTest { - private ScanDetail mTrustedScanDetail; - private ScanDetail mUntrustedScanDetail; - private ScanDetail mEphemeralScanDetail; - private WifiConfiguration mTrustedWifiConfiguration; - private WifiConfiguration mUntrustedWifiConfiguration; - private WifiConfiguration mEphemeralWifiConfiguration; - private ContentObserver mContentObserver; - - @Mock private Context mContext; - @Mock private ContentResolver mContentResolver; - @Mock private FrameworkFacade mFrameworkFacade; - @Mock private NetworkScoreManager mNetworkScoreManager; - @Mock private WifiConfigManager mWifiConfigManager; - - @Captor private ArgumentCaptor mNetworkKeyArrayCaptor; - @Captor private ArgumentCaptor mRecommendationRequestCaptor; - - private RecommendedNetworkEvaluator mRecommendedNetworkEvaluator; - - @Before - public void setUp() throws Exception { - mTrustedScanDetail = buildScanDetail("ssid"); - mUntrustedScanDetail = buildScanDetail("ssid1"); - mEphemeralScanDetail = buildScanDetail("ssid2"); - - mTrustedWifiConfiguration = new WifiConfiguration(); - mTrustedWifiConfiguration.networkId = 5; - mTrustedWifiConfiguration.SSID = mTrustedScanDetail.getSSID(); - mTrustedWifiConfiguration.BSSID = mTrustedScanDetail.getBSSIDString(); - mTrustedWifiConfiguration.getNetworkSelectionStatus().setCandidate( - mTrustedScanDetail.getScanResult()); - - mUntrustedWifiConfiguration = new WifiConfiguration(); - mUntrustedWifiConfiguration.networkId = 6; - mUntrustedWifiConfiguration.SSID = mUntrustedScanDetail.getSSID(); - mUntrustedWifiConfiguration.BSSID = mUntrustedScanDetail.getBSSIDString(); - - mEphemeralWifiConfiguration = new WifiConfiguration(); - mEphemeralWifiConfiguration.SSID = mEphemeralScanDetail.getSSID(); - mEphemeralWifiConfiguration.BSSID = mEphemeralScanDetail.getBSSIDString(); - mEphemeralWifiConfiguration.ephemeral = true; - - MockitoAnnotations.initMocks(this); - - when(mFrameworkFacade.getIntegerSetting(mContext, - Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0)) - .thenReturn(1); - long dayMillis = TimeUnit.DAYS.toMillis(1); - when(mFrameworkFacade.getLongSetting(mContext, - Settings.Global.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS, dayMillis)) - .thenReturn(dayMillis); - - ArgumentCaptor observerCaptor = - ArgumentCaptor.forClass(ContentObserver.class); - mRecommendedNetworkEvaluator = new RecommendedNetworkEvaluator(mContext, mContentResolver, - Looper.getMainLooper(), mFrameworkFacade, mNetworkScoreManager, - mWifiConfigManager, new LocalLog(0)); - verify(mFrameworkFacade).registerContentObserver(eq(mContext), any(Uri.class), eq(false), - observerCaptor.capture()); - mContentObserver = observerCaptor.getValue(); - - reset(mNetworkScoreManager); - - when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(mTrustedScanDetail)) - .thenReturn(mTrustedWifiConfiguration); - when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(mUntrustedScanDetail)) - .thenReturn(null); - when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(mEphemeralScanDetail)) - .thenReturn(mEphemeralWifiConfiguration); - when(mWifiConfigManager.getConfiguredNetwork(mTrustedWifiConfiguration.networkId)) - .thenReturn(mTrustedWifiConfiguration); - when(mWifiConfigManager.getSavedNetworks()) - .thenReturn(Lists.newArrayList(mTrustedWifiConfiguration)); - } - - @Test - public void testUpdate_recommendationsDisabled() { - ArrayList scanDetails = new ArrayList<>(); - when(mFrameworkFacade.getIntegerSetting(mContext, - Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0)) - .thenReturn(0); - - mContentObserver.onChange(false /* unused */); - - mRecommendedNetworkEvaluator.update(scanDetails); - - verifyZeroInteractions(mNetworkScoreManager); - verify(mWifiConfigManager).updateNetworkNotRecommended( - mTrustedWifiConfiguration.networkId, false /* notRecommended */); - } - - @Test - public void testUpdate_emptyScanList() { - mRecommendedNetworkEvaluator.update(new ArrayList()); - - verifyZeroInteractions(mNetworkScoreManager); - verify(mWifiConfigManager).updateNetworkNotRecommended( - mTrustedWifiConfiguration.networkId, false /* notRecommended */); - } - - @Test - public void testUpdate_allNetworksUnscored() { - mRecommendedNetworkEvaluator.update(Lists.newArrayList(mTrustedScanDetail, - mUntrustedScanDetail)); - - verify(mWifiConfigManager).updateNetworkNotRecommended( - mTrustedWifiConfiguration.networkId, false /* notRecommended */); - verify(mNetworkScoreManager).requestScores(mNetworkKeyArrayCaptor.capture()); - assertEquals(2, mNetworkKeyArrayCaptor.getValue().length); - NetworkKey expectedNetworkKey = new NetworkKey(new WifiKey(ScanResultUtil.createQuotedSSID( - mTrustedScanDetail.getSSID()), mTrustedScanDetail.getBSSIDString())); - assertEquals(expectedNetworkKey, mNetworkKeyArrayCaptor.getValue()[0]); - expectedNetworkKey = new NetworkKey(new WifiKey(ScanResultUtil.createQuotedSSID( - mUntrustedScanDetail.getSSID()), mUntrustedScanDetail.getBSSIDString())); - assertEquals(expectedNetworkKey, mNetworkKeyArrayCaptor.getValue()[1]); - } - - @Test - public void testUpdate_oneScored_twoScored() { - mRecommendedNetworkEvaluator.update(Lists.newArrayList(mUntrustedScanDetail)); - - // Next scan should only trigger a request for the trusted network. - mRecommendedNetworkEvaluator.update( - Lists.newArrayList(mTrustedScanDetail, mUntrustedScanDetail)); - - verify(mWifiConfigManager, times(2)).updateNetworkNotRecommended( - mTrustedWifiConfiguration.networkId, false /* notRecommended */); - verify(mNetworkScoreManager, times(2)).requestScores(mNetworkKeyArrayCaptor.capture()); - - NetworkKey[] requestedScores = mNetworkKeyArrayCaptor.getAllValues().get(0); - assertEquals(1, requestedScores.length); - NetworkKey expectedNetworkKey = new NetworkKey(new WifiKey(ScanResultUtil.createQuotedSSID( - mUntrustedScanDetail.getSSID()), mUntrustedScanDetail.getBSSIDString())); - assertEquals(expectedNetworkKey, requestedScores[0]); - - requestedScores = mNetworkKeyArrayCaptor.getAllValues().get(1); - assertEquals(1, requestedScores.length); - expectedNetworkKey = new NetworkKey(new WifiKey(ScanResultUtil.createQuotedSSID( - mTrustedScanDetail.getSSID()), mTrustedScanDetail.getBSSIDString())); - assertEquals(expectedNetworkKey, requestedScores[0]); - } - - @Test - public void testEvaluateNetworks_recommendationsDisabled() { - when(mFrameworkFacade.getIntegerSetting(mContext, - Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0)) - .thenReturn(0); - - mContentObserver.onChange(false /* unused */); - - mRecommendedNetworkEvaluator.evaluateNetworks(null, null, null, false, false, null); - - verifyZeroInteractions(mWifiConfigManager, mNetworkScoreManager); - } - - @Test - public void testEvaluateNetworks_emptyScanList() { - WifiConfiguration result = mRecommendedNetworkEvaluator.evaluateNetworks( - new ArrayList(), null, null, false, - false /* untrustedNetworkAllowed */, null); - - assertNull(result); - verifyZeroInteractions(mWifiConfigManager, mNetworkScoreManager); - } - - @Test - public void testEvaluateNetworks_onlyTrustedNetworksAllowed_noTrustedInScanList() { - WifiConfiguration result = mRecommendedNetworkEvaluator.evaluateNetworks( - Lists.newArrayList(mUntrustedScanDetail), null, null, false, - false /* untrustedNetworkAllowed */, null); - - assertNull(result); - verifyZeroInteractions(mNetworkScoreManager); - } - - @Test - public void testEvaluateNetworks_untrustedNetworksAllowed_onlyDeletedEphemeral() { - when(mWifiConfigManager.wasEphemeralNetworkDeleted(ScanResultUtil - .createQuotedSSID(mUntrustedScanDetail.getScanResult().SSID))) - .thenReturn(true); - - WifiConfiguration result = mRecommendedNetworkEvaluator.evaluateNetworks( - Lists.newArrayList(mUntrustedScanDetail), null, null, false, - true /* untrustedNetworkAllowed */, null); - - assertNull(result); - verifyZeroInteractions(mNetworkScoreManager); - } - - @Test - public void testEvaluateNetworks_recommendation_onlyTrustedNetworkAllowed() { - when(mWifiConfigManager.wasEphemeralNetworkDeleted(anyString())).thenReturn(false); - when(mNetworkScoreManager.requestRecommendation(any(RecommendationRequest.class))) - .thenReturn(RecommendationResult - .createConnectRecommendation(mTrustedWifiConfiguration)); - - WifiConfiguration result = mRecommendedNetworkEvaluator.evaluateNetworks( - Lists.newArrayList(mTrustedScanDetail, mUntrustedScanDetail), - null, null, false, false /* untrustedNetworkAllowed */, null); - - assertEquals(mTrustedWifiConfiguration, result); - verify(mNetworkScoreManager).requestRecommendation(mRecommendationRequestCaptor.capture()); - assertEquals(1, mRecommendationRequestCaptor.getValue().getScanResults().length); - assertEquals(mTrustedScanDetail.getScanResult(), - mRecommendationRequestCaptor.getValue().getScanResults()[0]); - verify(mWifiConfigManager).setNetworkCandidateScanResult( - mTrustedWifiConfiguration.networkId, mTrustedScanDetail.getScanResult(), 0); - } - - @Test - public void testEvaluateNetworks_trustedRecommendation_untrustedNetworksAllowed() { - when(mWifiConfigManager.wasEphemeralNetworkDeleted(anyString())).thenReturn(false); - when(mNetworkScoreManager.requestRecommendation(any(RecommendationRequest.class))) - .thenReturn(RecommendationResult - .createConnectRecommendation(mTrustedWifiConfiguration)); - - WifiConfiguration result = mRecommendedNetworkEvaluator.evaluateNetworks( - Lists.newArrayList(mTrustedScanDetail, mUntrustedScanDetail), - null, null, false, true /* untrustedNetworkAllowed */, null); - - assertEquals(mTrustedWifiConfiguration, result); - verify(mNetworkScoreManager).requestRecommendation(mRecommendationRequestCaptor.capture()); - assertEquals(2, mRecommendationRequestCaptor.getValue().getScanResults().length); - assertEquals(mTrustedScanDetail.getScanResult(), - mRecommendationRequestCaptor.getValue().getScanResults()[0]); - assertEquals(mUntrustedScanDetail.getScanResult(), - mRecommendationRequestCaptor.getValue().getScanResults()[1]); - verify(mWifiConfigManager).setNetworkCandidateScanResult( - mTrustedWifiConfiguration.networkId, mTrustedScanDetail.getScanResult(), 0); - } - - @Test - public void testEvaluateNetworks_trustedRecommendation_anyBssidSpecified() { - WifiConfiguration recommendedNetwork = new WifiConfiguration(); - recommendedNetwork.SSID = mTrustedWifiConfiguration.SSID; - recommendedNetwork.BSSID = "any"; - - when(mWifiConfigManager.wasEphemeralNetworkDeleted(anyString())).thenReturn(false); - when(mNetworkScoreManager.requestRecommendation(any(RecommendationRequest.class))) - .thenReturn(RecommendationResult.createConnectRecommendation(recommendedNetwork)); - - WifiConfiguration result = mRecommendedNetworkEvaluator.evaluateNetworks( - Lists.newArrayList(mTrustedScanDetail), - null, null, false, false /* untrustedNetworkAllowed */, null); - - assertEquals(mTrustedWifiConfiguration, result); - verify(mNetworkScoreManager).requestRecommendation(mRecommendationRequestCaptor.capture()); - assertEquals(1, mRecommendationRequestCaptor.getValue().getScanResults().length); - assertEquals(mTrustedScanDetail.getScanResult(), - mRecommendationRequestCaptor.getValue().getScanResults()[0]); - verify(mWifiConfigManager).setNetworkCandidateScanResult( - mTrustedWifiConfiguration.networkId, mTrustedScanDetail.getScanResult(), 0); - } - - @Test - public void testEvaluateNetworks_untrustedRecommendation_untrustedNetworksAllowed() { - NetworkUpdateResult networkUpdateResult = new NetworkUpdateResult(10); - when(mWifiConfigManager.addOrUpdateNetwork(mUntrustedWifiConfiguration, Process.WIFI_UID)) - .thenReturn(networkUpdateResult); - when(mWifiConfigManager.getConfiguredNetwork(networkUpdateResult.getNetworkId())) - .thenReturn(mUntrustedWifiConfiguration); - when(mWifiConfigManager.wasEphemeralNetworkDeleted(anyString())).thenReturn(false); - when(mNetworkScoreManager.requestRecommendation(any(RecommendationRequest.class))) - .thenReturn(RecommendationResult - .createConnectRecommendation(mUntrustedWifiConfiguration)); - - WifiConfiguration result = mRecommendedNetworkEvaluator.evaluateNetworks( - Lists.newArrayList(mTrustedScanDetail, mUntrustedScanDetail), - null, null, false, true /* untrustedNetworkAllowed */, null); - - assertEquals(mUntrustedWifiConfiguration, result); - assertNull(result.BSSID); - verify(mNetworkScoreManager).requestRecommendation(mRecommendationRequestCaptor.capture()); - assertEquals(2, mRecommendationRequestCaptor.getValue().getScanResults().length); - assertEquals(mTrustedScanDetail.getScanResult(), - mRecommendationRequestCaptor.getValue().getScanResults()[0]); - assertEquals(mUntrustedScanDetail.getScanResult(), - mRecommendationRequestCaptor.getValue().getScanResults()[1]); - verify(mWifiConfigManager).setNetworkCandidateScanResult( - networkUpdateResult.getNetworkId(), mUntrustedScanDetail.getScanResult(), 0); - verify(mWifiConfigManager, never()).updateNetworkSelectionStatus(anyInt(), anyInt()); - } - - @Test - public void testEvaluateNetworks_untrustedRecommendation_updateFailed() { - NetworkUpdateResult networkUpdateResult = new NetworkUpdateResult( - WifiConfiguration.INVALID_NETWORK_ID); - when(mWifiConfigManager.addOrUpdateNetwork(mUntrustedWifiConfiguration, Process.WIFI_UID)) - .thenReturn(networkUpdateResult); - when(mWifiConfigManager.wasEphemeralNetworkDeleted(anyString())).thenReturn(false); - when(mNetworkScoreManager.requestRecommendation(any(RecommendationRequest.class))) - .thenReturn(RecommendationResult - .createConnectRecommendation(mUntrustedWifiConfiguration)); - - WifiConfiguration result = mRecommendedNetworkEvaluator.evaluateNetworks( - Lists.newArrayList(mTrustedScanDetail, mUntrustedScanDetail), - null, null, false, true /* untrustedNetworkAllowed */, null); - - assertNull(result); - verify(mNetworkScoreManager).requestRecommendation(mRecommendationRequestCaptor.capture()); - assertEquals(2, mRecommendationRequestCaptor.getValue().getScanResults().length); - assertEquals(mTrustedScanDetail.getScanResult(), - mRecommendationRequestCaptor.getValue().getScanResults()[0]); - assertEquals(mUntrustedScanDetail.getScanResult(), - mRecommendationRequestCaptor.getValue().getScanResults()[1]); - verify(mWifiConfigManager, never()) - .setNetworkCandidateScanResult(anyInt(), any(ScanResult.class), anyInt()); - } - - @Test - public void testEvaluateNetworks_doNotConnectRecommendation_untrustedNetworksAllowed() { - when(mWifiConfigManager.wasEphemeralNetworkDeleted(anyString())).thenReturn(false); - when(mNetworkScoreManager.requestRecommendation(any(RecommendationRequest.class))) - .thenReturn(RecommendationResult.createDoNotConnectRecommendation()); - - WifiConfiguration result = mRecommendedNetworkEvaluator.evaluateNetworks( - Lists.newArrayList(mTrustedScanDetail, mUntrustedScanDetail), - null, null, false, true /* untrustedNetworkAllowed */, null); - - assertNull(result); - verify(mNetworkScoreManager).requestRecommendation(mRecommendationRequestCaptor.capture()); - assertEquals(2, mRecommendationRequestCaptor.getValue().getScanResults().length); - assertEquals(mTrustedScanDetail.getScanResult(), - mRecommendationRequestCaptor.getValue().getScanResults()[0]); - assertEquals(mUntrustedScanDetail.getScanResult(), - mRecommendationRequestCaptor.getValue().getScanResults()[1]); - verify(mWifiConfigManager) - .updateNetworkNotRecommended(mTrustedWifiConfiguration.networkId, true); - } - - @Test - public void testEvaluateNetworks_nullRecommendation() { - when(mWifiConfigManager.wasEphemeralNetworkDeleted(anyString())).thenReturn(false); - when(mNetworkScoreManager.requestRecommendation(any(RecommendationRequest.class))) - .thenReturn(null); - - WifiConfiguration result = mRecommendedNetworkEvaluator.evaluateNetworks( - Lists.newArrayList(mTrustedScanDetail, mUntrustedScanDetail), - null, null, false, false /* untrustedNetworkAllowed */, null); - - assertNull(result); - verify(mNetworkScoreManager).requestRecommendation(any(RecommendationRequest.class)); - verify(mWifiConfigManager, never()).updateNetworkSelectionStatus(anyInt(), anyInt()); - } - - @Test - public void testEvaluateNetworks_requestContainsCurrentNetwork() { - when(mWifiConfigManager.wasEphemeralNetworkDeleted(anyString())).thenReturn(false); - when(mNetworkScoreManager.requestRecommendation(any(RecommendationRequest.class))) - .thenReturn(RecommendationResult.createDoNotConnectRecommendation()); - - mRecommendedNetworkEvaluator.evaluateNetworks( - Lists.newArrayList(mTrustedScanDetail, mUntrustedScanDetail), - mTrustedWifiConfiguration, null, false, true /* untrustedNetworkAllowed */, null); - - verify(mNetworkScoreManager).requestRecommendation(mRecommendationRequestCaptor.capture()); - assertSame(mTrustedWifiConfiguration, - mRecommendationRequestCaptor.getValue().getConnectedConfig()); - verify(mWifiConfigManager) - .updateNetworkNotRecommended(mTrustedWifiConfiguration.networkId, true); - } - - @Test - public void testEvaluateNetworks_requestConnectableNetworks() { - when(mWifiConfigManager.wasEphemeralNetworkDeleted(anyString())).thenReturn(false); - when(mNetworkScoreManager.requestRecommendation(any(RecommendationRequest.class))) - .thenReturn(RecommendationResult.createDoNotConnectRecommendation()); - - mRecommendedNetworkEvaluator.evaluateNetworks( - Lists.newArrayList(mTrustedScanDetail, mUntrustedScanDetail, - mEphemeralScanDetail), - null, null, false, true /* untrustedNetworkAllowed */, null); - - verify(mNetworkScoreManager).requestRecommendation(mRecommendationRequestCaptor.capture()); - RecommendationRequest request = mRecommendationRequestCaptor.getValue(); - assertEquals(2, request.getConnectableConfigs().length); - Set ssids = new ArraySet<>(); - for (WifiConfiguration config : request.getConnectableConfigs()) { - ssids.add(config.SSID); - } - Set expectedSsids = new ArraySet<>(); - expectedSsids.add(mTrustedWifiConfiguration.SSID); - expectedSsids.add(mEphemeralWifiConfiguration.SSID); - assertEquals(expectedSsids, ssids); - } - - @Test - public void testEvaluateNetworks_requestConnectableNetworks_filterDisabledNetworks() { - WifiConfiguration disabledWifiConfiguration = mTrustedWifiConfiguration; - disabledWifiConfiguration.getNetworkSelectionStatus().setNetworkSelectionStatus( - NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED); - when(mWifiConfigManager.getSavedNetworkForScanDetailAndCache(mTrustedScanDetail)) - .thenReturn(disabledWifiConfiguration); - when(mNetworkScoreManager.requestRecommendation(any(RecommendationRequest.class))) - .thenReturn(RecommendationResult.createDoNotConnectRecommendation()); - - mRecommendedNetworkEvaluator.evaluateNetworks( - Lists.newArrayList(mTrustedScanDetail, mEphemeralScanDetail), - null, null, false, true /* untrustedNetworkAllowed */, null); - - verify(mNetworkScoreManager).requestRecommendation(mRecommendationRequestCaptor.capture()); - RecommendationRequest request = mRecommendationRequestCaptor.getValue(); - assertEquals(1, request.getConnectableConfigs().length); - assertEquals(mEphemeralWifiConfiguration, request.getConnectableConfigs()[0]); - } - - @Test - public void testEvaluateNetworks_scanResultMarkedAsUntrusted_configIsEphemeral() { - when(mWifiConfigManager.wasEphemeralNetworkDeleted(anyString())).thenReturn(false); - when(mNetworkScoreManager.requestRecommendation(any(RecommendationRequest.class))) - .thenReturn(RecommendationResult.createDoNotConnectRecommendation()); - - mRecommendedNetworkEvaluator.evaluateNetworks(Lists.newArrayList(mEphemeralScanDetail), - null, null, false, true /* untrustedNetworkAllowed */, null); - - verify(mNetworkScoreManager).requestRecommendation(mRecommendationRequestCaptor.capture()); - RecommendationRequest request = mRecommendationRequestCaptor.getValue(); - assertEquals(1, request.getScanResults().length); - assertTrue(request.getScanResults()[0].untrusted); - } - - @Test - public void testEvaluateNetworks_potentialConnectableNetworksPopulated() { - when(mWifiConfigManager.wasEphemeralNetworkDeleted(anyString())).thenReturn(false); - when(mNetworkScoreManager.requestRecommendation(any(RecommendationRequest.class))) - .thenReturn(RecommendationResult.createDoNotConnectRecommendation()); - - List> potentialConnectableNetworks = new ArrayList<>(); - mRecommendedNetworkEvaluator.evaluateNetworks( - Lists.newArrayList(mTrustedScanDetail, mEphemeralScanDetail, - mUntrustedScanDetail), null, null, false, - true /* untrustedNetworkAllowed */, potentialConnectableNetworks); - - assertEquals(3, potentialConnectableNetworks.size()); - Pair expectedTrustedPair = - Pair.create(mTrustedScanDetail, mTrustedWifiConfiguration); - Pair expectedUntrustedPair = - Pair.create(mUntrustedScanDetail, null); - Pair expectedEphemPair = - Pair.create(mEphemeralScanDetail, mEphemeralWifiConfiguration); - assertTrue(potentialConnectableNetworks.contains(expectedTrustedPair)); - assertTrue(potentialConnectableNetworks.contains(expectedUntrustedPair)); - assertTrue(potentialConnectableNetworks.contains(expectedEphemPair)); - } - - @Test - public void testEvaluateNetworks_potentialConnectableNetworksIsNull() { - when(mWifiConfigManager.wasEphemeralNetworkDeleted(anyString())).thenReturn(false); - when(mNetworkScoreManager.requestRecommendation(any(RecommendationRequest.class))) - .thenReturn(RecommendationResult.createDoNotConnectRecommendation()); - - mRecommendedNetworkEvaluator.evaluateNetworks( - Lists.newArrayList(mTrustedScanDetail, mEphemeralScanDetail, - mUntrustedScanDetail), - null, null, false, true /* untrustedNetworkAllowed */, null); - - // should not throw a NPE. - } - - @Test - public void testEvaluateNetworks_requestContainsLastSelectedNetwork() { - int lastSelectedNetworkId = 5; - long lastSelectedTimestamp = 1000; - when(mWifiConfigManager.wasEphemeralNetworkDeleted(anyString())).thenReturn(false); - when(mWifiConfigManager.getLastSelectedNetwork()).thenReturn(lastSelectedNetworkId); - when(mWifiConfigManager.getLastSelectedTimeStamp()).thenReturn(lastSelectedTimestamp); - - mRecommendedNetworkEvaluator.evaluateNetworks(Lists.newArrayList(mTrustedScanDetail), - null, null, false, false /* untrustedNetworkAllowed */, null); - - verify(mNetworkScoreManager).requestRecommendation(mRecommendationRequestCaptor.capture()); - RecommendationRequest request = mRecommendationRequestCaptor.getValue(); - assertEquals(lastSelectedNetworkId, request.getLastSelectedNetworkId()); - assertEquals(lastSelectedTimestamp, request.getLastSelectedNetworkTimestamp()); - } - - private static ScanDetail buildScanDetail(String ssid) { - return new ScanDetail(WifiSsid.createFromAsciiEncoded(ssid), - "00:00:00:00:00:00", "", 0, 0, 0, 0); - } -} diff --git a/tests/wifitests/src/com/android/server/wifi/ScoredNetworkEvaluatorTest.java b/tests/wifitests/src/com/android/server/wifi/ScoredNetworkEvaluatorTest.java new file mode 100644 index 000000000..55b00c9b5 --- /dev/null +++ b/tests/wifitests/src/com/android/server/wifi/ScoredNetworkEvaluatorTest.java @@ -0,0 +1,577 @@ +/* + * 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.database.ContentObserver; +import android.net.NetworkKey; +import android.net.NetworkScoreManager; +import android.net.Uri; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiNetworkScoreCache; +import android.os.Looper; +import android.os.SystemClock; +import android.provider.Settings; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.LocalLog; + +import com.android.server.wifi.WifiNetworkSelectorTestUtil.ScanDetailsAndWifiConfigs; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +/** + * Unit tests for {@link ScoredNetworkEvaluator}. + */ +@SmallTest +public class ScoredNetworkEvaluatorTest { + private ContentObserver mContentObserver; + private int mThresholdQualifiedRssi2G; + private int mThresholdQualifiedRssi5G; + + @Mock private Context mContext; + @Mock private Clock mClock; + @Mock private FrameworkFacade mFrameworkFacade; + @Mock private NetworkScoreManager mNetworkScoreManager; + @Mock private WifiConfigManager mWifiConfigManager; + + @Captor private ArgumentCaptor mNetworkKeyArrayCaptor; + + private WifiNetworkScoreCache mScoreCache; + private ScoredNetworkEvaluator mScoredNetworkEvaluator; + + @Before + public void setUp() throws Exception { + mThresholdQualifiedRssi2G = -73; + mThresholdQualifiedRssi5G = -70; + + MockitoAnnotations.initMocks(this); + + when(mFrameworkFacade.getIntegerSetting(mContext, + Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0)) + .thenReturn(1); + + ArgumentCaptor observerCaptor = + ArgumentCaptor.forClass(ContentObserver.class); + mScoreCache = new WifiNetworkScoreCache(mContext); + mScoredNetworkEvaluator = new ScoredNetworkEvaluator(mContext, + Looper.getMainLooper(), mFrameworkFacade, mNetworkScoreManager, + mWifiConfigManager, new LocalLog(0), mScoreCache); + verify(mFrameworkFacade).registerContentObserver(eq(mContext), any(Uri.class), eq(false), + observerCaptor.capture()); + mContentObserver = observerCaptor.getValue(); + + reset(mNetworkScoreManager); + + when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()); + } + + @After + public void tearDown() { + validateMockitoUsage(); + } + + @Test + public void testUpdate_recommendationsDisabled() { + 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); + + when(mFrameworkFacade.getIntegerSetting(mContext, + Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0)) + .thenReturn(0); + + mContentObserver.onChange(false /* unused */); + + mScoredNetworkEvaluator.update(scanDetailsAndConfigs.getScanDetails()); + + verifyZeroInteractions(mNetworkScoreManager); + } + + @Test + public void testUpdate_emptyScanList() { + 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); + + mScoredNetworkEvaluator.update(new ArrayList()); + + verifyZeroInteractions(mNetworkScoreManager); + } + + @Test + public void testUpdate_allNetworksUnscored() { + 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 + 10}; + + ScanDetailsAndWifiConfigs scanDetailsAndConfigs = WifiNetworkSelectorTestUtil + .setupScanDetailsAndConfigStore( + ssids, bssids, freqs, caps, levels, securities, mWifiConfigManager, mClock); + + mScoredNetworkEvaluator.update(scanDetailsAndConfigs.getScanDetails()); + + verify(mNetworkScoreManager).requestScores(mNetworkKeyArrayCaptor.capture()); + assertEquals(2, mNetworkKeyArrayCaptor.getValue().length); + NetworkKey expectedNetworkKey = NetworkKey.createFromScanResult( + scanDetailsAndConfigs.getScanDetails().get(0).getScanResult()); + assertEquals(expectedNetworkKey, mNetworkKeyArrayCaptor.getValue()[0]); + expectedNetworkKey = NetworkKey.createFromScanResult( + scanDetailsAndConfigs.getScanDetails().get(1).getScanResult()); + assertEquals(expectedNetworkKey, mNetworkKeyArrayCaptor.getValue()[1]); + } + + @Test + public void testUpdate_oneScored_oneUnscored() { + 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 + 10}; + + ScanDetailsAndWifiConfigs scanDetailsAndConfigs = WifiNetworkSelectorTestUtil + .setupScanDetailsAndConfigStore( + ssids, bssids, freqs, caps, levels, securities, mWifiConfigManager, mClock); + + List scoredScanDetails = scanDetailsAndConfigs.getScanDetails().subList(0, 1); + Integer[] scores = {120}; + boolean[] meteredHints = {true}; + WifiNetworkSelectorTestUtil.configureScoreCache( + mScoreCache, scoredScanDetails, scores, meteredHints); + + mScoredNetworkEvaluator.update(scanDetailsAndConfigs.getScanDetails()); + + verify(mNetworkScoreManager).requestScores(mNetworkKeyArrayCaptor.capture()); + + NetworkKey[] requestedScores = mNetworkKeyArrayCaptor.getValue(); + assertEquals(1, requestedScores.length); + NetworkKey expectedNetworkKey = NetworkKey.createFromScanResult( + scanDetailsAndConfigs.getScanDetails().get(1).getScanResult()); + assertEquals(expectedNetworkKey, requestedScores[0]); + } + + @Test + public void testEvaluateNetworks_recommendationsDisabled() { + when(mFrameworkFacade.getIntegerSetting(mContext, + Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0)) + .thenReturn(0); + + mContentObserver.onChange(false /* unused */); + + mScoredNetworkEvaluator.evaluateNetworks(null, null, null, false, false, null); + + verifyZeroInteractions(mWifiConfigManager, mNetworkScoreManager); + } + + /** + * When no saved networks available, choose the available ephemeral networks + * if untrusted networks are allowed. + */ + @Test + public void testEvaluateNetworks_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 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, scanDetails.get(1), meteredHints[1]); + + // Untrusted networks allowed. + WifiConfiguration candidate = mScoredNetworkEvaluator.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 testEvaluateNetworks_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 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, scanDetails.get(i), meteredHints[i]); + } + + WifiConfiguration candidate = mScoredNetworkEvaluator.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 testEvaluateNetworks_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 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); + + WifiNetworkSelectorTestUtil.setupEphemeralNetwork( + mWifiConfigManager, 1, scanDetails.get(1), meteredHints[1]); + + // Untrusted networks not allowed. + WifiConfiguration candidate = mScoredNetworkEvaluator.evaluateNetworks(scanDetails, + null, null, false, false, null); + + assertEquals("Expect null configuration", null, candidate); + } + + /** + * Choose externally scored saved network. + */ + @Test + public void testEvaluateNetworks_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}; + + WifiNetworkSelectorTestUtil.ScanDetailsAndWifiConfigs scanDetailsAndConfigs = + WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids, + freqs, caps, levels, securities, mWifiConfigManager, mClock); + List scanDetails = scanDetailsAndConfigs.getScanDetails(); + WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs(); + savedConfigs[0].useExternalScores = true; + + WifiNetworkSelectorTestUtil.configureScoreCache(mScoreCache, + scanDetails, scores, meteredHints); + + WifiConfiguration candidate = mScoredNetworkEvaluator.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 testEvaluateNetworks_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}; + + WifiNetworkSelectorTestUtil.ScanDetailsAndWifiConfigs scanDetailsAndConfigs = + WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids, + freqs, caps, levels, securities, mWifiConfigManager, mClock); + List scanDetails = scanDetailsAndConfigs.getScanDetails(); + WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs(); + savedConfigs[0].useExternalScores = savedConfigs[1].useExternalScores = true; + + WifiNetworkSelectorTestUtil.configureScoreCache(mScoreCache, + scanDetails, scores, meteredHints); + + WifiConfiguration candidate = mScoredNetworkEvaluator.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 testEvaluateNetworks_chooseExternallyScoredOverUntrustedNetworksWithSameScore() { + 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}; + + WifiNetworkSelectorTestUtil.ScanDetailsAndWifiConfigs scanDetailsAndConfigs = + WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids, + freqs, caps, levels, securities, mWifiConfigManager, mClock); + List scanDetails = scanDetailsAndConfigs.getScanDetails(); + WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs(); + savedConfigs[0].useExternalScores = true; + + WifiNetworkSelectorTestUtil.configureScoreCache(mScoreCache, + scanDetails, scores, meteredHints); + + WifiConfiguration candidate = mScoredNetworkEvaluator.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 testEvaluateNetworks_chooseUntrustedWithHigherScoreThanExternallyScoredNetwork() { + // 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. + WifiNetworkSelectorTestUtil.ScanDetailsAndWifiConfigs scanDetailsAndConfigs = + WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(savedSsids, + savedBssids, savedFreqs, savedCaps, savedLevels, savedSecurities, + mWifiConfigManager, mClock); + List 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, scanDetails.get(1), + meteredHints[1]); + + // Set up score cache for both the saved network and the ephemeral network. + WifiNetworkSelectorTestUtil.configureScoreCache(mScoreCache, + scanDetails, scores, meteredHints); + + WifiConfiguration candidate = mScoredNetworkEvaluator.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 testEvaluateNetworks_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}; + + WifiNetworkSelectorTestUtil.ScanDetailsAndWifiConfigs scanDetailsAndConfigs = + WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids, + freqs, caps, levels, securities, mWifiConfigManager, mClock); + List scanDetails = scanDetailsAndConfigs.getScanDetails(); + WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs(); + savedConfigs[0].useExternalScores = true; + + WifiNetworkSelectorTestUtil.configureScoreCache(mScoreCache, + scanDetails, scores, meteredHints); + + WifiConfiguration candidate = mScoredNetworkEvaluator.evaluateNetworks(scanDetails, + null, null, false, true, null); + + assertEquals("Expect null configuration", null, candidate); + } + + /** + * Between two ephemeral networks with the same RSSI, choose + * the currently connected one. + */ + @Test + public void testEvaluateNetworks_chooseActiveEphemeralNetwork() { + 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 + 28, mThresholdQualifiedRssi2G + 28}; + boolean[] meteredHints = {true, true}; + ScanResult[] scanResults = new ScanResult[2]; + WifiConfiguration[] ephemeralNetworkConfigs = new WifiConfiguration[2]; + + List scanDetails = WifiNetworkSelectorTestUtil + .buildScanDetails(ssids, bssids, freqs, caps, levels, mClock); + + WifiNetworkSelectorTestUtil.configureScoreCache( + mScoreCache, scanDetails, null, 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, scanDetails.get(i), meteredHints[i]); + } + + WifiConfiguration candidate = mScoredNetworkEvaluator.evaluateNetworks( + scanDetails, ephemeralNetworkConfigs[1], + bssids[1], true, true, null); + + WifiConfigurationTestUtil.assertConfigurationEqual(ephemeralNetworkConfigs[1], candidate); + WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager, + scanResults[1], candidate); + assertEquals(meteredHints[1], candidate.meteredHint); + } + + /** + * Between two externally scored saved networks with the same RSSI, choose + * the currently connected one. + */ + @Test + public void testEvaluateNetworks_chooseActiveSavedNetwork() { + 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 + 28, mThresholdQualifiedRssi2G + 28}; + boolean[] meteredHints = {false, false}; + + WifiNetworkSelectorTestUtil.ScanDetailsAndWifiConfigs scanDetailsAndConfigs = + WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids, + freqs, caps, levels, securities, mWifiConfigManager, mClock); + List scanDetails = scanDetailsAndConfigs.getScanDetails(); + WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs(); + savedConfigs[0].useExternalScores = savedConfigs[1].useExternalScores = true; + + WifiNetworkSelectorTestUtil.configureScoreCache(mScoreCache, + scanDetails, null, meteredHints); + + WifiConfiguration candidate = mScoredNetworkEvaluator.evaluateNetworks(scanDetails, + savedConfigs[1], bssids[1], true, true, null); + + WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate); + WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager, + scanDetails.get(1).getScanResult(), candidate); + } +} diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTestUtil.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTestUtil.java index 1e255c86c..9c78c9b12 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTestUtil.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTestUtil.java @@ -177,7 +177,7 @@ public class WifiNetworkSelectorTestUtil { * @param wifiConfigManager the mocked WifiConfigManager * @param configs input configuration need to be added to WifiConfigureStore */ - private static void prepareConfigStore(WifiConfigManager wifiConfigManager, + private static void prepareConfigStore(final WifiConfigManager wifiConfigManager, final WifiConfiguration[] configs) { when(wifiConfigManager.getConfiguredNetwork(anyInt())) .then(new AnswerWithArguments() { @@ -356,18 +356,22 @@ public class WifiNetworkSelectorTestUtil { * * @param wifiConfigManager WifiConfigManager mock * @param networkId ID of the ephemeral network - * @param scanResult scanResult of the ephemeral network + * @param scanDetail scanDetail 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) { + int networkId, ScanDetail scanDetail, 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); + final WifiConfiguration config = + ScanResultUtil.createNetworkFromScanResult(scanDetail.getScanResult()); + config.ephemeral = true; config.networkId = networkId; config.meteredHint = meteredHint; + when(wifiConfigManager.getSavedNetworkForScanDetailAndCache(eq(scanDetail))) + .thenReturn(new WifiConfiguration(config)); when(wifiConfigManager.getConfiguredNetwork(eq(networkId))) .then(new AnswerWithArguments() { public WifiConfiguration answer(int netId) { @@ -385,6 +389,15 @@ public class WifiNetworkSelectorTestUtil { return true; } }); + when(wifiConfigManager.updateNetworkSelectionStatus(eq(networkId), + eq(WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE))) + .then(new AnswerWithArguments() { + public boolean answer(int netId, int status) { + config.getNetworkSelectionStatus().setNetworkSelectionStatus( + WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE); + return true; + } + }); return config; } } -- cgit v1.2.3