diff options
Diffstat (limited to 'service')
6 files changed, 270 insertions, 19 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 + "\""; + } } |