blob: 447cdc2d8f67cbb343fe99399da04b647697b5d1 [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 org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.validateMockitoUsage;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiEnterpriseConfig;
import android.os.Process;
import android.telephony.TelephonyManager;
import android.util.LocalLog;
import androidx.test.filters.SmallTest;
import com.android.server.wifi.util.ScanResultUtil;
import com.android.server.wifi.util.TelephonyUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Unit tests for CarrierNeteworkEvaluator
*/
@SmallTest
public class CarrierNetworkEvaluatorTest extends WifiBaseTest {
private static final String CARRIER1_SSID = "\"carrier1\"";
private static final String CARRIER2_SSID = "\"carrier2\"";
private static final String CARRIER_SAVED_SSID = "\"carrier3-saved\"";
private static final String CARRIER_SAVED_EPH_SSID = "\"carrier4-saved-ephemeral\"";
private static final String NON_CARRIER_SSID = "\"non-carrier\"";
private static final String TEST_MCC_MNC = "123456";
private static final int CARRIER1_NET_ID = 1;
private static final int CARRIER2_NET_ID = 2;
private static final int CARRIER_SAVED_NET_ID = 3;
private static final int CARRIER_SAVED_EPH_NET_ID = 4;
private static final int NON_CARRIER_NET_ID = 5;
private CarrierNetworkEvaluator mDut;
@Mock private WifiConfigManager mWifiConfigManager;
@Mock private CarrierNetworkConfig mCarrierNetworkConfig;
@Mock private LocalLog mLocalLog;
@Mock private Clock mClock;
@Mock private WifiNetworkSelector.NetworkEvaluator.OnConnectableListener mConnectableListener;
@Mock private WifiInjector mWifiInjector;
@Mock private TelephonyManager mTelephonyManager;
@Mock private TelephonyManager mDataTelephonyManager;
private ArgumentCaptor<ScanDetail> mScanDetailCaptor = ArgumentCaptor.forClass(
ScanDetail.class);
private ArgumentCaptor<WifiConfiguration> mWifiConfigCaptor = ArgumentCaptor.forClass(
WifiConfiguration.class);
private class GetConfiguredNetworkForScanDetailsAnswer implements Answer<WifiConfiguration> {
private Map<String, WifiConfiguration> mConfig = new HashMap<>();
public void addConfig(ScanDetail scanDetail, WifiConfiguration config) {
mConfig.put(scanDetail.toKeyString(), config);
}
@Override
public WifiConfiguration answer(InvocationOnMock invocation) throws Throwable {
ScanDetail scanDetail = invocation.getArgument(0);
return mConfig.get(scanDetail.toKeyString());
}
}
private GetConfiguredNetworkForScanDetailsAnswer mGetConfiguredNetworkForScanDetailsAnswer;
private class AddOrUpdateNetworkAnswer implements Answer<NetworkUpdateResult> {
private Map<String, Integer> mConfigs = new HashMap<>();
public void addConfig(WifiConfiguration config, int networkId) {
mConfigs.put(config.getKey(), networkId);
}
@Override
public NetworkUpdateResult answer(InvocationOnMock invocation) throws Throwable {
WifiConfiguration config = invocation.getArgument(0);
Integer networkId = mConfigs.get(config.getKey());
if (networkId == null) return null;
when(mWifiConfigManager.getConfiguredNetwork(networkId)).thenReturn(config);
NetworkUpdateResult networkUpdateResult = mock(NetworkUpdateResult.class);
when(networkUpdateResult.isSuccess()).thenReturn(true);
when(networkUpdateResult.getNetworkId()).thenReturn(networkId);
return networkUpdateResult;
}
}
private AddOrUpdateNetworkAnswer mAddOrUpdateNetworkAnswer;
private WifiConfiguration configureNewSsid(int networkId, ScanDetail scanDetail,
boolean isEphemeral, boolean isSaved) {
WifiConfiguration newConfig = ScanResultUtil.createNetworkFromScanResult(
scanDetail.getScanResult());
assertTrue("" + newConfig, WifiConfigurationUtil.validate(newConfig, true));
assertEquals(ScanResultMatchInfo.fromScanResult(scanDetail.getScanResult()),
ScanResultMatchInfo.fromWifiConfiguration(newConfig));
newConfig.ephemeral = isEphemeral;
if (isSaved) {
mGetConfiguredNetworkForScanDetailsAnswer.addConfig(scanDetail, newConfig);
}
when(mWifiConfigManager.enableNetwork(
networkId, false, Process.WIFI_UID, null)).thenReturn(true);
when(mWifiConfigManager.setNetworkCandidateScanResult(eq(networkId), any(),
anyInt())).thenReturn(true);
when(mWifiConfigManager.getConfiguredNetwork(networkId)).thenReturn(newConfig);
mAddOrUpdateNetworkAnswer.addConfig(newConfig, networkId);
return newConfig;
}
/** Sets up test. */
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mDut = new CarrierNetworkEvaluator(mWifiConfigManager, mCarrierNetworkConfig, mLocalLog,
mWifiInjector);
when(mWifiInjector.makeTelephonyManager()).thenReturn(mTelephonyManager);
when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mDataTelephonyManager);
when(mDataTelephonyManager.getSimOperator()).thenReturn(TEST_MCC_MNC);
when(mDataTelephonyManager.getSimState()).thenReturn(TelephonyManager.SIM_STATE_READY);
when(mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()).thenReturn(true);
when(mCarrierNetworkConfig.isCarrierNetwork(eq(CARRIER1_SSID.replace("\"", ""))))
.thenReturn(true);
when(mCarrierNetworkConfig.isCarrierNetwork(eq(CARRIER2_SSID.replace("\"", ""))))
.thenReturn(true);
when(mCarrierNetworkConfig.isCarrierNetwork(eq(CARRIER_SAVED_SSID.replace("\"", ""))))
.thenReturn(true);
when(mCarrierNetworkConfig.isCarrierNetwork(eq(CARRIER_SAVED_EPH_SSID.replace("\"", ""))))
.thenReturn(true);
when(mCarrierNetworkConfig.getNetworkEapType(eq(CARRIER1_SSID.replace("\"", ""))))
.thenReturn(WifiEnterpriseConfig.Eap.AKA);
when(mCarrierNetworkConfig.getNetworkEapType(eq(CARRIER2_SSID.replace("\"", ""))))
.thenReturn(WifiEnterpriseConfig.Eap.AKA_PRIME);
when(mCarrierNetworkConfig.getNetworkEapType(eq(CARRIER_SAVED_SSID.replace("\"", ""))))
.thenReturn(WifiEnterpriseConfig.Eap.SIM);
when(mCarrierNetworkConfig.getNetworkEapType(eq(CARRIER_SAVED_EPH_SSID.replace("\"", ""))))
.thenReturn(WifiEnterpriseConfig.Eap.AKA);
mAddOrUpdateNetworkAnswer = new AddOrUpdateNetworkAnswer();
when(mWifiConfigManager.addOrUpdateNetwork(any(), eq(Process.WIFI_UID))).thenAnswer(
mAddOrUpdateNetworkAnswer);
mGetConfiguredNetworkForScanDetailsAnswer = new GetConfiguredNetworkForScanDetailsAnswer();
when(mWifiConfigManager.getConfiguredNetworkForScanDetail(any())).thenAnswer(
mGetConfiguredNetworkForScanDetailsAnswer);
}
/** Cleans up test. */
@After
public void cleanup() {
validateMockitoUsage();
}
/**
* Baseline positive test case: carrier Wi-Fi enabled (have cert), present >1 Carrier networks
* of varying RSSI, include some none carrier networks with even better RSSI and some saved
* carrier networks (one of which is ephemeral).
*
* Desired behavior:
* - all Carrier Wi-Fi (including all saved networks) as connectable
* - best Carrier Wi-Fi (highest RSSI) as return value
*/
@Test
public void testSelectOneFromMultiple() {
String[] ssids = {CARRIER1_SSID, CARRIER2_SSID, CARRIER_SAVED_SSID, CARRIER_SAVED_EPH_SSID,
NON_CARRIER_SSID};
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "6c:f3:7f:ae:8c:f5",
"6c:f3:7f:ae:8c:f6", "6c:f3:7f:ae:8c:f7"};
int[] freqs = {2470, 2437, 2470, 2470, 2470};
String[] caps = {"[WPA2-EAP-CCMP]", "[WPA2-EAP-CCMP]", "[WPA2-EAP-CCMP]",
"[WPA2-EAP-CCMP]", "[]"};
int[] levels = {10, 20, 11, 15, 50};
List<ScanDetail> scanDetails = WifiNetworkSelectorTestUtil.buildScanDetails(ssids, bssids,
freqs, caps, levels, mClock);
configureNewSsid(CARRIER1_NET_ID, scanDetails.get(0), true, false);
configureNewSsid(CARRIER2_NET_ID, scanDetails.get(1), true, false);
configureNewSsid(CARRIER_SAVED_NET_ID, scanDetails.get(2), false, true);
configureNewSsid(CARRIER_SAVED_EPH_NET_ID, scanDetails.get(3), true, false);
configureNewSsid(NON_CARRIER_NET_ID, scanDetails.get(4), false, true);
WifiConfiguration selected = mDut.evaluateNetworks(scanDetails, null, null, false, false,
mConnectableListener);
verify(mConnectableListener, times(4)).onConnectable(mScanDetailCaptor.capture(),
mWifiConfigCaptor.capture(), anyInt());
assertEquals(4, mScanDetailCaptor.getAllValues().size());
assertEquals(CARRIER1_SSID.replace("\"", ""),
mScanDetailCaptor.getAllValues().get(0).getSSID());
assertEquals(CARRIER2_SSID.replace("\"", ""),
mScanDetailCaptor.getAllValues().get(1).getSSID());
assertEquals(CARRIER_SAVED_SSID.replace("\"", ""),
mScanDetailCaptor.getAllValues().get(2).getSSID());
assertEquals(CARRIER_SAVED_EPH_SSID.replace("\"", ""),
mScanDetailCaptor.getAllValues().get(3).getSSID());
assertEquals(4, mWifiConfigCaptor.getAllValues().size());
WifiConfiguration config1 = mWifiConfigCaptor.getAllValues().get(0);
assertEquals(CARRIER1_SSID, config1.SSID);
assertTrue(config1.isEphemeral());
assertTrue(config1.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP));
WifiConfiguration config2 = mWifiConfigCaptor.getAllValues().get(1);
assertEquals(CARRIER2_SSID, config2.SSID);
assertTrue(config2.isEphemeral());
assertTrue(config2.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP));
WifiConfiguration config3 = mWifiConfigCaptor.getAllValues().get(2);
assertEquals(CARRIER_SAVED_SSID, config3.SSID);
// all configs returned by CarrierNetworkEvaluator are ephemeral.
assertTrue(config3.isEphemeral());
assertTrue(config3.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP));
WifiConfiguration config4 = mWifiConfigCaptor.getAllValues().get(3);
assertEquals(CARRIER_SAVED_EPH_SSID, config4.SSID);
assertTrue(config4.isEphemeral());
assertTrue(config4.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP));
assertEquals(config2.getKey(), selected.getKey()); // SSID2 has the highest RSSI
assertEquals("", selected.enterpriseConfig.getAnonymousIdentity());
assertTrue(TelephonyUtil.isSimEapMethod(selected.enterpriseConfig.getEapMethod()));
}
/**
* Cert installed and no Carrier Wi-Fi visible
*
* Desired behavior: no networks connectable or selected
*/
@Test
public void testSelectFromNoneAvailable() {
String[] ssids = {NON_CARRIER_SSID};
String[] bssids = {"6c:f3:7f:ae:8c:f6"};
int[] freqs = {2470};
String[] caps = {"[]"};
int[] levels = {40};
List<ScanDetail> scanDetails = WifiNetworkSelectorTestUtil.buildScanDetails(ssids, bssids,
freqs, caps, levels, mClock);
configureNewSsid(NON_CARRIER_NET_ID, scanDetails.get(0), false, true);
WifiConfiguration selected = mDut.evaluateNetworks(scanDetails, null, null, false, false,
mConnectableListener);
verify(mConnectableListener, never()).onConnectable(any(), any(), anyInt());
assertNull(selected);
}
/**
* Multiple carrier Wi-Fi networks visible but no cert installed.
*
* Desired behavior: no networks connectable or selected
*/
@Test
public void testNoCarrierCert() {
String[] ssids = {CARRIER1_SSID, CARRIER2_SSID, CARRIER_SAVED_SSID, CARRIER_SAVED_EPH_SSID,
NON_CARRIER_SSID};
String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "6c:f3:7f:ae:8c:f5",
"6c:f3:7f:ae:8c:f6", "6c:f3:7f:ae:8c:f7"};
int[] freqs = {2470, 2437, 2470, 2470, 2470};
String[] caps = {"[WPA2-EAP-CCMP]", "[WPA2-EAP-CCMP]", "[WPA2-EAP-CCMP]",
"[WPA2-EAP-CCMP]", "[]"};
int[] levels = {10, 20, 30, 40, 50};
when(mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()).thenReturn(false);
List<ScanDetail> scanDetails = WifiNetworkSelectorTestUtil.buildScanDetails(ssids, bssids,
freqs, caps, levels, mClock);
configureNewSsid(CARRIER1_NET_ID, scanDetails.get(0), true, false);
configureNewSsid(CARRIER2_NET_ID, scanDetails.get(1), true, false);
configureNewSsid(CARRIER_SAVED_NET_ID, scanDetails.get(2), false, true);
configureNewSsid(CARRIER_SAVED_EPH_NET_ID, scanDetails.get(3), true, false);
configureNewSsid(NON_CARRIER_NET_ID, scanDetails.get(4), false, true);
WifiConfiguration selected = mDut.evaluateNetworks(scanDetails, null, null, false, false,
mConnectableListener);
verify(mConnectableListener, never()).onConnectable(any(), any(), anyInt());
assertNull(selected);
}
/**
* One carrier Wi-Fi networks visible and cert installed but user has previously forgotten the
* network.
*
* Desired behavior: no networks connectable or selected
*/
@Test
public void testAvailableButPreviouslyUserDeleted() {
String[] ssids = {CARRIER1_SSID};
String[] bssids = {"6c:f3:7f:ae:8c:f3"};
int[] freqs = {2470};
String[] caps = {"[WPA2-EAP-CCMP]"};
int[] levels = {10};
when(mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()).thenReturn(true);
when(mWifiConfigManager.wasEphemeralNetworkDeleted(CARRIER1_SSID))
.thenReturn(true);
List<ScanDetail> scanDetails = WifiNetworkSelectorTestUtil.buildScanDetails(ssids, bssids,
freqs, caps, levels, mClock);
configureNewSsid(CARRIER1_NET_ID, scanDetails.get(0), true, false);
WifiConfiguration selected = mDut.evaluateNetworks(scanDetails, null, null, false, false,
mConnectableListener);
verify(mConnectableListener, never()).onConnectable(any(), any(), anyInt());
assertNull(selected);
}
/**
* One carrier Wi-Fi networks visible and cert installed but ssid is blacklisted.
*
* Desired behavior: no networks connectable or selected
*/
@Test
public void testAvailableButBlacklisted() {
String[] ssids = {CARRIER1_SSID};
String[] bssids = {"6c:f3:7f:ae:8c:f3"};
int[] freqs = {2470};
String[] caps = {"[WPA2-EAP-CCMP]"};
int[] levels = {10};
when(mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()).thenReturn(true);
List<ScanDetail> scanDetails = WifiNetworkSelectorTestUtil.buildScanDetails(ssids, bssids,
freqs, caps, levels, mClock);
WifiConfiguration blacklisted =
configureNewSsid(CARRIER1_NET_ID, scanDetails.get(0), true, false);
blacklisted.getNetworkSelectionStatus()
.setNetworkSelectionStatus(
WifiConfiguration.NetworkSelectionStatus
.NETWORK_SELECTION_PERMANENTLY_DISABLED);
when(mWifiConfigManager.getConfiguredNetwork(eq(blacklisted.getKey())))
.thenReturn(blacklisted);
when(mWifiConfigManager.tryEnableNetwork(CARRIER1_NET_ID))
.thenReturn(false);
WifiConfiguration selected = mDut.evaluateNetworks(scanDetails, null, null, false, false,
mConnectableListener);
verify(mWifiConfigManager).getConfiguredNetwork(eq(blacklisted.getKey()));
verify(mConnectableListener, never()).onConnectable(any(), any(), anyInt());
assertNull(selected);
}
/**
* One carrier Wi-Fi network that is visible and supports encrypted IMSI.
*
* Desired behavior: selected network supports encrypted IMSI by using EAP-SIM/AKA/AKA'
* and has an empty anonymous identity. The anonymous identity will be populated with
* {@code anonymous@<realm>} by ClientModeImpl's handling of the
* {@link ClientModeImpl#CMD_START_CONNECT} event.
*/
@Test
public void testSupportsEncryptedImsi() {
String[] ssids = {CARRIER1_SSID};
String[] bssids = {"6c:f3:7f:ae:8c:f3"};
int[] freqs = {2470};
String[] caps = {"[WPA2-EAP-CCMP]"};
int[] levels = {10};
when(mCarrierNetworkConfig.isCarrierEncryptionInfoAvailable()).thenReturn(true);
List<ScanDetail> scanDetails = WifiNetworkSelectorTestUtil.buildScanDetails(ssids, bssids,
freqs, caps, levels, mClock);
WifiConfiguration carrierConfig = configureNewSsid(CARRIER1_NET_ID, scanDetails.get(0),
true, false);
WifiConfiguration selected = mDut.evaluateNetworks(scanDetails, null, null, false, false,
mConnectableListener);
assertEquals(carrierConfig.getKey(), selected.getKey());
assertEquals("", selected.enterpriseConfig.getAnonymousIdentity());
assertTrue(TelephonyUtil.isSimEapMethod(selected.enterpriseConfig.getEapMethod()));
}
}