blob: fadfc6bc53333df86b73c815217287cf640abefd [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wifi;
import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus
.NETWORK_SELECTION_TEMPORARY_DISABLED;
import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_PSK;
import static com.android.server.wifi.WifiConfigurationTestUtil.generateWifiConfig;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiNetworkSuggestion;
import android.net.wifi.WifiSsid;
import android.util.LocalLog;
import android.util.Pair;
import androidx.test.filters.SmallTest;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Unit tests for {@link com.android.server.wifi.NetworkSuggestionEvaluator}.
*/
@SmallTest
public class NetworkSuggestionEvaluatorTest {
private static final int TEST_UID = 3555;
private static final int TEST_UID_OTHER = 3545;
private static final int TEST_NETWORK_ID = 55;
private static final String TEST_PACKAGE = "com.test";
private static final String TEST_PACKAGE_OTHER = "com.test.other";
private @Mock WifiConfigManager mWifiConfigManager;
private @Mock WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
private @Mock Clock mClock;
private NetworkSuggestionEvaluator mNetworkSuggestionEvaluator;
/** Sets up test. */
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mNetworkSuggestionEvaluator = new NetworkSuggestionEvaluator(
mWifiNetworkSuggestionsManager, mWifiConfigManager, new LocalLog(100));
}
/**
* Ensure that we ignore all scan results not matching the network suggestion.
* Expected candidate: null
* Expected connectable Networks: {}
*/
@Test
public void testSelectNetworkSuggestionForNoMatch() {
String[] scanSsids = {"test1", "test2"};
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2470, 2437};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
int[] levels = {-67, -76};
String[] suggestionSsids = {};
int[] securities = {};
boolean[] appInteractions = {};
boolean[] meteredness = {};
int[] priorities = {};
int[] uids = {};
String[] packageNames = {};
ScanDetail[] scanDetails =
buildScanDetails(scanSsids, bssids, freqs, caps, levels, mClock);
WifiNetworkSuggestion[] suggestions = buildNetworkSuggestions(suggestionSsids, securities,
appInteractions, meteredness, priorities, uids, packageNames);
// Link the scan result with suggestions.
linkScanDetailsWithNetworkSuggestions(scanDetails, suggestions);
List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
WifiConfiguration candidate = mNetworkSuggestionEvaluator.evaluateNetworks(
Arrays.asList(scanDetails), null, null, true, false,
(ScanDetail scanDetail, WifiConfiguration configuration, int score) -> {
connectableNetworks.add(Pair.create(scanDetail, configuration));
});
assertNull(candidate);
assertTrue(connectableNetworks.isEmpty());
}
/**
* Ensure that we select the only matching network suggestion.
* Expected candidate: suggestionSsids[0]
* Expected connectable Networks: {suggestionSsids[0]}
*/
@Test
public void testSelectNetworkSuggestionForOneMatch() {
String[] scanSsids = {"test1", "test2"};
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2470, 2437};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
int[] levels = {-67, -76};
String[] suggestionSsids = {"\"" + scanSsids[0] + "\""};
int[] securities = {SECURITY_PSK};
boolean[] appInteractions = {true};
boolean[] meteredness = {true};
int[] priorities = {-1};
int[] uids = {TEST_UID};
String[] packageNames = {TEST_PACKAGE};
ScanDetail[] scanDetails =
buildScanDetails(scanSsids, bssids, freqs, caps, levels, mClock);
WifiNetworkSuggestion[] suggestions = buildNetworkSuggestions(suggestionSsids, securities,
appInteractions, meteredness, priorities, uids, packageNames);
// Link the scan result with suggestions.
linkScanDetailsWithNetworkSuggestions(scanDetails, suggestions);
// setup config manager interactions.
setupAddToWifiConfigManager(suggestions[0].wifiConfiguration);
List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
WifiConfiguration candidate = mNetworkSuggestionEvaluator.evaluateNetworks(
Arrays.asList(scanDetails), null, null, true, false,
(ScanDetail scanDetail, WifiConfiguration configuration, int score) -> {
connectableNetworks.add(Pair.create(scanDetail, configuration));
});
assertNotNull(candidate);
assertEquals(suggestionSsids[0] , candidate.SSID);
validateConnectableNetworks(connectableNetworks, scanSsids[0]);
verifyAddToWifiConfigManager(suggestions[0].wifiConfiguration);
}
/**
* Ensure that we select the network suggestion corresponding to the scan result with
* highest RSSI.
* Expected candidate: suggestionSsids[1]
* Expected connectable Networks: {suggestionSsids[0], suggestionSsids[1]}
*/
@Test
public void testSelectNetworkSuggestionForMultipleMatch() {
String[] scanSsids = {"test1", "test2"};
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2470, 2437};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
int[] levels = {-56, -45};
String[] suggestionSsids = {"\"" + scanSsids[0] + "\"", "\"" + scanSsids[1] + "\""};
int[] securities = {SECURITY_PSK, SECURITY_PSK};
boolean[] appInteractions = {true, true};
boolean[] meteredness = {true, true};
int[] priorities = {-1, -1};
int[] uids = {TEST_UID, TEST_UID};
String[] packageNames = {TEST_PACKAGE, TEST_PACKAGE};
ScanDetail[] scanDetails =
buildScanDetails(scanSsids, bssids, freqs, caps, levels, mClock);
WifiNetworkSuggestion[] suggestions = buildNetworkSuggestions(suggestionSsids, securities,
appInteractions, meteredness, priorities, uids, packageNames);
// Link the scan result with suggestions.
linkScanDetailsWithNetworkSuggestions(scanDetails, suggestions);
// setup config manager interactions.
setupAddToWifiConfigManager(suggestions[0].wifiConfiguration,
suggestions[1].wifiConfiguration);
List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
WifiConfiguration candidate = mNetworkSuggestionEvaluator.evaluateNetworks(
Arrays.asList(scanDetails), null, null, true, false,
(ScanDetail scanDetail, WifiConfiguration configuration, int score) -> {
connectableNetworks.add(Pair.create(scanDetail, configuration));
});
assertNotNull(candidate);
assertEquals(suggestionSsids[1] , candidate.SSID);
validateConnectableNetworks(connectableNetworks, scanSsids[0], scanSsids[1]);
verifyAddToWifiConfigManager(suggestions[1].wifiConfiguration,
suggestions[1].wifiConfiguration);
}
/**
* Ensure that we select the network suggestion corresponding to the scan result with
* higest priority.
* Expected candidate: suggestionSsids[0]
* Expected connectable Networks: {suggestionSsids[0], suggestionSsids[1]}
*/
@Test
public void testSelectNetworkSuggestionForMultipleMatchHighPriorityWins() {
String[] scanSsids = {"test1", "test2"};
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2470, 2437};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
int[] levels = {-56, -45};
String[] suggestionSsids = {"\"" + scanSsids[0] + "\"", "\"" + scanSsids[1] + "\""};
int[] securities = {SECURITY_PSK, SECURITY_PSK};
boolean[] appInteractions = {true, true};
boolean[] meteredness = {true, true};
int[] priorities = {5, 1};
int[] uids = {TEST_UID, TEST_UID};
String[] packageNames = {TEST_PACKAGE, TEST_PACKAGE};
ScanDetail[] scanDetails =
buildScanDetails(scanSsids, bssids, freqs, caps, levels, mClock);
WifiNetworkSuggestion[] suggestions = buildNetworkSuggestions(suggestionSsids, securities,
appInteractions, meteredness, priorities, uids, packageNames);
// Link the scan result with suggestions.
linkScanDetailsWithNetworkSuggestions(scanDetails, suggestions);
// setup config manager interactions.
setupAddToWifiConfigManager(suggestions[0].wifiConfiguration,
suggestions[1].wifiConfiguration);
List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
WifiConfiguration candidate = mNetworkSuggestionEvaluator.evaluateNetworks(
Arrays.asList(scanDetails), null, null, true, false,
(ScanDetail scanDetail, WifiConfiguration configuration, int score) -> {
connectableNetworks.add(Pair.create(scanDetail, configuration));
});
assertNotNull(candidate);
assertEquals(suggestionSsids[0] , candidate.SSID);
validateConnectableNetworks(connectableNetworks, scanSsids[0]);
verifyAddToWifiConfigManager(suggestions[0].wifiConfiguration);
}
/**
* Ensure that we select the network suggestion corresponding to the scan result with
* highest RSSI. The lower RSSI scan result has multiple matching suggestions
* (should pick any one in the connectable networks).
*
* Expected candidate: suggestionSsids[0]
* Expected connectable Networks: {suggestionSsids[0],
* (suggestionSsids[1] || suggestionSsids[2]}
*/
@Test
public void testSelectNetworkSuggestionForMultipleMatchWithMultipleSuggestions() {
String[] scanSsids = {"test1", "test2"};
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2470, 2437};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
int[] levels = {-23, -45};
String[] suggestionSsids = {"\"" + scanSsids[0] + "\"", "\"" + scanSsids[1] + "\"",
"\"" + scanSsids[1] + "\""};
int[] securities = {SECURITY_PSK, SECURITY_PSK, SECURITY_PSK};
boolean[] appInteractions = {true, true, false};
boolean[] meteredness = {true, true, false};
int[] priorities = {-1, -1, -1};
int[] uids = {TEST_UID, TEST_UID, TEST_UID_OTHER};
String[] packageNames = {TEST_PACKAGE, TEST_PACKAGE, TEST_PACKAGE_OTHER};
ScanDetail[] scanDetails =
buildScanDetails(scanSsids, bssids, freqs, caps, levels, mClock);
WifiNetworkSuggestion[] suggestions = buildNetworkSuggestions(suggestionSsids, securities,
appInteractions, meteredness, priorities, uids, packageNames);
// Link the scan result with suggestions.
linkScanDetailsWithNetworkSuggestions(scanDetails, suggestions);
// setup config manager interactions.
setupAddToWifiConfigManager(suggestions[0].wifiConfiguration,
suggestions[1].wifiConfiguration, suggestions[2].wifiConfiguration);
List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
WifiConfiguration candidate = mNetworkSuggestionEvaluator.evaluateNetworks(
Arrays.asList(scanDetails), null, null, true, false,
(ScanDetail scanDetail, WifiConfiguration configuration, int score) -> {
connectableNetworks.add(Pair.create(scanDetail, configuration));
});
assertNotNull(candidate);
assertEquals(suggestionSsids[0] , candidate.SSID);
validateConnectableNetworks(connectableNetworks, scanSsids);
verifyAddToWifiConfigManager(suggestions[0].wifiConfiguration,
suggestions[1].wifiConfiguration);
}
/**
* Ensure that we select the network suggestion with the higest priority among network
* suggestions from the same package. Among different packages, pick the suggestion
* corresponding to the scan result with highest RSSI.
*
* The suggestion[1] has higher priority than suggestion[0] even though it has lower RSSI than
* suggestion[0].
*
* Expected candidate: suggestionSsids[1]
* Expected connectable Networks: {suggestionSsids[1],
* (suggestionSsids[2],
* suggestionSsids[3]}
*/
@Test
public void
testSelectNetworkSuggestionForMultipleMatchWithMultipleSuggestionsHighPriorityWins() {
String[] scanSsids = {"test1", "test2", "test3", "test4"};
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "6c:fc:de:34:12",
"6c:fd:a1:11:11:98"};
int[] freqs = {2470, 2437, 2470, 2437};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]",
"[WPA2-EAP-CCMP][ESS]"};
int[] levels = {-23, -45, -56, -65};
String[] suggestionSsids = {"\"" + scanSsids[0] + "\"", "\"" + scanSsids[1] + "\"",
"\"" + scanSsids[2] + "\"", "\"" + scanSsids[3] + "\""};
int[] securities = {SECURITY_PSK, SECURITY_PSK, SECURITY_PSK, SECURITY_PSK};
boolean[] appInteractions = {true, true, false, false};
boolean[] meteredness = {true, true, false, false};
int[] priorities = {0, 5, -1, -1};
int[] uids = {TEST_UID, TEST_UID, TEST_UID_OTHER, TEST_UID_OTHER};
String[] packageNames = {TEST_PACKAGE, TEST_PACKAGE, TEST_PACKAGE_OTHER,
TEST_PACKAGE_OTHER};
ScanDetail[] scanDetails =
buildScanDetails(scanSsids, bssids, freqs, caps, levels, mClock);
WifiNetworkSuggestion[] suggestions = buildNetworkSuggestions(suggestionSsids, securities,
appInteractions, meteredness, priorities, uids, packageNames);
// Link the scan result with suggestions.
linkScanDetailsWithNetworkSuggestions(scanDetails, suggestions);
// setup config manager interactions.
setupAddToWifiConfigManager(suggestions[0].wifiConfiguration,
suggestions[1].wifiConfiguration, suggestions[2].wifiConfiguration,
suggestions[3].wifiConfiguration);
List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
WifiConfiguration candidate = mNetworkSuggestionEvaluator.evaluateNetworks(
Arrays.asList(scanDetails), null, null, true, false,
(ScanDetail scanDetail, WifiConfiguration configuration, int score) -> {
connectableNetworks.add(Pair.create(scanDetail, configuration));
});
assertNotNull(candidate);
assertEquals(suggestionSsids[1] , candidate.SSID);
validateConnectableNetworks(connectableNetworks, scanSsids[1], scanSsids[2], scanSsids[3]);
verifyAddToWifiConfigManager(suggestions[1].wifiConfiguration,
suggestions[2].wifiConfiguration, suggestions[3].wifiConfiguration);
}
/**
* Ensure that we select the only matching network suggestion, but return null because
* we failed the {@link WifiConfigManager} interactions.
* Expected candidate: null.
* Expected connectable Networks: {suggestionSsids[0], suggestionSsids[1]}
*/
@Test
public void testSelectNetworkSuggestionForOneMatchButFailToAddToWifiConfigManager() {
String[] scanSsids = {"test1", "test2"};
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2470, 2437};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
int[] levels = {-67, -76};
String[] suggestionSsids = {"\"" + scanSsids[0] + "\""};
int[] securities = {SECURITY_PSK};
boolean[] appInteractions = {true};
boolean[] meteredness = {true};
int[] priorities = {-1};
int[] uids = {TEST_UID};
String[] packageNames = {TEST_PACKAGE};
ScanDetail[] scanDetails =
buildScanDetails(scanSsids, bssids, freqs, caps, levels, mClock);
WifiNetworkSuggestion[] suggestions = buildNetworkSuggestions(suggestionSsids, securities,
appInteractions, meteredness, priorities, uids, packageNames);
// Link the scan result with suggestions.
linkScanDetailsWithNetworkSuggestions(scanDetails, suggestions);
// Fail add to WifiConfigManager
when(mWifiConfigManager.addOrUpdateNetwork(any(), anyInt(), anyString()))
.thenReturn(new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID));
List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
WifiConfiguration candidate = mNetworkSuggestionEvaluator.evaluateNetworks(
Arrays.asList(scanDetails), null, null, true, false,
(ScanDetail scanDetail, WifiConfiguration configuration, int score) -> {
connectableNetworks.add(Pair.create(scanDetail, configuration));
});
assertNull(candidate);
assertTrue(connectableNetworks.isEmpty());
verify(mWifiConfigManager, times(scanSsids.length))
.wasEphemeralNetworkDeleted(anyString());
verify(mWifiConfigManager).getConfiguredNetwork(eq(
suggestions[0].wifiConfiguration.configKey()));
verify(mWifiConfigManager).addOrUpdateNetwork(any(), anyInt(), anyString());
// Verify we did not try to add any new networks or other interactions with
// WifiConfigManager.
verifyNoMoreInteractions(mWifiConfigManager);
}
/**
* Ensure that we select the only matching network suggestion, but that matches an existing
* saved network (maybe saved or maybe it exists from a previous connection attempt) .
* Expected candidate: suggestionSsids[0]
* Expected connectable Networks: {suggestionSsids[0]}
*/
@Test
public void testSelectNetworkSuggestionForOneMatchForExistingNetwork() {
String[] scanSsids = {"test1", "test2"};
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2470, 2437};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
int[] levels = {-67, -76};
String[] suggestionSsids = {"\"" + scanSsids[0] + "\""};
int[] securities = {SECURITY_PSK};
boolean[] appInteractions = {true};
boolean[] meteredness = {true};
int[] priorities = {-1};
int[] uids = {TEST_UID};
String[] packageNames = {TEST_PACKAGE};
ScanDetail[] scanDetails =
buildScanDetails(scanSsids, bssids, freqs, caps, levels, mClock);
WifiNetworkSuggestion[] suggestions = buildNetworkSuggestions(suggestionSsids, securities,
appInteractions, meteredness, priorities, uids, packageNames);
// Link the scan result with suggestions.
linkScanDetailsWithNetworkSuggestions(scanDetails, suggestions);
// Existing saved network matching the credentials.
when(mWifiConfigManager.getConfiguredNetwork(suggestions[0].wifiConfiguration.configKey()))
.thenReturn(suggestions[0].wifiConfiguration);
List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
WifiConfiguration candidate = mNetworkSuggestionEvaluator.evaluateNetworks(
Arrays.asList(scanDetails), null, null, true, false,
(ScanDetail scanDetail, WifiConfiguration configuration, int score) -> {
connectableNetworks.add(Pair.create(scanDetail, configuration));
});
assertNotNull(candidate);
assertEquals(suggestionSsids[0] , candidate.SSID);
validateConnectableNetworks(connectableNetworks, new String[] {scanSsids[0]});
// check for any saved networks.
verify(mWifiConfigManager, times(scanSsids.length))
.wasEphemeralNetworkDeleted(anyString());
verify(mWifiConfigManager).getConfiguredNetwork(candidate.configKey());
// Verify we did not try to add any new networks or other interactions with
// WifiConfigManager.
verifyNoMoreInteractions(mWifiConfigManager);
}
/**
* Ensure that we don't select the only matching network suggestion if it was previously
* disabled by the user.
* Expected candidate: null
* Expected connectable Networks: {}
*/
@Test
public void testSelectNetworkSuggestionForOneMatchButUserForgotTheNetwork() {
String[] scanSsids = {"test1", "test2"};
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2470, 2437};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
int[] levels = {-67, -76};
String[] suggestionSsids = {"\"" + scanSsids[0] + "\""};
int[] securities = {SECURITY_PSK};
boolean[] appInteractions = {true};
boolean[] meteredness = {true};
int[] priorities = {-1};
int[] uids = {TEST_UID};
String[] packageNames = {TEST_PACKAGE};
ScanDetail[] scanDetails =
buildScanDetails(scanSsids, bssids, freqs, caps, levels, mClock);
WifiNetworkSuggestion[] suggestions = buildNetworkSuggestions(suggestionSsids, securities,
appInteractions, meteredness, priorities, uids, packageNames);
// Link the scan result with suggestions.
linkScanDetailsWithNetworkSuggestions(scanDetails, suggestions);
// setup config manager interactions.
setupAddToWifiConfigManager(suggestions[0].wifiConfiguration);
// Network was disabled by the user.
when(mWifiConfigManager.wasEphemeralNetworkDeleted(suggestionSsids[0])).thenReturn(true);
List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
WifiConfiguration candidate = mNetworkSuggestionEvaluator.evaluateNetworks(
Arrays.asList(scanDetails), null, null, true, false,
(ScanDetail scanDetail, WifiConfiguration configuration, int score) -> {
connectableNetworks.add(Pair.create(scanDetail, configuration));
});
assertNull(candidate);
assertTrue(connectableNetworks.isEmpty());
verify(mWifiConfigManager, times(scanSsids.length))
.wasEphemeralNetworkDeleted(anyString());
// Verify we did not try to add any new networks or other interactions with
// WifiConfigManager.
verifyNoMoreInteractions(mWifiConfigManager);
}
/**
* Ensure that we don't select the only matching network suggestion if the network configuration
* already exists (maybe saved or maybe it exists from a previous connection attempt) and
* blacklisted.
* Expected candidate: null
* Expected connectable Networks: {}
*/
@Test
public void testSelectNetworkSuggestionForOneMatchForExistingNetworkButTempDisabled() {
String[] scanSsids = {"test1", "test2"};
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2470, 2437};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
int[] levels = {-67, -76};
String[] suggestionSsids = {"\"" + scanSsids[0] + "\""};
int[] securities = {SECURITY_PSK};
boolean[] appInteractions = {true};
boolean[] meteredness = {true};
int[] priorities = {-1};
int[] uids = {TEST_UID};
String[] packageNames = {TEST_PACKAGE};
ScanDetail[] scanDetails =
buildScanDetails(scanSsids, bssids, freqs, caps, levels, mClock);
WifiNetworkSuggestion[] suggestions = buildNetworkSuggestions(suggestionSsids, securities,
appInteractions, meteredness, priorities, uids, packageNames);
// Link the scan result with suggestions.
linkScanDetailsWithNetworkSuggestions(scanDetails, suggestions);
// setup config manager interactions.
setupAddToWifiConfigManager(suggestions[0].wifiConfiguration);
// Mark the network disabled.
suggestions[0].wifiConfiguration.getNetworkSelectionStatus().setNetworkSelectionStatus(
NETWORK_SELECTION_TEMPORARY_DISABLED);
// Existing network matching the credentials.
when(mWifiConfigManager.getConfiguredNetwork(suggestions[0].wifiConfiguration.configKey()))
.thenReturn(suggestions[0].wifiConfiguration);
List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
WifiConfiguration candidate = mNetworkSuggestionEvaluator.evaluateNetworks(
Arrays.asList(scanDetails), null, null, true, false,
(ScanDetail scanDetail, WifiConfiguration configuration, int score) -> {
connectableNetworks.add(Pair.create(scanDetail, configuration));
});
assertNull(candidate);
assertTrue(connectableNetworks.isEmpty());
verify(mWifiConfigManager, times(scanSsids.length))
.wasEphemeralNetworkDeleted(anyString());
verify(mWifiConfigManager).getConfiguredNetwork(eq(
suggestions[0].wifiConfiguration.configKey()));
verify(mWifiConfigManager).tryEnableNetwork(eq(
suggestions[0].wifiConfiguration.networkId));
// Verify we did not try to add any new networks or other interactions with
// WifiConfigManager.
verifyNoMoreInteractions(mWifiConfigManager);
}
/**
* Ensure that we do select the only matching network suggestion if the network configuration
* already exists (maybe saved or maybe it exists from a previous connection attempt) and a
* temporary blacklist expired.
* Expected candidate: suggestionSsids[0]
* Expected connectable Networks: {suggestionSsids[0]}
*/
@Test
public void testSelectNetworkSuggestionForOneMatchForExistingNetworkButTempDisableExpired() {
String[] scanSsids = {"test1", "test2"};
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
int[] freqs = {2470, 2437};
String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
int[] levels = {-67, -76};
String[] suggestionSsids = {"\"" + scanSsids[0] + "\""};
int[] securities = {SECURITY_PSK};
boolean[] appInteractions = {true};
boolean[] meteredness = {true};
int[] priorities = {-1};
int[] uids = {TEST_UID};
String[] packageNames = {TEST_PACKAGE};
ScanDetail[] scanDetails =
buildScanDetails(scanSsids, bssids, freqs, caps, levels, mClock);
WifiNetworkSuggestion[] suggestions = buildNetworkSuggestions(suggestionSsids, securities,
appInteractions, meteredness, priorities, uids, packageNames);
// Link the scan result with suggestions.
linkScanDetailsWithNetworkSuggestions(scanDetails, suggestions);
// setup config manager interactions.
setupAddToWifiConfigManager(suggestions[0].wifiConfiguration);
// Mark the network disabled.
suggestions[0].wifiConfiguration.getNetworkSelectionStatus().setNetworkSelectionStatus(
NETWORK_SELECTION_TEMPORARY_DISABLED);
// Existing network matching the credentials.
when(mWifiConfigManager.getConfiguredNetwork(suggestions[0].wifiConfiguration.configKey()))
.thenReturn(suggestions[0].wifiConfiguration);
when(mWifiConfigManager.tryEnableNetwork(suggestions[0].wifiConfiguration.networkId))
.thenReturn(true);
List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks = new ArrayList<>();
WifiConfiguration candidate = mNetworkSuggestionEvaluator.evaluateNetworks(
Arrays.asList(scanDetails), null, null, true, false,
(ScanDetail scanDetail, WifiConfiguration configuration, int score) -> {
connectableNetworks.add(Pair.create(scanDetail, configuration));
});
assertNotNull(candidate);
assertEquals(suggestionSsids[0] , candidate.SSID);
validateConnectableNetworks(connectableNetworks, new String[] {scanSsids[0]});
verify(mWifiConfigManager, times(scanSsids.length))
.wasEphemeralNetworkDeleted(anyString());
verify(mWifiConfigManager).getConfiguredNetwork(eq(
suggestions[0].wifiConfiguration.configKey()));
verify(mWifiConfigManager).tryEnableNetwork(eq(
suggestions[0].wifiConfiguration.networkId));
// Verify we did not try to add any new networks or other interactions with
// WifiConfigManager.
verifyNoMoreInteractions(mWifiConfigManager);
}
private void setupAddToWifiConfigManager(WifiConfiguration...candidates) {
for (int i = 0; i < candidates.length; i++) {
WifiConfiguration candidate = candidates[i];
// setup & verify the WifiConfigmanager interactions for adding/enabling the network.
when(mWifiConfigManager.addOrUpdateNetwork(
argThat(new WifiConfigMatcher(candidate)), anyInt(), anyString()))
.thenReturn(new NetworkUpdateResult(TEST_NETWORK_ID + i));
when(mWifiConfigManager.updateNetworkSelectionStatus(eq(TEST_NETWORK_ID + i), anyInt()))
.thenReturn(true);
candidate.networkId = TEST_NETWORK_ID + i;
when(mWifiConfigManager.getConfiguredNetwork(TEST_NETWORK_ID + i))
.thenReturn(candidate);
}
}
class WifiConfigMatcher implements ArgumentMatcher<WifiConfiguration> {
private final WifiConfiguration mConfig;
WifiConfigMatcher(WifiConfiguration config) {
assertNotNull(config);
mConfig = config;
}
@Override
public boolean matches(WifiConfiguration otherConfig) {
if (otherConfig == null) return false;
return mConfig.configKey().equals(otherConfig.configKey());
}
}
private void verifyAddToWifiConfigManager(WifiConfiguration...candidates) {
// check for any saved networks.
verify(mWifiConfigManager, atLeast(candidates.length)).getConfiguredNetwork(anyString());
ArgumentCaptor<WifiConfiguration> wifiConfigurationCaptor =
ArgumentCaptor.forClass(WifiConfiguration.class);
verify(mWifiConfigManager, times(candidates.length)).addOrUpdateNetwork(
wifiConfigurationCaptor.capture(), anyInt(), anyString());
for (int i = 0; i < candidates.length; i++) {
WifiConfiguration addedWifiConfiguration = null;
for (WifiConfiguration configuration : wifiConfigurationCaptor.getAllValues()) {
if (configuration.SSID.equals(candidates[i].SSID)) {
addedWifiConfiguration = configuration;
break;
}
}
assertNotNull(addedWifiConfiguration);
assertTrue(addedWifiConfiguration.ephemeral);
assertTrue(addedWifiConfiguration.fromWifiNetworkSuggestion);
}
verify(mWifiConfigManager, times(candidates.length)).updateNetworkSelectionStatus(
anyInt(), anyInt());
verify(mWifiConfigManager, times(candidates.length)).getConfiguredNetwork(anyInt());
}
/**
* Build an array of scanDetails based on the caller supplied network SSID, BSSID,
* frequency, capability and RSSI level information.
*/
public static ScanDetail[] buildScanDetails(String[] ssids, String[] bssids, int[] freqs,
String[] caps, int[] levels, Clock clock) {
if (ssids == null || ssids.length == 0) return new ScanDetail[0];
ScanDetail[] scanDetails = new ScanDetail[ssids.length];
long timeStamp = clock.getElapsedSinceBootMillis();
for (int index = 0; index < ssids.length; index++) {
scanDetails[index] = new ScanDetail(WifiSsid.createFromAsciiEncoded(ssids[index]),
bssids[index], caps[index], levels[index], freqs[index], timeStamp, 0);
}
return scanDetails;
}
/**
* Generate an array of {@link android.net.wifi.WifiConfiguration} based on the caller
* supplied network SSID and security information.
*/
public static WifiConfiguration[] buildWifiConfigurations(String[] ssids, int[] securities) {
if (ssids == null || ssids.length == 0) return new WifiConfiguration[0];
WifiConfiguration[] configs = new WifiConfiguration[ssids.length];
for (int index = 0; index < ssids.length; index++) {
configs[index] = generateWifiConfig(-1, 0, ssids[index], false, true, null,
null, securities[index]);
}
return configs;
}
private WifiNetworkSuggestion[] buildNetworkSuggestions(
String[] ssids, int[] securities, boolean[] appInteractions, boolean[] meteredness,
int[] priorities, int[] uids, String[] packageNames) {
WifiConfiguration[] configs = buildWifiConfigurations(ssids, securities);
WifiNetworkSuggestion[] suggestions = new WifiNetworkSuggestion[configs.length];
for (int i = 0; i < configs.length; i++) {
configs[i].priority = priorities[i];
configs[i].meteredOverride = meteredness[i]
? WifiConfiguration.METERED_OVERRIDE_METERED
: WifiConfiguration.METERED_OVERRIDE_NONE;
suggestions[i] = new WifiNetworkSuggestion(configs[i], appInteractions[i],
false, uids[i], packageNames[i]);
}
return suggestions;
}
/**
* Link scan results to the network suggestions.
*
* The shorter of the 2 input params will be used to loop over so the inputs don't
* need to be of equal length.
* If there are more scan details than suggestions, the remaining
* scan details will be associated with a NULL suggestions.
* If there are more suggestions than scan details, the remaining
* suggestions will be associated with the last scan detail.
*/
private void linkScanDetailsWithNetworkSuggestions(
ScanDetail[] scanDetails, WifiNetworkSuggestion[] suggestions) {
if (suggestions == null || scanDetails == null) {
return;
}
int minLength = Math.min(scanDetails.length, suggestions.length);
// 1 to 1 mapping from scan detail to suggestion.
for (int i = 0; i < minLength; i++) {
ScanDetail scanDetail = scanDetails[i];
final WifiNetworkSuggestion matchingSuggestion = suggestions[i];
HashSet<WifiNetworkSuggestion> matchingSuggestions =
new HashSet<WifiNetworkSuggestion>() {{
add(matchingSuggestion);
}};
when(mWifiNetworkSuggestionsManager.getNetworkSuggestionsForScanDetail(eq(scanDetail)))
.thenReturn((matchingSuggestions));
}
if (scanDetails.length > suggestions.length) {
// No match for the remaining scan details.
for (int i = minLength; i < scanDetails.length; i++) {
ScanDetail scanDetail = scanDetails[i];
when(mWifiNetworkSuggestionsManager.getNetworkSuggestionsForScanDetail(
eq(scanDetail))).thenReturn(null);
}
} else if (suggestions.length > scanDetails.length) {
// All the additional suggestions match the last scan detail.
HashSet<WifiNetworkSuggestion> matchingSuggestions = new HashSet<>();
for (int i = minLength; i < suggestions.length; i++) {
matchingSuggestions.add(suggestions[i]);
}
ScanDetail lastScanDetail = scanDetails[minLength - 1];
when(mWifiNetworkSuggestionsManager.getNetworkSuggestionsForScanDetail(
eq(lastScanDetail))).thenReturn((matchingSuggestions));
}
}
private void validateConnectableNetworks(List<Pair<ScanDetail, WifiConfiguration>> actual,
String...expectedSsids) {
Set<String> expectedSsidSet = new HashSet<>(Arrays.asList(expectedSsids));
assertEquals(expectedSsidSet.size(), actual.size());
for (Pair<ScanDetail, WifiConfiguration> candidate : actual) {
// check if the scan detail matches the wificonfiguration.
assertEquals("\"" + candidate.first.getSSID() + "\"", candidate.second.SSID);
// check if both match one of the expected ssid's.
assertTrue(expectedSsidSet.remove(candidate.first.getSSID()));
}
assertTrue(expectedSsidSet.isEmpty());
}
}