1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.server.wifi;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertNull;
22 import static org.mockito.Mockito.anyInt;
23 import static org.mockito.Mockito.when;
24 
25 import android.app.test.MockAnswerUtil.AnswerWithArguments;
26 import android.content.pm.UserInfo;
27 import android.net.wifi.ScanResult;
28 import android.net.wifi.WifiConfiguration;
29 import android.os.UserHandle;
30 import android.os.UserManager;
31 import android.util.SparseArray;
32 
33 import androidx.test.filters.SmallTest;
34 
35 import org.junit.Before;
36 import org.junit.Test;
37 import org.mockito.Mock;
38 import org.mockito.MockitoAnnotations;
39 
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Collection;
43 import java.util.HashSet;
44 import java.util.List;
45 import java.util.Set;
46 
47 /**
48  * Unit tests for {@link com.android.server.wifi.ConfigurationMapTest}.
49  */
50 @SmallTest
51 public class ConfigurationMapTest {
52     private static final List<WifiConfiguration> CONFIGS = Arrays.asList(
53             WifiConfigurationTestUtil.generateWifiConfig(
54                     0, 1000000, "\"red\"", true, true, null, null),
55             WifiConfigurationTestUtil.generateWifiConfig(
56                     1, 1000001, "\"green\"", true, false, "example.com", "Green"),
57             WifiConfigurationTestUtil.generateWifiConfig(
58                     2, 1200000, "\"blue\"", false, true, null, null),
59             WifiConfigurationTestUtil.generateWifiConfig(
60                     3, 1100000, "\"cyan\"", true, true, null, null),
61             WifiConfigurationTestUtil.generateWifiConfig(
62                     4, 1100001, "\"yellow\"", true, true, "example.org", "Yellow"),
63             WifiConfigurationTestUtil.generateWifiConfig(
64                     5, 1100002, "\"magenta\"", false, false, null, null));
65 
66     private static final SparseArray<List<UserInfo>> USER_PROFILES = new SparseArray<>();
67     static {
USER_PROFILES.put(UserHandle.USER_SYSTEM, Arrays.asList( new UserInfo(UserHandle.USER_SYSTEM, "Owner", 0), new UserInfo(12, "Managed Profile", 0)))68         USER_PROFILES.put(UserHandle.USER_SYSTEM, Arrays.asList(
69                 new UserInfo(UserHandle.USER_SYSTEM, "Owner", 0),
70                 new UserInfo(12, "Managed Profile", 0)));
71         USER_PROFILES.put(10, Arrays.asList(new UserInfo(10, "Alice", 0)));
72         USER_PROFILES.put(11, Arrays.asList(new UserInfo(11, "Bob", 0)));
73     }
74 
75     @Mock UserManager mUserManager;
76 
77     private int mCurrentUserId = UserHandle.USER_SYSTEM;
78     private ConfigurationMap mConfigs;
79 
80     /**
81      * Sets up the test harness before running a test.
82      */
83     @Before
setUp()84     public void setUp() {
85         MockitoAnnotations.initMocks(this);
86 
87         when(mUserManager.getProfiles(anyInt()))
88                 .then(new AnswerWithArguments() {
89                     public List<UserInfo> answer(int userId) {
90                         return USER_PROFILES.get(userId);
91                     }
92                 });
93         mConfigs = new ConfigurationMap(mUserManager);
94     }
95 
switchUser(int newUserId)96     private void switchUser(int newUserId) {
97         mCurrentUserId = newUserId;
98         mConfigs.setNewUser(newUserId);
99         mConfigs.clear();
100     }
101 
getEnabledNetworksForCurrentUser()102     private Collection<WifiConfiguration> getEnabledNetworksForCurrentUser() {
103         List<WifiConfiguration> list = new ArrayList<>();
104         for (WifiConfiguration config : mConfigs.valuesForCurrentUser()) {
105             if (config.status != WifiConfiguration.Status.DISABLED) {
106                 list.add(config);
107             }
108         }
109         return list;
110     }
111 
getEphemeralForCurrentUser(String ssid)112     private WifiConfiguration getEphemeralForCurrentUser(String ssid) {
113         for (WifiConfiguration config : mConfigs.valuesForCurrentUser()) {
114             if (ssid.equals(config.SSID) && config.ephemeral) {
115                 return config;
116             }
117         }
118         return null;
119     }
120 
addNetworks(List<WifiConfiguration> configs)121     private void addNetworks(List<WifiConfiguration> configs) {
122         for (WifiConfiguration config : configs) {
123             assertNull(mConfigs.put(config));
124         }
125     }
126 
verifyGetters(List<WifiConfiguration> configs)127     private void verifyGetters(List<WifiConfiguration> configs) {
128         final Set<WifiConfiguration> configsForCurrentUser = new HashSet<>();
129         final Set<WifiConfiguration> enabledConfigsForCurrentUser = new HashSet<>();
130         final List<WifiConfiguration> configsNotForCurrentUser = new ArrayList<>();
131 
132         // Find out which network configurations should be / should not be visible to the current
133         // user. Also, check that *ForAllUsers() methods can be used to access all network
134         // configurations, irrespective of their visibility to the current user.
135         for (WifiConfiguration config : configs) {
136             if (WifiConfigurationUtil.isVisibleToAnyProfile(config,
137                     USER_PROFILES.get(mCurrentUserId))) {
138                 configsForCurrentUser.add(config);
139                 if (config.status != WifiConfiguration.Status.DISABLED) {
140                     enabledConfigsForCurrentUser.add(config);
141                 }
142             } else {
143                 configsNotForCurrentUser.add(config);
144             }
145 
146             assertEquals(config, mConfigs.getForAllUsers(config.networkId));
147         }
148 
149         // Verify that *ForCurrentUser() methods can be used to access network configurations
150         // visible to the current user.
151         for (WifiConfiguration config : configsForCurrentUser) {
152             assertEquals(config, mConfigs.getForCurrentUser(config.networkId));
153             assertEquals(config, mConfigs.getByConfigKeyForCurrentUser(config.configKey()));
154             final boolean wasEphemeral = config.ephemeral;
155             config.ephemeral = false;
156             assertNull(getEphemeralForCurrentUser(config.SSID));
157             config.ephemeral = true;
158             assertEquals(config, getEphemeralForCurrentUser(config.SSID));
159             config.ephemeral = wasEphemeral;
160         }
161 
162         // Verify that *ForCurrentUser() methods cannot be used to access network configurations not
163         // visible to the current user.
164         for (WifiConfiguration config : configsNotForCurrentUser) {
165             assertNull(mConfigs.getForCurrentUser(config.networkId));
166             assertNull(mConfigs.getByConfigKeyForCurrentUser(config.configKey()));
167             final boolean wasEphemeral = config.ephemeral;
168             config.ephemeral = false;
169             assertNull(getEphemeralForCurrentUser(config.SSID));
170             config.ephemeral = true;
171             assertNull(getEphemeralForCurrentUser(config.SSID));
172             config.ephemeral = wasEphemeral;
173         }
174 
175         // Verify that the methods which refer to more than one network configuration return the
176         // correct sets of networks.
177         assertEquals(configs.size(), mConfigs.sizeForAllUsers());
178         assertEquals(configsForCurrentUser.size(), mConfigs.sizeForCurrentUser());
179         assertEquals(enabledConfigsForCurrentUser,
180                 new HashSet<WifiConfiguration>(getEnabledNetworksForCurrentUser()));
181         assertEquals(new HashSet<>(configs),
182                 new HashSet<WifiConfiguration>(mConfigs.valuesForAllUsers()));
183     }
184 
createScanResultForNetwork(WifiConfiguration config)185     private ScanResult createScanResultForNetwork(WifiConfiguration config) {
186         return WifiConfigurationTestUtil.createScanDetailForNetwork(config, "", 0, 0, 0, 0)
187                 .getScanResult();
188     }
189 
190     /**
191      * Helper function to create a scan result matching the network and ensuring that
192      * {@link ConfigurationMap#getByScanResultForCurrentUser(ScanResult)} can match that network.
193      */
verifyScanResultMatchWithNetwork(WifiConfiguration config)194     private void verifyScanResultMatchWithNetwork(WifiConfiguration config) {
195         mConfigs.put(config);
196         ScanResult scanResult = createScanResultForNetwork(config);
197         WifiConfiguration retrievedConfig =
198                 mConfigs.getByScanResultForCurrentUser(scanResult);
199         assertNotNull(retrievedConfig);
200         assertEquals(config.configKey(), retrievedConfig.configKey());
201     }
202 
203     /**
204      * Verifies that all getters return the correct network configurations, taking into account the
205      * current user. Also verifies that handleUserSwitch() returns the list of network
206      * configurations that are no longer visible.
207      */
208     @Test
testGettersAndHandleUserSwitch()209     public void testGettersAndHandleUserSwitch() {
210         addNetworks(CONFIGS);
211         verifyGetters(CONFIGS);
212 
213         switchUser(10);
214         addNetworks(CONFIGS);
215         verifyGetters(CONFIGS);
216 
217         switchUser(11);
218         addNetworks(CONFIGS);
219         verifyGetters(CONFIGS);
220     }
221 
222     /**
223      * Verifies put(), remove() and clear().
224      */
225     @Test
testPutRemoveClear()226     public void testPutRemoveClear() {
227         final List<WifiConfiguration> configs = new ArrayList<>();
228         final WifiConfiguration config1 = CONFIGS.get(0);
229 
230         // Verify that there are no network configurations to start with.
231         switchUser(UserHandle.getUserId(config1.creatorUid));
232         verifyGetters(configs);
233 
234         // Add |config1|.
235         assertNull(mConfigs.put(config1));
236         // Verify that the getters return |config1|.
237         configs.add(config1);
238         verifyGetters(configs);
239 
240         // Overwrite |config1| with |config2|.
241         final WifiConfiguration config2 = CONFIGS.get(1);
242         config2.networkId = config1.networkId;
243         assertEquals(config1, mConfigs.put(config2));
244         // Verify that the getters return |config2| only.
245         configs.clear();
246         configs.add(config2);
247         verifyGetters(configs);
248 
249         // Add |config3|, which belongs to a managed profile of the current user.
250         final WifiConfiguration config3 = CONFIGS.get(2);
251         assertNull(mConfigs.put(config3));
252         // Verify that the getters return |config2| and |config3|.
253         configs.add(config3);
254         verifyGetters(configs);
255 
256         // Remove |config2|.
257         assertEquals(config2, mConfigs.remove(config2.networkId));
258         // Verify that the getters return |config3| only.
259         configs.remove(config2);
260         verifyGetters(configs);
261 
262         // Clear all network configurations.
263         mConfigs.clear();
264         // Verify that the getters do not return any network configurations.
265         configs.clear();
266         verifyGetters(configs);
267     }
268 
269     /**
270      * Verifies that {@link ConfigurationMap#getByScanResultForCurrentUser(ScanResult)} can
271      * positively match the corresponding networks.
272      */
273     @Test
testScanResultDoesMatchCorrespondingNetworks()274     public void testScanResultDoesMatchCorrespondingNetworks() {
275         verifyScanResultMatchWithNetwork(WifiConfigurationTestUtil.createOpenNetwork());
276         verifyScanResultMatchWithNetwork(WifiConfigurationTestUtil.createPskNetwork());
277         verifyScanResultMatchWithNetwork(WifiConfigurationTestUtil.createWepNetwork());
278         verifyScanResultMatchWithNetwork(WifiConfigurationTestUtil.createEapNetwork());
279     }
280 
281     /**
282      * Verifies that {@link ConfigurationMap#getByScanResultForCurrentUser(ScanResult)} does not
283      * match other networks.
284      */
285     @Test
testScanResultDoesNotMatchWithOtherNetworks()286     public void testScanResultDoesNotMatchWithOtherNetworks() {
287         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
288         ScanResult scanResult = createScanResultForNetwork(config);
289         // Change the network security type and the old scan result should not match now.
290         config.allowedKeyManagement.clear();
291         config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
292         mConfigs.put(config);
293         assertNull(mConfigs.getByScanResultForCurrentUser(scanResult));
294     }
295 
296     /**
297      * Verifies that {@link ConfigurationMap#getByScanResultForCurrentUser(ScanResult)} does not
298      * match networks which have been removed.
299      */
300     @Test
testScanResultDoesNotMatchAfterNetworkRemove()301     public void testScanResultDoesNotMatchAfterNetworkRemove() {
302         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
303         ScanResult scanResult = createScanResultForNetwork(config);
304         config.networkId = 5;
305         mConfigs.put(config);
306         // Create another network in the map.
307         mConfigs.put(WifiConfigurationTestUtil.createPskNetwork());
308         assertNotNull(mConfigs.getByScanResultForCurrentUser(scanResult));
309 
310         mConfigs.remove(config.networkId);
311         assertNull(mConfigs.getByScanResultForCurrentUser(scanResult));
312     }
313 
314     /**
315      * Verifies that {@link ConfigurationMap#getByScanResultForCurrentUser(ScanResult)} does not
316      * match networks after clear.
317      */
318     @Test
testScanResultDoesNotMatchAfterClear()319     public void testScanResultDoesNotMatchAfterClear() {
320         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
321         ScanResult scanResult = createScanResultForNetwork(config);
322         config.networkId = 5;
323         mConfigs.put(config);
324         // Create another network in the map.
325         mConfigs.put(WifiConfigurationTestUtil.createPskNetwork());
326         assertNotNull(mConfigs.getByScanResultForCurrentUser(scanResult));
327 
328         mConfigs.clear();
329         assertNull(mConfigs.getByScanResultForCurrentUser(scanResult));
330     }
331 }
332