diff options
author | Pankaj Kanwar <pkanwar@google.com> | 2016-12-07 17:57:29 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2016-12-07 17:57:29 +0000 |
commit | 139a17fd50072bcc04749c18e0f2ebf3385f29b8 (patch) | |
tree | efca4cbbfe354a0f8c06a00f5d5ba3be21b7b69b | |
parent | c05b60f706ef4cbee6d12c01224afe07fad725be (diff) | |
parent | e22b68960966645a77cb71042879a4ab0d9bd638 (diff) | |
download | android_frameworks_opt_net_wifi-139a17fd50072bcc04749c18e0f2ebf3385f29b8.tar.gz android_frameworks_opt_net_wifi-139a17fd50072bcc04749c18e0f2ebf3385f29b8.tar.bz2 android_frameworks_opt_net_wifi-139a17fd50072bcc04749c18e0f2ebf3385f29b8.zip |
Merge "DO NOT MERGE: Allow Carriers to specify Wifi Networks." into nyc-mr2-dev
-rw-r--r-- | service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java | 202 | ||||
-rw-r--r-- | tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java | 151 |
2 files changed, 349 insertions, 4 deletions
diff --git a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java index 1ddf6ebcb..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,7 +28,10 @@ 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; @@ -38,6 +44,8 @@ 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; @@ -109,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 @@ -192,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) { @@ -239,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; @@ -583,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 @@ -606,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) { @@ -633,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); @@ -733,10 +800,21 @@ 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( + 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 @@ -872,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; } @@ -956,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. @@ -973,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) { @@ -1061,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/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java b/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java index 49343644a..957e8c24c 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java @@ -80,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 @@ -99,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) { @@ -2370,6 +2388,7 @@ public class WifiQualifiedNetworkSelectorTest { 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); @@ -2388,4 +2407,136 @@ public class WifiQualifiedNetworkSelectorTest { 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); + } } |