diff options
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); + } } |