summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--service/java/com/android/server/wifi/WifiConfigManager.java20
-rw-r--r--service/java/com/android/server/wifi/WifiConfigStore.java36
-rw-r--r--service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java221
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachine.java1
-rw-r--r--service/java/com/android/server/wifi/hotspot2/omadm/OMAParser.java3
-rw-r--r--service/java/com/android/server/wifi/util/ScanDetailUtil.java8
-rw-r--r--tests/wifitests/src/com/android/server/wifi/PasspointManagementObjectManagerTest.java36
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java18
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java218
9 files changed, 534 insertions, 27 deletions
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index 4a27fef97..407773ce9 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -94,6 +94,7 @@ import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -242,6 +243,9 @@ public class WifiConfigManager {
public AtomicInteger mCurrentNetworkBoost = new AtomicInteger();
public AtomicInteger mBandAward5Ghz = new AtomicInteger();
+ // Indicates whether the system is capable of 802.11r fast BSS transition.
+ private boolean mSystemSupportsFastBssTransition = false;
+
/**
* Framework keeps a list of ephemeral SSIDs that where deleted by user,
* so as, framework knows not to autojoin again those SSIDs based on scorer input.
@@ -377,6 +381,8 @@ public class WifiConfigManager {
R.integer.config_wifi_framework_current_network_boost));
mNetworkSwitchingBlackListPeriodMs = mContext.getResources().getInteger(
R.integer.config_wifi_network_switching_blacklist_time);
+ mSystemSupportsFastBssTransition = mContext.getResources().getBoolean(
+ R.bool.config_wifi_fast_bss_transition_enabled);
boolean hs2on = mContext.getResources().getBoolean(R.bool.config_wifi_hotspot2_enabled);
Log.d(Utils.hs2LogTag(getClass()), "Passpoint is " + (hs2on ? "enabled" : "disabled"));
@@ -1123,6 +1129,14 @@ public class WifiConfigManager {
ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoList = new ArrayList<>();
ArrayList<WifiConfiguration> wifiConfigurations =
new ArrayList<>(mConfiguredNetworks.valuesForCurrentUser());
+ // Remove any permanently disabled networks.
+ Iterator<WifiConfiguration> iter = wifiConfigurations.iterator();
+ while (iter.hasNext()) {
+ WifiConfiguration config = iter.next();
+ if (config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()) {
+ iter.remove();
+ }
+ }
Collections.sort(wifiConfigurations, pnoListComparator);
// Let's use the network list size as the highest priority and then go down from there.
// So, the most frequently connected network has the highest priority now.
@@ -1951,7 +1965,8 @@ public class WifiConfigManager {
// HasEverConnected to be set to false.
WifiConfiguration originalConfig = new WifiConfiguration(currentConfig);
- if (!mWifiConfigStore.addOrUpdateNetwork(config, currentConfig)) {
+ if (!mWifiConfigStore.addOrUpdateNetwork(config, currentConfig,
+ mSystemSupportsFastBssTransition)) {
return new NetworkUpdateResult(INVALID_NETWORK_ID);
}
int netId = config.networkId;
@@ -3240,7 +3255,8 @@ public class WifiConfigManager {
/**
* Check if the provided ephemeral network was deleted by the user or not.
- * @param ssid ssid of the network
+ * @param ssid caller must ensure that the SSID passed thru this API match
+ * the WifiConfiguration.SSID rules, and thus be surrounded by quotes.
* @return true if network was deleted, false otherwise.
*/
public boolean wasEphemeralNetworkDeleted(String ssid) {
diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java
index b693e2344..beb3373d2 100644
--- a/service/java/com/android/server/wifi/WifiConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiConfigStore.java
@@ -421,13 +421,6 @@ public class WifiConfigStore {
}
config.setIpAssignment(IpAssignment.DHCP);
config.setProxySettings(ProxySettings.NONE);
- if (!WifiServiceImpl.isValid(config)) {
- if (mShowNetworks) {
- localLog("Ignoring network " + config.networkId + " because configuration "
- + "loaded from wpa_supplicant.conf is not valid.");
- }
- continue;
- }
// The configKey is explicitly stored in wpa_supplicant.conf, because config does
// not contain sufficient information to compute it at this point.
String configKey = extras.get(ID_STRING_KEY_CONFIG_KEY);
@@ -601,14 +594,27 @@ public class WifiConfigStore {
return true;
}
+ private BitSet addFastTransitionFlags(BitSet keyManagementFlags) {
+ BitSet modifiedFlags = keyManagementFlags;
+ if (keyManagementFlags.get(WifiConfiguration.KeyMgmt.WPA_PSK)) {
+ modifiedFlags.set(WifiConfiguration.KeyMgmt.FT_PSK);
+ }
+ if (keyManagementFlags.get(WifiConfiguration.KeyMgmt.WPA_EAP)) {
+ modifiedFlags.set(WifiConfiguration.KeyMgmt.FT_EAP);
+ }
+ return modifiedFlags;
+ }
+
/**
* Save an entire network configuration to wpa_supplicant.
*
* @param config Config corresponding to the network.
- * @param netId Net Id of the network.
+ * @param netId Net Id of the network.
+ * @param addFastTransitionFlags Add the BSS fast transition(80211r) flags to the network.
* @return true if successful, false otherwise.
*/
- private boolean saveNetwork(WifiConfiguration config, int netId) {
+ private boolean saveNetwork(WifiConfiguration config, int netId,
+ boolean addFastTransitionFlags) {
if (config == null) {
return false;
}
@@ -631,6 +637,10 @@ public class WifiConfigStore {
return false;
}
}
+ BitSet allowedKeyManagement = config.allowedKeyManagement;
+ if (addFastTransitionFlags) {
+ allowedKeyManagement = addFastTransitionFlags(config.allowedKeyManagement);
+ }
String allowedKeyManagementString =
makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings);
if (config.allowedKeyManagement.cardinality() != 0 && !mWifiNative.setNetworkVariable(
@@ -788,11 +798,13 @@ public class WifiConfigStore {
/**
* Add or update a network configuration to wpa_supplicant.
*
- * @param config Config corresponding to the network.
+ * @param config Config corresponding to the network.
* @param existingConfig Existing config corresponding to the network saved in our database.
+ * @param addFastTransitionFlags Add the BSS fast transition(80211r) flags to the network.
* @return true if successful, false otherwise.
*/
- public boolean addOrUpdateNetwork(WifiConfiguration config, WifiConfiguration existingConfig) {
+ public boolean addOrUpdateNetwork(WifiConfiguration config, WifiConfiguration existingConfig,
+ boolean addFastTransitionFlags) {
if (config == null) {
return false;
}
@@ -816,7 +828,7 @@ public class WifiConfigStore {
// Save the new network ID to the config
config.networkId = netId;
}
- if (!saveNetwork(config, netId)) {
+ if (!saveNetwork(config, netId, addFastTransitionFlags)) {
if (newNetwork) {
mWifiNative.removeNetwork(netId);
loge("Failed to set a network variable, removed network: " + netId);
diff --git a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java
index dd8bdae50..a612cbba1 100644
--- a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java
+++ b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java
@@ -17,7 +17,10 @@
package com.android.server.wifi;
import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.net.NetworkKey;
import android.net.NetworkScoreManager;
import android.net.WifiKey;
@@ -25,18 +28,24 @@ import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
import android.text.TextUtils;
+import android.util.Base64;
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.ScanDetailUtil;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.nio.charset.StandardCharsets;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -108,6 +117,8 @@ public class WifiQualifiedNetworkSelector {
private int mUserPreferedBand = WifiManager.WIFI_FREQUENCY_BAND_AUTO;
private Map<String, BssidBlacklistStatus> mBssidBlacklist =
new HashMap<String, BssidBlacklistStatus>();
+ private List<WifiConfiguration> mCarrierConfiguredNetworks = new ArrayList<WifiConfiguration>();
+ private CarrierConfigManager mCarrierConfigManager;
/**
* class save the blacklist status of a given BSSID
@@ -191,6 +202,50 @@ public class WifiQualifiedNetworkSelector {
mNoIntnetPenalty = (mWifiConfigManager.mThresholdSaturatedRssi24.get() + mRssiScoreOffset)
* mRssiScoreSlope + mWifiConfigManager.mBandAward5Ghz.get()
+ mWifiConfigManager.mCurrentNetworkBoost.get() + mSameBssidAward + mSecurityAward;
+ mCarrierConfigManager = (CarrierConfigManager)
+ context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+
+ final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ localLog("mBroadcastReceiver: onReceive " + intent.getAction());
+ PersistableBundle b = mCarrierConfigManager.getConfig();
+ String[] mWifiArray =
+ b.getStringArray(CarrierConfigManager.KEY_CARRIER_WIFI_STRING_ARRAY);
+ WifiConfiguration wifiConfig;
+ if (mWifiArray == null) {
+ return;
+ }
+
+ for (String config : mWifiArray) {
+ String[] wc = config.split("\\|");
+ wifiConfig = new WifiConfiguration();
+ try {
+ byte[] decodedBytes = Base64.decode(wc[0], Base64.DEFAULT);
+ String ssid = new String(decodedBytes);
+ wifiConfig.SSID = "\"" + ssid + "\"";
+ } catch (IllegalArgumentException ex) {
+ localLog("mBroadcaseReceiver: Could not decode base64 string");
+ continue;
+ }
+ try {
+ int s = Integer.parseInt(wc[1]);
+ wifiConfig.allowedKeyManagement.set(s);
+ } catch (NumberFormatException e) {
+ localLog("mBroadcastReceiver: not an integer" + wc[1]);
+ }
+ mCarrierConfiguredNetworks.add(wifiConfig);
+ localLog("mBroadcastReceiver: onReceive networks:" + wifiConfig.SSID);
+ }
+ }
+ };
+ context.registerReceiver(mBroadcastReceiver, new IntentFilter(
+ CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
+ }
+
+ @VisibleForTesting
+ public void setCarrierConfiguredNetworks(List<WifiConfiguration> carrierConfiguredNetworks) {
+ mCarrierConfiguredNetworks = carrierConfiguredNetworks;
}
void enableVerboseLogging(int verbose) {
@@ -238,7 +293,7 @@ public class WifiQualifiedNetworkSelector {
// Current network band must match with user preference selection
if (mWifiInfo.is24GHz() && (mUserPreferedBand != WifiManager.WIFI_FREQUENCY_BAND_2GHZ)) {
- localLog("Current band dose not match user preference. Start Qualified Network"
+ localLog("Current band does not match user preference. Start Qualified Network"
+ " Selection Current band = " + (mWifiInfo.is24GHz() ? "2.4GHz band"
: "5GHz band") + "UserPreference band = " + mUserPreferedBand);
return false;
@@ -582,6 +637,16 @@ public class WifiQualifiedNetworkSelector {
return status == null ? false : status.mIsBlacklisted;
}
+ private boolean isCarrierNetwork(ScanResult scanResult) {
+ String ssid = "\"" + scanResult.SSID + "\"";
+ for (WifiConfiguration config : mCarrierConfiguredNetworks) {
+ if (config.SSID.equals(ssid)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* ToDo: This should be called in Connectivity Manager when it gets new scan result
* check whether a network slection is needed. If need, check all the new scan results and
@@ -605,7 +670,7 @@ public class WifiQualifiedNetworkSelector {
* false -- supplicant is not in a transient state
* @return the qualified network candidate found. If no available candidate, return null
*/
- public WifiConfiguration selectQualifiedNetwork(boolean forceSelectNetwork ,
+ public WifiConfiguration selectQualifiedNetwork(boolean forceSelectNetwork,
boolean isUntrustedConnectionsAllowed, List<ScanDetail> scanDetails,
boolean isLinkDebouncing, boolean isConnected, boolean isDisconnected,
boolean isSupplicantTransient) {
@@ -632,8 +697,11 @@ public class WifiQualifiedNetworkSelector {
int currentHighestScore = Integer.MIN_VALUE;
ScanResult scanResultCandidate = null;
WifiConfiguration networkCandidate = null;
+ WifiConfiguration carrierCandidate = null;
final ExternalScoreEvaluator externalScoreEvaluator =
new ExternalScoreEvaluator(mLocalLog, mDbg);
+ final CarrierScoreEvaluator carrierScoreEvaluator =
+ new CarrierScoreEvaluator(mLocalLog, mDbg);
String lastUserSelectedNetWorkKey = mWifiConfigManager.getLastSelectedConfiguration();
WifiConfiguration lastUserSelectedNetwork =
mWifiConfigManager.getWifiConfiguration(lastUserSelectedNetWorkKey);
@@ -651,6 +719,7 @@ public class WifiQualifiedNetworkSelector {
StringBuffer noValidSsid = new StringBuffer();
StringBuffer scoreHistory = new StringBuffer();
ArrayList<NetworkKey> unscoredNetworks = new ArrayList<NetworkKey>();
+ boolean scanResultsHaveCurrentBssid = false;
//iterate all scan results and find the best candidate with the highest score
for (ScanDetail scanDetail : mScanDetails) {
@@ -664,6 +733,12 @@ public class WifiQualifiedNetworkSelector {
continue;
}
+ //check if the scan results contain the current connected
+ //BSSID.
+ if (scanResult.BSSID.equals(mCurrentBssid)) {
+ scanResultsHaveCurrentBssid = true;
+ }
+
final String scanId = toScanId(scanResult);
//check whether this BSSID is blocked or not
if (mWifiConfigManager.isBssidBlacklisted(scanResult.BSSID)
@@ -725,10 +800,22 @@ public class WifiQualifiedNetworkSelector {
// 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) {
+ localLog("Network is a ephemeral network...");
if (isUntrustedConnectionsAllowed) {
Integer netScore = getNetworkScore(scanResult, false);
- if (netScore != null
- && !mWifiConfigManager.wasEphemeralNetworkDeleted(scanResult.SSID)) {
+ if (netScore == null) {
+ localLog("Checking the carrierScoreEvaluator for candidates...");
+ // Evaluate the carrier network as a possible candidate.
+ if (!mCarrierConfiguredNetworks.isEmpty() && isCarrierNetwork(scanResult)) {
+ carrierScoreEvaluator.evalCarrierCandidate(scanResult,
+ getCarrierScore(scanResult, mCurrentConnectedNetwork,
+ (mCurrentBssid == null ? false :
+ mCurrentBssid.equals(scanResult.BSSID))));
+ }
+
+ }
+ else if (!mWifiConfigManager.wasEphemeralNetworkDeleted(
+ ScanDetailUtil.createQuotedSSID(scanResult.SSID))) {
externalScoreEvaluator.evalUntrustedCandidate(netScore, scanResult);
// scanDetail is for available ephemeral network
filteredScanDetails.add(Pair.create(scanDetail,
@@ -817,6 +904,16 @@ public class WifiQualifiedNetworkSelector {
localLog(scoreHistory.toString());
}
+ //QNS listens to all single scan results. Some scan requests may not include
+ //the channel of the currently connected network, so the currently connected network
+ //won't show up in the scan results. We don't act on these scan results to avoid
+ //aggressive network switching which might trigger disconnection.
+ if (isConnected && !scanResultsHaveCurrentBssid) {
+ localLog("Current connected BSSID " + mCurrentBssid + " is not in the scan results."
+ + " Skip network selection.");
+ return null;
+ }
+
//we need traverse the whole user preference to choose the one user like most now
if (scanResultCandidate != null) {
WifiConfiguration tempConfig = networkCandidate;
@@ -853,6 +950,14 @@ public class WifiQualifiedNetworkSelector {
}
if (scanResultCandidate == null) {
+ networkCandidate = getCarrierScoreCandidate(carrierScoreEvaluator);
+ localLog("Carrier candidate::" + networkCandidate);
+ if (networkCandidate != null) {
+ scanResultCandidate = networkCandidate.getNetworkSelectionStatus().getCandidate();
+ }
+ }
+
+ if (scanResultCandidate == null) {
localLog("Can not find any suitable candidates");
return null;
}
@@ -937,6 +1042,32 @@ public class WifiQualifiedNetworkSelector {
}
/**
+ * Returns the best candidate network according to the given CarrierScoreEvaluator.
+ */
+ @Nullable
+ WifiConfiguration getCarrierScoreCandidate(CarrierScoreEvaluator scoreEvaluator) {
+ WifiConfiguration networkCandidate = null;
+
+ ScanResult untrustedScanResultCandidate = scoreEvaluator.getScanResultCandidate();
+ if (untrustedScanResultCandidate == null) {
+ return null;
+ }
+ WifiConfiguration unTrustedNetworkCandidate =
+ mWifiConfigManager.wifiConfigurationFromScanResult(
+ untrustedScanResultCandidate);
+ // Mark this config as ephemeral so it isn't persisted.
+ unTrustedNetworkCandidate.ephemeral = true;
+ mWifiConfigManager.saveNetwork(unTrustedNetworkCandidate, WifiConfiguration.UNKNOWN_UID);
+ localLog(String.format("new carrier candidate %s network ID:%d, ",
+ toScanId(untrustedScanResultCandidate), unTrustedNetworkCandidate.networkId));
+
+ unTrustedNetworkCandidate.getNetworkSelectionStatus()
+ .setCandidate(untrustedScanResultCandidate);
+ networkCandidate = unTrustedNetworkCandidate;
+ return networkCandidate;
+ }
+
+ /**
* Returns the available external network score or NULL if no score is available.
*
* @param scanResult The scan result of the network to score.
@@ -954,6 +1085,43 @@ public class WifiQualifiedNetworkSelector {
}
/**
+ * 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.
+ */
+ int getCarrierScore(ScanResult scanResult, WifiConfiguration currentNetwork,
+ boolean sameBssid) {
+ localLog("Calc Carrier score: w/" + sameBssid);
+ if (currentNetwork != null) {
+ localLog("scoring: compare::" + scanResult.SSID + ", with:" + currentNetwork.SSID);
+ }
+ int score = 0;
+ // Calculate the RSSI score.
+ int rssi = scanResult.level <= mWifiConfigManager.mThresholdSaturatedRssi24.get()
+ ? scanResult.level : mWifiConfigManager.mThresholdSaturatedRssi24.get();
+ score += (rssi + mRssiScoreOffset) * mRssiScoreSlope;
+
+ // 5GHz band bonus.
+ if (scanResult.is5GHz()) {
+ score += BAND_AWARD_5GHz;
+ }
+
+ //same network award
+ if ((currentNetwork != null) && currentNetwork.SSID.equals(scanResult.SSID)) {
+ score += mWifiConfigManager.mCurrentNetworkBoost.get();
+ }
+
+ //same BSSID award
+ if (sameBssid) {
+ score += mSameBssidAward;
+ }
+
+ localLog("Calc Carrier score:" + score);
+ return score;
+ }
+
+ /**
* Formats the given ScanResult as a scan ID for logging.
*/
private static String toScanId(@Nullable ScanResult scanResult) {
@@ -1042,4 +1210,49 @@ public class WifiQualifiedNetworkSelector {
}
}
}
+
+ /**
+ * Used to track and evaluate networks that are assigned by the Carriers.
+ */
+ static class CarrierScoreEvaluator {
+ // Always set to the best known candidate
+ private int mHighScore = WifiNetworkScoreCache.INVALID_NETWORK_SCORE;
+ private WifiConfiguration mSavedConfig;
+ private ScanResult mScanResultCandidate;
+ private final LocalLog mLocalLog;
+ private final boolean mDbg;
+
+ CarrierScoreEvaluator(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 evalCarrierCandidate(ScanResult scanResult, int score) {
+ if (score > mHighScore) {
+ mHighScore = score;
+ mScanResultCandidate = scanResult;
+ localLog(toScanId(scanResult) +
+ " become the new untrusted carrier network candidate");
+ }
+ }
+
+ 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 9d8a66f2d..0c7e987ee 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -1026,7 +1026,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiRss
mP2pSupported = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WIFI_DIRECT);
-
mWifiConfigManager = mFacade.makeWifiConfigManager(context, mWifiNative, facade,
mWifiInjector.getClock(), userManager, mWifiInjector.getKeyStore());
diff --git a/service/java/com/android/server/wifi/hotspot2/omadm/OMAParser.java b/service/java/com/android/server/wifi/hotspot2/omadm/OMAParser.java
index cbcd81d16..d39fa33a1 100644
--- a/service/java/com/android/server/wifi/hotspot2/omadm/OMAParser.java
+++ b/service/java/com/android/server/wifi/hotspot2/omadm/OMAParser.java
@@ -26,6 +26,9 @@ public class OMAParser extends DefaultHandler {
}
public MOTree parse(String text, String urn) throws IOException, SAXException {
+ if (text == null) {
+ throw new IOException("Missing text string");
+ }
try {
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(new InputSource(new StringReader(text)), this);
diff --git a/service/java/com/android/server/wifi/util/ScanDetailUtil.java b/service/java/com/android/server/wifi/util/ScanDetailUtil.java
index a83900e0a..c5ec92af9 100644
--- a/service/java/com/android/server/wifi/util/ScanDetailUtil.java
+++ b/service/java/com/android/server/wifi/util/ScanDetailUtil.java
@@ -37,4 +37,12 @@ public class ScanDetailUtil {
scanResult.informationElements, scanResult.anqpLines, scanResult.frequency);
return new ScanDetail(scanResult, networkDetail, null);
}
+
+ /**
+ * Helper method to quote the SSID in Scan result to use for comparing/filling SSID stored in
+ * WifiConfiguration object.
+ */
+ public static String createQuotedSSID(String ssid) {
+ return "\"" + ssid + "\"";
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/PasspointManagementObjectManagerTest.java b/tests/wifitests/src/com/android/server/wifi/PasspointManagementObjectManagerTest.java
index c76bf91a3..d3022b932 100644
--- a/tests/wifitests/src/com/android/server/wifi/PasspointManagementObjectManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/PasspointManagementObjectManagerTest.java
@@ -193,6 +193,21 @@ public class PasspointManagementObjectManagerTest {
assertEquals("testIdentity1", homeSP.getCredential().getUserName());
}
+ /** Verify IOException is thrown when trying to add a SP from a null XML string. */
+ @Test(expected = IOException.class)
+ public void addSPFromNullXmlString() throws Exception {
+ File file = tempFolder.newFile("PerProviderSubscription.conf");
+ PasspointManagementObjectManager moMgr = new PasspointManagementObjectManager(file, true);
+ String xml = null; // Needed to avoid ambiguity on function call.
+ moMgr.addSP(xml);
+ }
+
+ /** Verify IOException is thrown when trying to build a SP from a null XML string. */
+ @Test(expected = IOException.class)
+ public void buildSPFromNullXmlString() throws Exception {
+ PasspointManagementObjectManager.buildSP(null);
+ }
+
/** verify that xml serialization/deserialization works */
public void checkXml() throws Exception {
InputStream in = getClass().getClassLoader().getResourceAsStream(R2_TTLS_XML_FILE);
@@ -268,6 +283,27 @@ public class PasspointManagementObjectManagerTest {
assertEquals(9, homeSP.getUpdateIdentifier());
}
+ /** Verify IOException is thrown when trying to modify a SP using a null XML string. */
+ @Test(expected = IOException.class)
+ public void modifySPFromNullXmlString() throws Exception {
+ File file = createFileFromResource(R2_CONFIG_FILE);
+ PasspointManagementObjectManager moMgr = new PasspointManagementObjectManager(file, true);
+ List<HomeSP> homeSPs = moMgr.loadAllSPs();
+ assertEquals(2, homeSPs.size());
+
+ /* PasspointManagementObjectDefinition with null xmlTree. */
+ String urn = "wfa:mo:hotspot2dot0-perprovidersubscription:1.0";
+ String baseUri = "./Wi-Fi/wi-fi.org/PerProviderSubscription/UpdateIdentifier";
+ String xmlTree = null;
+
+ PasspointManagementObjectDefinition moDef =
+ new PasspointManagementObjectDefinition(baseUri, urn, xmlTree);
+ List<PasspointManagementObjectDefinition> moDefs =
+ new ArrayList<PasspointManagementObjectDefinition>();
+ moDefs.add(moDef);
+ moMgr.modifySP("wi-fi.org", moDefs);
+ }
+
/** verify removing an existing service provider works */
@Test
public void removeSP() throws Exception {
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
index a5850005f..fab06bd56 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
@@ -1060,9 +1060,12 @@ public class WifiConfigManagerTest {
config.priority = rand.nextInt(10000);
config.getNetworkSelectionStatus().setNetworkSelectionStatus(
networkSelectionStatusValues.pop());
- networkSelectionStatusToNetworkIdMap.put(
- config.getNetworkSelectionStatus().getNetworkSelectionStatus(),
- config.networkId);
+ // Permanently disabled networks should not be present in PNO scan request.
+ if (!config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()) {
+ networkSelectionStatusToNetworkIdMap.put(
+ config.getNetworkSelectionStatus().getNetworkSelectionStatus(),
+ config.networkId);
+ }
Log.i(TAG, "networkID: " + config.networkId + ", NetworkSelectionStatus: "
+ config.getNetworkSelectionStatus().getNetworkSelectionStatus());
}
@@ -1150,9 +1153,12 @@ public class WifiConfigManagerTest {
config.priority = rand.nextInt(10000);
config.getNetworkSelectionStatus().setNetworkSelectionStatus(
networkSelectionStatusValues.pop());
- networkSelectionStatusToNetworkIdMap.put(
- config.getNetworkSelectionStatus().getNetworkSelectionStatus(),
- config.networkId);
+ // Permanently disabled networks should not be present in PNO scan request.
+ if (!config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()) {
+ networkSelectionStatusToNetworkIdMap.put(
+ config.getNetworkSelectionStatus().getNetworkSelectionStatus(),
+ config.networkId);
+ }
Log.i(TAG, "networkID: " + config.networkId + ", NetworkSelectionStatus: "
+ config.getNetworkSelectionStatus().getNetworkSelectionStatus());
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java b/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java
index 1726e7d32..957e8c24c 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java
@@ -46,6 +46,7 @@ import android.util.LocalLog;
import com.android.internal.R;
import com.android.server.wifi.MockAnswerUtil.AnswerWithArguments;
+import com.android.server.wifi.util.ScanDetailUtil;
import org.junit.After;
import org.junit.Before;
@@ -79,6 +80,23 @@ public class WifiQualifiedNetworkSelectorTest {
mWifiQualifiedNetworkSelector.setUserPreferredBand(1);
mWifiQualifiedNetworkSelector.setWifiNetworkScoreCache(mScoreCache);
when(mClock.elapsedRealtime()).thenReturn(SystemClock.elapsedRealtime());
+
+ //setup Carrier Networks
+ WifiConfiguration wifiConfig = new WifiConfiguration();
+ wifiConfig.SSID = "\"TEST1\"";
+ wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ mCarrierConfiguredNetworks.add(wifiConfig);
+
+ WifiConfiguration wifiConfig1 = new WifiConfiguration();
+ wifiConfig1.SSID = "\"TEST2\"";
+ wifiConfig1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ mCarrierConfiguredNetworks.add(wifiConfig1);
+
+ WifiConfiguration wifiConfig2 = new WifiConfiguration();
+ wifiConfig2.SSID = "\"TEST3\"";
+ wifiConfig2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ mCarrierConfiguredNetworks.add(wifiConfig2);
+ mWifiQualifiedNetworkSelector.setCarrierConfiguredNetworks(mCarrierConfiguredNetworks);
}
@After
@@ -98,6 +116,7 @@ public class WifiQualifiedNetworkSelectorTest {
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";
+ List<WifiConfiguration> mCarrierConfiguredNetworks = new ArrayList<WifiConfiguration>();
private List<ScanDetail> getScanDetails(String[] ssids, String[] bssids, int[] frequencies,
String[] caps, int[] levels) {
@@ -1070,6 +1089,10 @@ public class WifiQualifiedNetworkSelectorTest {
//first QNS
mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, scanDetails, false,
false, true, false);
+ when(mWifiInfo.getNetworkId()).thenReturn(1);
+ when(mWifiInfo.getBSSID()).thenReturn(bssids[1]);
+ when(mWifiInfo.is24GHz()).thenReturn(false);
+ when(mWifiConfigManager.getEnableAutoJoinWhenAssociated()).thenReturn(true);
//immediately second QNS
WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(true,
false, scanDetails, false, true, false, false);
@@ -1879,10 +1902,12 @@ public class WifiQualifiedNetworkSelectorTest {
// The second scan result is for an ephemeral network which was previously deleted
when(mWifiConfigManager
- .wasEphemeralNetworkDeleted(scanDetails.get(0).getScanResult().SSID))
+ .wasEphemeralNetworkDeleted(ScanDetailUtil.createQuotedSSID(
+ scanDetails.get(0).getScanResult().SSID)))
.thenReturn(false);
when(mWifiConfigManager
- .wasEphemeralNetworkDeleted(scanDetails.get(1).getScanResult().SSID))
+ .wasEphemeralNetworkDeleted(ScanDetailUtil.createQuotedSSID(
+ scanDetails.get(1).getScanResult().SSID)))
.thenReturn(true);
WifiConfiguration.NetworkSelectionStatus selectionStatus =
@@ -2325,4 +2350,193 @@ public class WifiQualifiedNetworkSelectorTest {
false, scanDetails, false, true, false, false);
verifySelectedResult(chosenScanResult, candidate);
}
+
+ /**
+ * Case #48 no new QNS if current network doesn't show up in the
+ * scan results.
+ *
+ * In this test. we simulate following scenario:
+ * WifiStateMachine is under connected state and 2.4GHz test1 is connected.
+ * The second scan results contains test2 which is 5GHz but no test1. Skip
+ * QNS to avoid aggressive network switching.
+ *
+ * expected return null
+ */
+ @Test
+ public void noNewQNSCurrentNetworkNotInScanResults() {
+ //Prepare saved network configurations.
+ String[] ssidsConfig = DEFAULT_SSIDS;
+ int[] security = {SECURITY_PSK, SECURITY_PSK};
+ WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssidsConfig, security);
+ prepareConfigStore(savedConfigs);
+ final List<WifiConfiguration> savedNetwork = Arrays.asList(savedConfigs);
+ when(mWifiConfigManager.getSavedNetworks()).thenReturn(savedNetwork);
+
+ //Prepare the first scan results.
+ String[] ssids = {DEFAULT_SSIDS[0]};
+ String[] bssids = {DEFAULT_BSSIDS[0]};
+ int[] frequencies = {2437};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {-78};
+ List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
+ scanResultLinkConfiguration(savedConfigs, scanDetails);
+
+ //Connect to test1.
+ mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, scanDetails, false,
+ false, true, false);
+
+ when(mWifiInfo.getNetworkId()).thenReturn(1);
+ when(mWifiInfo.getBSSID()).thenReturn(bssids[0]);
+ when(mWifiInfo.is24GHz()).thenReturn(true);
+ mWifiQualifiedNetworkSelector.setWifiNetworkScoreCache(null);
+ when(mWifiConfigManager.getEnableAutoJoinWhenAssociated()).thenReturn(true);
+ when(mClock.elapsedRealtime()).thenReturn(SystemClock.elapsedRealtime() + 11 * 1000);
+
+ //Prepare the second scan results which doesn't contain test1.
+ ssids[0] = DEFAULT_SSIDS[1];
+ bssids[0] = DEFAULT_BSSIDS[1];
+ frequencies[0] = 5180;
+ caps[0] = "[WPA2-EAP-CCMP][ESS]";
+ levels[0] = WifiQualifiedNetworkSelector.QUALIFIED_RSSI_5G_BAND;
+ scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
+ scanResultLinkConfiguration(savedConfigs, scanDetails);
+
+ //Skip the second network selection since current connected network is
+ //missing from the scan results.
+ WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
+ false, scanDetails, false, true, false, false);
+ assertEquals("Expect no network selection", null, candidate);
+ }
+
+ /**
+ * Case #49 Between two 2G Carrier networks, choose the one with stronger RSSI value
+ * if other conditions are the same and the RSSI values are not staturated.
+ */
+ @Test
+ public void chooseStrongerRssi2GCarrierNetwork() {
+
+ String[] ssids = {"TEST1", "TEST2"};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] frequencies = {2470, 2437};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {-65,-55};
+ int[] security = {SECURITY_PSK, SECURITY_PSK};
+
+ List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
+
+ WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
+ prepareConfigStore(savedConfigs);
+
+ ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
+ WifiConfiguration unTrustedNetworkCandidate = mock(WifiConfiguration.class);
+ unTrustedNetworkCandidate.SSID = null;
+ unTrustedNetworkCandidate.networkId = WifiConfiguration.INVALID_NETWORK_ID;
+ when(mWifiConfigManager.updateSavedNetworkWithNewScanDetail(scanDetails.get(1),
+ false)).thenReturn(null);
+ when(mWifiConfigManager
+ .wifiConfigurationFromScanResult(scanDetails.get(1).getScanResult()))
+ .thenReturn(unTrustedNetworkCandidate);
+ WifiConfiguration.NetworkSelectionStatus selectionStatus =
+ mock(WifiConfiguration.NetworkSelectionStatus.class);
+ when(unTrustedNetworkCandidate.getNetworkSelectionStatus()).thenReturn(selectionStatus);
+ when(selectionStatus.getCandidate()).thenReturn(chosenScanResult);
+
+ WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
+ true, scanDetails, false, false, true, false);
+ assertSame(unTrustedNetworkCandidate, candidate);
+ }
+
+ /**
+ * Case #50 Choose 5G over 2G.
+ */
+ @Test
+ public void choose5GNetworkOver2GNetwork() {
+
+ String[] ssids = {"TEST1", "TEST2"};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] frequencies = {2437, 5240};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {-65,-55};
+
+ List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
+ ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
+ WifiConfiguration unTrustedNetworkCandidate = mock(WifiConfiguration.class);
+ unTrustedNetworkCandidate.SSID = null;
+ unTrustedNetworkCandidate.networkId = WifiConfiguration.INVALID_NETWORK_ID;
+ when(mWifiConfigManager.updateSavedNetworkWithNewScanDetail(scanDetails.get(1),
+ false)).thenReturn(null);
+ when(mWifiConfigManager
+ .wifiConfigurationFromScanResult(scanDetails.get(1).getScanResult()))
+ .thenReturn(unTrustedNetworkCandidate);
+ WifiConfiguration.NetworkSelectionStatus selectionStatus =
+ mock(WifiConfiguration.NetworkSelectionStatus.class);
+ when(unTrustedNetworkCandidate.getNetworkSelectionStatus()).thenReturn(selectionStatus);
+ when(selectionStatus.getCandidate()).thenReturn(chosenScanResult);
+
+ WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
+ true, scanDetails, false, false, true, false);
+ assertSame(unTrustedNetworkCandidate, candidate);
+ }
+
+ /**
+ * Case #51 Stay on same BSSID & SSID.
+ */
+ @Test
+ public void chooseSameNetwork() {
+
+ String[] ssids = {"TEST1", "TEST2"};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] frequencies = {2470, 2437};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
+ int[] levels = {-65,-55};
+ int[] security = {SECURITY_PSK, SECURITY_PSK};
+
+ List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
+ WifiConfiguration[] savedConfigs = generateWifiConfigurations(ssids, security);
+ prepareConfigStore(savedConfigs);
+
+ ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
+ WifiConfiguration unTrustedNetworkCandidate = mock(WifiConfiguration.class);
+ unTrustedNetworkCandidate.SSID = null;
+ unTrustedNetworkCandidate.networkId = WifiConfiguration.INVALID_NETWORK_ID;
+
+ when(mWifiInfo.getNetworkId()).thenReturn(0);
+ when(mWifiInfo.getBSSID()).thenReturn(bssids[0]);
+ when(mWifiConfigManager.updateSavedNetworkWithNewScanDetail(scanDetails.get(0),
+ true)).thenReturn(null);
+ when(mWifiConfigManager
+ .wifiConfigurationFromScanResult(scanDetails.get(0).getScanResult()))
+ .thenReturn(unTrustedNetworkCandidate);
+ WifiConfiguration.NetworkSelectionStatus selectionStatus =
+ mock(WifiConfiguration.NetworkSelectionStatus.class);
+ when(unTrustedNetworkCandidate.getNetworkSelectionStatus()).thenReturn(selectionStatus);
+ when(selectionStatus.getCandidate()).thenReturn(chosenScanResult);
+
+ WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
+ true, scanDetails, false, true, false, false);
+ assertSame(unTrustedNetworkCandidate, candidate);
+ }
+
+ /**
+ * Case #52 Test condition where no Carrier networks are defined.
+ */
+ @Test
+ public void testNoCarrierNetworks() {
+
+ String[] ssids = {"TEST1", "TEST2"};
+ String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
+ int[] frequencies = {5200, 5240};
+ String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
+ // test2 has slightly stronger RSSI value than test1
+ int[] levels = {-65,-53};
+
+ List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels);
+
+ List<WifiConfiguration> nullCarrierConfiguredNetworks = new ArrayList<WifiConfiguration>();
+ mWifiQualifiedNetworkSelector.setCarrierConfiguredNetworks(nullCarrierConfiguredNetworks);
+
+ WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false,
+ true, scanDetails, false, false, true, false);
+ assertEquals("Expect no network selection", null, candidate);
+ }
}