diff options
-rw-r--r-- | service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java | 31 | ||||
-rw-r--r-- | tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java | 165 |
2 files changed, 190 insertions, 6 deletions
diff --git a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java index 1601f7361..8a3f7aa2b 100644 --- a/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java +++ b/service/java/com/android/server/wifi/WifiQualifiedNetworkSelector.java @@ -55,6 +55,8 @@ public class WifiQualifiedNetworkSelector { private String mCurrentBssid = null; //buffer most recent scan results private List<ScanDetail> mScanDetails = null; + //buffer of filtered scan results (Scan results considered by network selection) + private volatile List<ScanDetail> mFilteredScanDetails = null; //Minimum time gap between last successful Qualified Network Selection and new selection attempt //usable only when current state is connected state default 10 s @@ -134,6 +136,16 @@ public class WifiQualifiedNetworkSelector { } /** + * @return the list of ScanDetails scored as potential candidates by the last run of + * selectQualifiedNetwork, this will be empty if QNS determined no selection was needed on last + * run. This includes scan details of sufficient signal strength, and had an associated + * WifiConfiguration. + */ + public List<ScanDetail> getFilteredScanDetails() { + return mFilteredScanDetails; + } + + /** * set the user selected preferred band * * @param band preferred band user selected @@ -615,6 +627,7 @@ public class WifiQualifiedNetworkSelector { boolean isSupplicantTransient) { qnsLog("==========start qualified Network Selection=========="); mScanDetails = scanDetails; + List<ScanDetail> filteredScanDetails = new ArrayList<>(); if (mCurrentConnectedNetwork == null) { mCurrentConnectedNetwork = mWifiConfigManager.getWifiConfiguration(mWifiInfo.getNetworkId()); @@ -628,6 +641,7 @@ public class WifiQualifiedNetworkSelector { isDisconnected, isSupplicantTransient)) { qnsLog("Quit qualified Network Selection since it is not forced and current network is" + " qualified already"); + mFilteredScanDetails = filteredScanDetails; return null; } @@ -705,11 +719,11 @@ public class WifiQualifiedNetworkSelector { } //check whether this scan result belong to a saved network - boolean ephemeral = false; + boolean potentiallyEphemeral = false; List<WifiConfiguration> associatedWifiConfigurations = mWifiConfigManager.updateSavedNetworkWithNewScanDetail(scanDetail); if (associatedWifiConfigurations == null) { - ephemeral = true; + potentiallyEphemeral = true; if (mDbg) { notSavedScan.append(scanId + " / "); } @@ -717,14 +731,14 @@ public class WifiQualifiedNetworkSelector { //if there are more than 1 associated network, it must be a passpoint network WifiConfiguration network = associatedWifiConfigurations.get(0); if (network.ephemeral) { - ephemeral = true; + potentiallyEphemeral = true; } } - if (ephemeral) { + if (potentiallyEphemeral) { if (isUntrustedConnectionsAllowed && mNetworkScoreCache != null) { int netScore = mNetworkScoreCache.getNetworkScore(scanResult, false); - //get network score + //get network score (Determine if this is an 'Ephemeral' network) if (netScore != WifiNetworkScoreCache.INVALID_NETWORK_SCORE) { qnsLog(scanId + "has score: " + netScore); if (netScore > unTrustedHighestScore) { @@ -732,9 +746,14 @@ public class WifiQualifiedNetworkSelector { untrustedScanResultCandidate = scanResult; qnsLog(scanId + " become the new untrusted candidate"); } + // scanDetail is for available ephemeral network + filteredScanDetails.add(scanDetail); } } continue; + } else { + // scanDetail is for available saved network + filteredScanDetails.add(scanDetail); } // calculate the core of each scanresult whose associated network is not ephemeral. Due @@ -782,6 +801,8 @@ public class WifiQualifiedNetworkSelector { } } + mFilteredScanDetails = filteredScanDetails; + //kick the score manager if there is any unscored network if (mScoreManager != null && unscoredNetworks.size() != 0) { NetworkKey[] unscoredNetworkKeys = diff --git a/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java b/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java index cc42a9d61..3d7aa65f1 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiQualifiedNetworkSelectorTest.java @@ -23,7 +23,6 @@ import static com.android.server.wifi.WifiConfigurationTestUtil.generateWifiConf import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; @@ -258,6 +257,13 @@ public class WifiQualifiedNetworkSelectorTest { when(mScoreCache.hasScoreCurve(scanResult)).thenReturn(true); when(mScoreCache.getNetworkScore(eq(scanResult), anyBoolean())).thenReturn(score); when(mScoreCache.getNetworkScore(scanResult)).thenReturn(score); + } else { + when(mScoreCache.isScoredNetwork(scanResult)).thenReturn(false); + when(mScoreCache.hasScoreCurve(scanResult)).thenReturn(false); + when(mScoreCache.getNetworkScore(eq(scanResult), anyBoolean())).thenReturn( + WifiNetworkScoreCache.INVALID_NETWORK_SCORE); + when(mScoreCache.getNetworkScore(scanResult)).thenReturn( + WifiNetworkScoreCache.INVALID_NETWORK_SCORE); } when(mScoreCache.getMeteredHint(scanResult)).thenReturn(meteredHints[i]); } @@ -1075,6 +1081,8 @@ public class WifiQualifiedNetworkSelectorTest { WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork(false, false, scanDetails, false, true, false, false); assertEquals("choose the wrong BSSID", null, candidate); + assertEquals("Should receive zero filteredScanDetails", 0, + mWifiQualifiedNetworkSelector.getFilteredScanDetails().size()); } /** @@ -1645,4 +1653,159 @@ public class WifiQualifiedNetworkSelectorTest { assertSame(candidate, unTrustedNetworkCandidate); assertEquals(meteredHints[1], candidate.meteredHint); } + + /** + * Case #34 Test Filtering of potential candidate scanDetails (Untrusted allowed) + * + * In this test. we simulate following scenario + * WifiStateMachine is under disconnected state + * test1 is @ 2GHz with RSSI -60 + * test2 is @ 5Ghz with RSSI -86, (below minimum threshold) + * test3 is @ 5Ghz with RSSI -50, however it has no associated saved config + * test4 is @ 2Ghz with RSSI -62, no associated config, but is Ephemeral + * + * Expected behavior: test1 is chosen due to 5GHz signal is too weak (5GHz bonus can not + * compensate). + * test1 & test4's scanDetails are returned by 'getFilteredScanDetail()' + */ + @Test + public void testGetFilteredScanDetailsReturnsOnlyConsideredScanDetails_untrustedAllowed() { + String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\""}; + String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55", + "c0:ff:ee:ee:e3:ee"}; + int[] frequencies = {2437, 5180, 5180, 2437}; + String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", + "[WPA2-EAP-CCMP][ESS]"}; + int[] levels = {-60, -86, -50, -62}; + int[] security = {SECURITY_PSK, SECURITY_PSK, SECURITY_PSK, SECURITY_PSK}; + boolean[] meteredHints = {false, false, false, true}; + Integer[] scores = {null, null, null, 120}; + + //Create all 4 scanDetails + List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels); + + //Setup NetworkScoreCache for detecting ephemeral networks ("test4") + configureScoreCache(scanDetails, scores, meteredHints); + WifiConfiguration unTrustedNetworkCandidate = mock(WifiConfiguration.class); + unTrustedNetworkCandidate.SSID = null; + unTrustedNetworkCandidate.networkId = WifiConfiguration.INVALID_NETWORK_ID; + ScanResult untrustedScanResult = scanDetails.get(3).getScanResult(); + when(mWifiConfigManager + .wifiConfigurationFromScanResult(untrustedScanResult)) + .thenReturn(unTrustedNetworkCandidate); + WifiConfiguration.NetworkSelectionStatus selectionStatus = + mock(WifiConfiguration.NetworkSelectionStatus.class); + when(unTrustedNetworkCandidate.getNetworkSelectionStatus()).thenReturn(selectionStatus); + + //Set up associated configs for test1 & test2 + WifiConfiguration[] savedConfigs = generateWifiConfigurations( + Arrays.copyOfRange(ssids, 0, 2), Arrays.copyOfRange(security, 0, 2)); + prepareConfigStore(savedConfigs); + List<ScanDetail> savedScanDetails = new ArrayList<ScanDetail>(scanDetails.subList(0, 2)); + final List<WifiConfiguration> savedNetwork = Arrays.asList(savedConfigs); + when(mWifiConfigManager.getConfiguredNetworks()).thenReturn(savedNetwork); + scanResultLinkConfiguration(savedConfigs, savedScanDetails); + + //Force mock ConfigManager to return null (and not an empty list) for "test3" & "test4" + when(mWifiConfigManager.updateSavedNetworkWithNewScanDetail(scanDetails.get(2))) + .thenReturn(null); + when(mWifiConfigManager.updateSavedNetworkWithNewScanDetail(scanDetails.get(3))) + .thenReturn(null); + + ScanResult chosenScanResult = scanDetails.get(0).getScanResult(); + + WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork( + false /* forceSelectNetwork */, + true /* isUntrustedConnectionsAllowed */, + scanDetails, + false, /* isLinkDebouncing */ + false, /* isConnected */ + true, /* isDisconnected */ + false /* isSupplicantTransient */); + + verifySelectedResult(chosenScanResult, candidate); + //Verify two scanDetails returned in the filteredScanDetails + assertEquals(2, mWifiQualifiedNetworkSelector.getFilteredScanDetails().size()); + assertEquals(mWifiQualifiedNetworkSelector.getFilteredScanDetails().get(0).toString(), + scanDetails.get(0).toString()); + assertEquals(mWifiQualifiedNetworkSelector.getFilteredScanDetails().get(1).toString(), + scanDetails.get(3).toString()); + } + + + /** + * Case #35 Test Filtering of potential candidate scanDetails (Untrusted disallowed) + * + * In this test. we simulate following scenario + * WifiStateMachine is under disconnected state + * test1 is @ 2GHz with RSSI -60 + * test2 is @ 5Ghz with RSSI -86, (below minimum threshold) + * test3 is @ 5Ghz with RSSI -50, however it has no associated saved config + * test4 is @ 2Ghz with RSSI -62, no associated config, but is Ephemeral + * + * Expected behavior: test1 is chosen due to 5GHz signal is too weak (5GHz bonus can not + * compensate). + * test1 & test4's scanDetails are returned by 'getFilteredScanDetail()' + */ + @Test + public void testGetFilteredScanDetailsReturnsOnlyConsideredScanDetails_untrustedDisallowed() { + String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\""}; + String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55", + "c0:ff:ee:ee:e3:ee"}; + int[] frequencies = {2437, 5180, 5180, 2437}; + String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", + "[WPA2-EAP-CCMP][ESS]"}; + int[] levels = {-60, -86, -50, -62}; + int[] security = {SECURITY_PSK, SECURITY_PSK, SECURITY_PSK, SECURITY_PSK}; + boolean[] meteredHints = {false, false, false, true}; + Integer[] scores = {null, null, null, 120}; + + //Create all 4 scanDetails + List<ScanDetail> scanDetails = getScanDetails(ssids, bssids, frequencies, caps, levels); + + //Setup NetworkScoreCache for detecting ephemeral networks ("test4") + configureScoreCache(scanDetails, scores, meteredHints); + WifiConfiguration unTrustedNetworkCandidate = mock(WifiConfiguration.class); + unTrustedNetworkCandidate.SSID = null; + unTrustedNetworkCandidate.networkId = WifiConfiguration.INVALID_NETWORK_ID; + ScanResult untrustedScanResult = scanDetails.get(3).getScanResult(); + when(mWifiConfigManager + .wifiConfigurationFromScanResult(untrustedScanResult)) + .thenReturn(unTrustedNetworkCandidate); + WifiConfiguration.NetworkSelectionStatus selectionStatus = + mock(WifiConfiguration.NetworkSelectionStatus.class); + when(unTrustedNetworkCandidate.getNetworkSelectionStatus()).thenReturn(selectionStatus); + + //Set up associated configs for test1 & test2 + WifiConfiguration[] savedConfigs = generateWifiConfigurations( + Arrays.copyOfRange(ssids, 0, 2), Arrays.copyOfRange(security, 0, 2)); + prepareConfigStore(savedConfigs); + List<ScanDetail> savedScanDetails = new ArrayList<ScanDetail>(scanDetails.subList(0, 2)); + final List<WifiConfiguration> savedNetwork = Arrays.asList(savedConfigs); + when(mWifiConfigManager.getConfiguredNetworks()).thenReturn(savedNetwork); + scanResultLinkConfiguration(savedConfigs, savedScanDetails); + + //Force mock ConfigManager to return null (and not an empty list) for "test3" & "test4" + when(mWifiConfigManager.updateSavedNetworkWithNewScanDetail(scanDetails.get(2))) + .thenReturn(null); + when(mWifiConfigManager.updateSavedNetworkWithNewScanDetail(scanDetails.get(3))) + .thenReturn(null); + + ScanResult chosenScanResult = scanDetails.get(0).getScanResult(); + + WifiConfiguration candidate = mWifiQualifiedNetworkSelector.selectQualifiedNetwork( + false /* forceSelectNetwork */, + false /* isUntrustedConnectionsAllowed */, + scanDetails, + false, /* isLinkDebouncing */ + false, /* isConnected */ + true, /* isDisconnected */ + false /* isSupplicantTransient */); + + verifySelectedResult(chosenScanResult, candidate); + //Verify two scanDetails returned in the filteredScanDetails + assertEquals(1, mWifiQualifiedNetworkSelector.getFilteredScanDetails().size()); + assertEquals(mWifiQualifiedNetworkSelector.getFilteredScanDetails().get(0).toString(), + scanDetails.get(0).toString()); + } } |