WifiConfigManagerTest.java revision c485ebf64d1049d17db8108b85653f53fcdc8949
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
17package com.android.server.wifi;
18
19import static org.hamcrest.CoreMatchers.not;
20import static org.junit.Assert.assertEquals;
21import static org.junit.Assert.assertFalse;
22import static org.junit.Assert.assertNotNull;
23import static org.junit.Assert.assertNull;
24import static org.junit.Assert.assertTrue;
25import static org.junit.Assert.fail;
26import static org.mockito.Mockito.anyInt;
27import static org.mockito.Mockito.anyObject;
28import static org.mockito.Mockito.anyString;
29import static org.mockito.Mockito.doAnswer;
30import static org.mockito.Mockito.eq;
31import static org.mockito.Mockito.intThat;
32import static org.mockito.Mockito.mock;
33import static org.mockito.Mockito.never;
34import static org.mockito.Mockito.reset;
35import static org.mockito.Mockito.verify;
36import static org.mockito.Mockito.when;
37
38import android.content.Context;
39import android.content.pm.UserInfo;
40import android.net.wifi.FakeKeys;
41import android.net.wifi.WifiConfiguration;
42import android.net.wifi.WifiConfiguration.KeyMgmt;
43import android.net.wifi.WifiEnterpriseConfig;
44import android.net.wifi.WifiEnterpriseConfig.Eap;
45import android.net.wifi.WifiEnterpriseConfig.Phase2;
46import android.os.Process;
47import android.os.UserHandle;
48import android.os.UserManager;
49import android.security.Credentials;
50import android.support.test.InstrumentationRegistry;
51import android.test.suitebuilder.annotation.SmallTest;
52import android.text.TextUtils;
53import android.util.Log;
54import android.util.SparseArray;
55
56import com.android.server.net.DelayedDiskWrite;
57import com.android.server.wifi.MockAnswerUtil.AnswerWithArguments;
58import com.android.server.wifi.hotspot2.omadm.PasspointManagementObjectManager;
59import com.android.server.wifi.hotspot2.pps.Credential;
60import com.android.server.wifi.hotspot2.pps.HomeSP;
61
62import org.junit.Before;
63import org.junit.Test;
64import org.mockito.Mock;
65import org.mockito.MockitoAnnotations;
66
67import java.io.ByteArrayInputStream;
68import java.io.ByteArrayOutputStream;
69import java.io.DataInputStream;
70import java.io.DataOutputStream;
71import java.io.EOFException;
72import java.io.File;
73import java.io.FileOutputStream;
74import java.io.IOException;
75import java.lang.reflect.Field;
76import java.math.BigInteger;
77import java.security.cert.CertificateEncodingException;
78import java.security.cert.X509Certificate;
79import java.util.ArrayDeque;
80import java.util.ArrayList;
81import java.util.Arrays;
82import java.util.BitSet;
83import java.util.Collection;
84import java.util.Collections;
85import java.util.HashMap;
86import java.util.HashSet;
87import java.util.List;
88import java.util.Map;
89import java.util.Random;
90import java.util.Set;
91import java.util.TreeMap;
92
93/**
94 * Unit tests for {@link com.android.server.wifi.WifiConfigManager}.
95 */
96@SmallTest
97public class WifiConfigManagerTest {
98    private static final List<WifiConfiguration> CONFIGS = Arrays.asList(
99            WifiConfigurationTestUtil.generateWifiConfig(
100                    0, 1000000, "\"red\"", true, true, null, null),
101            WifiConfigurationTestUtil.generateWifiConfig(
102                    1, 1000001, "\"green\"", true, true, "example.com", "Green"),
103            WifiConfigurationTestUtil.generateWifiConfig(
104                    2, 1100000, "\"blue\"", false, true, "example.org", "Blue"),
105            WifiConfigurationTestUtil.generateWifiConfig(
106                    3, 1200000, "\"cyan\"", false, true, null, null));
107
108    private static final int[] USER_IDS = {0, 10, 11};
109    private static final int MANAGED_PROFILE_USER_ID = 12;
110    private static final int MANAGED_PROFILE_PARENT_USER_ID = 0;
111    private static final SparseArray<List<UserInfo>> USER_PROFILES = new SparseArray<>();
112    static {
113        USER_PROFILES.put(0, Arrays.asList(new UserInfo(0, "Owner", 0),
114                new UserInfo(12, "Managed Profile", 0)));
115        USER_PROFILES.put(10, Arrays.asList(new UserInfo(10, "Alice", 0)));
116        USER_PROFILES.put(11, Arrays.asList(new UserInfo(11, "Bob", 0)));
117    }
118
119    private static final Map<Integer, List<WifiConfiguration>> VISIBLE_CONFIGS = new HashMap<>();
120    static {
121        for (int userId : USER_IDS) {
122            List<WifiConfiguration> configs = new ArrayList<>();
123            for (int i = 0; i < CONFIGS.size(); ++i) {
124                if (WifiConfigurationUtil.isVisibleToAnyProfile(CONFIGS.get(i),
125                        USER_PROFILES.get(userId))) {
126                    configs.add(CONFIGS.get(i));
127                }
128            }
129            VISIBLE_CONFIGS.put(userId, configs);
130        }
131    }
132
133    public static final String TAG = "WifiConfigManagerTest";
134    @Mock private Context mContext;
135    @Mock private WifiStateMachine mWifiStateMachine;
136    @Mock private WifiNative mWifiNative;
137    @Mock private FrameworkFacade mFrameworkFacade;
138    @Mock private UserManager mUserManager;
139    @Mock private DelayedDiskWrite mWriter;
140    @Mock private PasspointManagementObjectManager mMOManager;
141    @Mock private Clock mClock;
142    private WifiConfigManager mWifiConfigManager;
143    private ConfigurationMap mConfiguredNetworks;
144    public byte[] mNetworkHistoryBytes;
145    private MockKeyStore mMockKeyStore;
146
147    /**
148     * Called before each test
149     */
150    @Before
151    public void setUp() throws Exception {
152        MockitoAnnotations.initMocks(this);
153
154        final Context realContext = InstrumentationRegistry.getContext();
155        when(mContext.getPackageName()).thenReturn(realContext.getPackageName());
156        when(mContext.getResources()).thenReturn(realContext.getResources());
157        when(mContext.getPackageManager()).thenReturn(realContext.getPackageManager());
158
159        when(mWifiStateMachine.getCurrentUserId()).thenReturn(UserHandle.USER_SYSTEM);
160        when(mWifiStateMachine.getCurrentUserProfiles())
161                .thenReturn(USER_PROFILES.get(UserHandle.USER_SYSTEM));
162
163        for (int userId : USER_IDS) {
164            when(mUserManager.getProfiles(userId)).thenReturn(USER_PROFILES.get(userId));
165        }
166
167        mWifiConfigManager = new WifiConfigManager(mContext, mWifiStateMachine, mWifiNative,
168                mFrameworkFacade, mClock, mUserManager);
169
170        final Field configuredNetworksField =
171                WifiConfigManager.class.getDeclaredField("mConfiguredNetworks");
172        configuredNetworksField.setAccessible(true);
173        mConfiguredNetworks = (ConfigurationMap) configuredNetworksField.get(mWifiConfigManager);
174
175        // Intercept writes to networkHistory.txt.
176        doAnswer(new AnswerWithArguments() {
177            public void answer(String filePath, DelayedDiskWrite.Writer writer) throws Exception {
178                final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
179                final DataOutputStream stream = new DataOutputStream(buffer);
180                writer.onWriteCalled(stream);
181                stream.close();
182                mNetworkHistoryBytes = buffer.toByteArray();
183            }}).when(mWriter).write(anyString(), (DelayedDiskWrite.Writer) anyObject());
184        final Field writerField = WifiConfigManager.class.getDeclaredField("mWriter");
185        writerField.setAccessible(true);
186        writerField.set(mWifiConfigManager, mWriter);
187        final Field networkHistoryField =
188                WifiConfigManager.class.getDeclaredField("mWifiNetworkHistory");
189        networkHistoryField.setAccessible(true);
190        WifiNetworkHistory wifiNetworkHistory =
191                (WifiNetworkHistory) networkHistoryField.get(mWifiConfigManager);
192        final Field networkHistoryWriterField =
193                WifiNetworkHistory.class.getDeclaredField("mWriter");
194        networkHistoryWriterField.setAccessible(true);
195        networkHistoryWriterField.set(wifiNetworkHistory, mWriter);
196
197        when(mMOManager.isEnabled()).thenReturn(true);
198        final Field moManagerField = WifiConfigManager.class.getDeclaredField("mMOManager");
199        moManagerField.setAccessible(true);
200        moManagerField.set(mWifiConfigManager, mMOManager);
201
202        mMockKeyStore = new MockKeyStore();
203        final Field mKeyStoreField = WifiConfigManager.class.getDeclaredField("mKeyStore");
204        mKeyStoreField.setAccessible(true);
205        mKeyStoreField.set(mWifiConfigManager, mMockKeyStore.createMock());
206    }
207
208    private void switchUser(int newUserId) {
209        when(mWifiStateMachine.getCurrentUserId()).thenReturn(newUserId);
210        when(mWifiStateMachine.getCurrentUserProfiles())
211                .thenReturn(USER_PROFILES.get(newUserId));
212        mWifiConfigManager.handleUserSwitch();
213    }
214
215    private void switchUserToCreatorOrParentOf(WifiConfiguration config) {
216        final int creatorUserId = UserHandle.getUserId(config.creatorUid);
217        if (creatorUserId == MANAGED_PROFILE_USER_ID) {
218            switchUser(MANAGED_PROFILE_PARENT_USER_ID);
219        } else {
220            switchUser(creatorUserId);
221        }
222    }
223
224    private void addNetworks() throws Exception {
225        final int originalUserId = mWifiStateMachine.getCurrentUserId();
226
227        when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString())).thenReturn(true);
228        when(mWifiNative.setNetworkExtra(anyInt(), anyString(), (Map<String, String>) anyObject()))
229                .thenReturn(true);
230        for (int i = 0; i < CONFIGS.size(); ++i) {
231            assertEquals(i, CONFIGS.get(i).networkId);
232            switchUserToCreatorOrParentOf(CONFIGS.get(i));
233            final WifiConfiguration config = new WifiConfiguration(CONFIGS.get(i));
234            config.networkId = -1;
235            when(mWifiNative.addNetwork()).thenReturn(i);
236            when(mWifiNative.getNetworkVariable(i, WifiConfiguration.ssidVarName))
237                .thenReturn(encodeConfigSSID(CONFIGS.get(i)));
238            mWifiConfigManager.saveNetwork(config, config.creatorUid);
239        }
240
241        switchUser(originalUserId);
242    }
243
244    private String encodeConfigSSID(WifiConfiguration config) throws Exception {
245        return new BigInteger(1, config.SSID.substring(1, config.SSID.length() - 1)
246                .getBytes("UTF-8")).toString(16);
247    }
248
249    private WifiNative createNewWifiNativeMock() throws Exception {
250        final WifiNative wifiNative = mock(WifiNative.class);
251        final Field wifiNativeField = WifiConfigManager.class.getDeclaredField("mWifiNative");
252        wifiNativeField.setAccessible(true);
253        wifiNativeField.set(mWifiConfigManager, wifiNative);
254        return wifiNative;
255    }
256
257    /**
258     * Verifies that getConfiguredNetworksSize() returns the number of network configurations
259     * visible to the current user.
260     */
261    @Test
262    public void testGetConfiguredNetworksSize() throws Exception {
263        addNetworks();
264        for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
265            switchUser(entry.getKey());
266            assertEquals(entry.getValue().size(), mWifiConfigManager.getConfiguredNetworksSize());
267        }
268    }
269
270    private void verifyNetworkConfig(WifiConfiguration expectedConfig,
271            WifiConfiguration actualConfig) {
272        assertNotNull(actualConfig);
273        assertEquals(expectedConfig.SSID, actualConfig.SSID);
274        assertEquals(expectedConfig.FQDN, actualConfig.FQDN);
275        assertEquals(expectedConfig.providerFriendlyName,
276                actualConfig.providerFriendlyName);
277        assertEquals(expectedConfig.configKey(), actualConfig.configKey(false));
278    }
279
280    private void verifyNetworkConfigs(Collection<WifiConfiguration> expectedConfigs,
281            Collection<WifiConfiguration> actualConfigs) {
282        assertEquals(expectedConfigs.size(), actualConfigs.size());
283        for (WifiConfiguration expectedConfig : expectedConfigs) {
284            WifiConfiguration actualConfig = null;
285            // Find the network configuration to test (assume that |actualConfigs| contains them in
286            // undefined order).
287            for (final WifiConfiguration candidate : actualConfigs) {
288                if (candidate.networkId == expectedConfig.networkId) {
289                    actualConfig = candidate;
290                    break;
291                }
292            }
293            verifyNetworkConfig(expectedConfig, actualConfig);
294        }
295    }
296
297    /**
298     * Verifies that getConfiguredNetworksSize() returns the network configurations visible to the
299     * current user.
300     */
301    @Test
302    public void testGetConfiguredNetworks() throws Exception {
303        addNetworks();
304        for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
305            switchUser(entry.getKey());
306            verifyNetworkConfigs(entry.getValue(), mWifiConfigManager.getConfiguredNetworks());
307        }
308    }
309
310    /**
311     * Verifies that getPrivilegedConfiguredNetworks() returns the network configurations visible to
312     * the current user.
313     */
314    @Test
315    public void testGetPrivilegedConfiguredNetworks() throws Exception {
316        addNetworks();
317        for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
318            switchUser(entry.getKey());
319            verifyNetworkConfigs(entry.getValue(),
320                    mWifiConfigManager.getPrivilegedConfiguredNetworks());
321        }
322    }
323
324    /**
325     * Verifies that getWifiConfiguration(int netId) can be used to access network configurations
326     * visible to the current user only.
327     */
328    @Test
329    public void testGetWifiConfigurationByNetworkId() throws Exception {
330        addNetworks();
331        for (int userId : USER_IDS) {
332            switchUser(userId);
333            for (WifiConfiguration expectedConfig: CONFIGS) {
334                final WifiConfiguration actualConfig =
335                        mWifiConfigManager.getWifiConfiguration(expectedConfig.networkId);
336                if (WifiConfigurationUtil.isVisibleToAnyProfile(expectedConfig,
337                        USER_PROFILES.get(userId))) {
338                    verifyNetworkConfig(expectedConfig, actualConfig);
339                } else {
340                    assertNull(actualConfig);
341                }
342            }
343        }
344    }
345
346    /**
347     * Verifies that getWifiConfiguration(String key) can be used to access network configurations
348     * visible to the current user only.
349     */
350    @Test
351    public void testGetWifiConfigurationByConfigKey() throws Exception {
352        addNetworks();
353        for (int userId : USER_IDS) {
354            switchUser(userId);
355            for (WifiConfiguration expectedConfig: CONFIGS) {
356                final WifiConfiguration actualConfig =
357                        mWifiConfigManager.getWifiConfiguration(expectedConfig.configKey());
358                if (WifiConfigurationUtil.isVisibleToAnyProfile(expectedConfig,
359                        USER_PROFILES.get(userId))) {
360                    verifyNetworkConfig(expectedConfig, actualConfig);
361                } else {
362                    assertNull(actualConfig);
363                }
364            }
365        }
366    }
367
368    /**
369     * Verifies that enableAllNetworks() enables all temporarily disabled network configurations
370     * visible to the current user.
371     */
372    @Test
373    public void testEnableAllNetworks() throws Exception {
374        addNetworks();
375        for (int userId : USER_IDS) {
376            switchUser(userId);
377
378            for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
379                final WifiConfiguration.NetworkSelectionStatus status =
380                        config.getNetworkSelectionStatus();
381                status.setNetworkSelectionStatus(WifiConfiguration.NetworkSelectionStatus
382                        .NETWORK_SELECTION_TEMPORARY_DISABLED);
383                status.setNetworkSelectionDisableReason(
384                        WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE);
385                status.setDisableTime(System.currentTimeMillis() - 60 * 60 * 1000);
386            }
387
388            mWifiConfigManager.enableAllNetworks();
389
390            for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
391                assertEquals(WifiConfigurationUtil.isVisibleToAnyProfile(config,
392                        USER_PROFILES.get(userId)),
393                        config.getNetworkSelectionStatus().isNetworkEnabled());
394            }
395        }
396    }
397
398    /**
399     * Verifies that selectNetwork() disables all network configurations visible to the current user
400     * except the selected one.
401     */
402    @Test
403    public void testSelectNetwork() throws Exception {
404        addNetworks();
405
406        for (int userId : USER_IDS) {
407            switchUser(userId);
408
409            for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
410                // Enable all network configurations.
411                for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) {
412                    config2.status = WifiConfiguration.Status.ENABLED;
413                }
414
415                // Try to select a network configuration.
416                final WifiNative wifiNative = createNewWifiNativeMock();
417                when(wifiNative.selectNetwork(config.networkId)).thenReturn(true);
418                final boolean success =
419                        mWifiConfigManager.selectNetwork(config, false, config.creatorUid);
420                if (!WifiConfigurationUtil.isVisibleToAnyProfile(config,
421                        USER_PROFILES.get(userId))) {
422                    // If the network configuration is not visible to the current user, verify that
423                    // nothing changed.
424                    assertFalse(success);
425                    verify(wifiNative, never()).selectNetwork(anyInt());
426                    verify(wifiNative, never()).enableNetwork(anyInt());
427                    for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) {
428                        assertEquals(WifiConfiguration.Status.ENABLED, config2.status);
429                    }
430                } else {
431                    // If the network configuration is visible to the current user, verify that it
432                    // was enabled and all other network configurations visible to the user were
433                    // disabled.
434                    assertTrue(success);
435                    verify(wifiNative).selectNetwork(config.networkId);
436                    verify(wifiNative, never()).selectNetwork(intThat(not(config.networkId)));
437                    verify(wifiNative, never()).enableNetwork(config.networkId);
438                    verify(wifiNative, never()).enableNetwork(intThat(not(config.networkId)));
439                    for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) {
440                        if (WifiConfigurationUtil.isVisibleToAnyProfile(config2,
441                                USER_PROFILES.get(userId))
442                                && config2.networkId != config.networkId) {
443                            assertEquals(WifiConfiguration.Status.DISABLED, config2.status);
444                        } else {
445                            assertEquals(WifiConfiguration.Status.ENABLED, config2.status);
446                        }
447                    }
448                }
449            }
450        }
451    }
452
453    /**
454     * Verifies that saveNetwork() correctly stores a network configuration in wpa_supplicant
455     * variables and the networkHistory.txt file.
456     * TODO: Test all variables. Currently, only the following variables are tested:
457     * - In the wpa_supplicant: "ssid", "id_str"
458     * - In networkHistory.txt: "CONFIG", "CREATOR_UID_KEY", "SHARED"
459     */
460    private void verifySaveNetwork(int network) throws Exception {
461        // Switch to the correct user.
462        switchUserToCreatorOrParentOf(CONFIGS.get(network));
463
464        // Set up wpa_supplicant.
465        when(mWifiNative.addNetwork()).thenReturn(0);
466        when(mWifiNative.setNetworkVariable(eq(network), anyString(), anyString()))
467                .thenReturn(true);
468        when(mWifiNative.setNetworkExtra(eq(network), anyString(),
469                (Map<String, String>) anyObject())).thenReturn(true);
470        when(mWifiNative.getNetworkVariable(network, WifiConfiguration.ssidVarName))
471                .thenReturn(encodeConfigSSID(CONFIGS.get(network)));
472
473        // Store a network configuration.
474        mWifiConfigManager.saveNetwork(CONFIGS.get(network), CONFIGS.get(network).creatorUid);
475
476        // Verify that wpa_supplicant variables were written correctly for the network
477        // configuration.
478        final Map<String, String> metadata = new HashMap<String, String>();
479        if (CONFIGS.get(network).FQDN != null) {
480            metadata.put(WifiConfigManager.ID_STRING_KEY_FQDN, CONFIGS.get(network).FQDN);
481        }
482        metadata.put(WifiConfigManager.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(network).configKey());
483        metadata.put(WifiConfigManager.ID_STRING_KEY_CREATOR_UID,
484                Integer.toString(CONFIGS.get(network).creatorUid));
485        verify(mWifiNative).setNetworkExtra(network, WifiConfigManager.ID_STRING_VAR_NAME,
486                metadata);
487
488        // Verify that no wpa_supplicant variables were read or written for any other network
489        // configurations.
490        verify(mWifiNative, never()).setNetworkExtra(intThat(not(network)), anyString(),
491                (Map<String, String>) anyObject());
492        verify(mWifiNative, never()).setNetworkVariable(intThat(not(network)), anyString(),
493                anyString());
494        verify(mWifiNative, never()).getNetworkVariable(intThat(not(network)), anyString());
495
496        // Parse networkHistory.txt.
497        assertNotNull(mNetworkHistoryBytes);
498        final DataInputStream stream =
499                new DataInputStream(new ByteArrayInputStream(mNetworkHistoryBytes));
500        List<String> keys = new ArrayList<>();
501        List<String> values = new ArrayList<>();
502        try {
503            while (true) {
504                final String[] tokens = stream.readUTF().split(":", 2);
505                if (tokens.length == 2) {
506                    keys.add(tokens[0].trim());
507                    values.add(tokens[1].trim());
508                }
509            }
510        } catch (EOFException e) {
511            // Ignore. This is expected.
512        }
513
514        // Verify that a networkHistory.txt entry was written correctly for the network
515        // configuration.
516        assertTrue(keys.size() >= 3);
517        assertEquals(WifiNetworkHistory.CONFIG_KEY, keys.get(0));
518        assertEquals(CONFIGS.get(network).configKey(), values.get(0));
519        final int creatorUidIndex = keys.indexOf(WifiNetworkHistory.CREATOR_UID_KEY);
520        assertTrue(creatorUidIndex != -1);
521        assertEquals(Integer.toString(CONFIGS.get(network).creatorUid),
522                values.get(creatorUidIndex));
523        final int sharedIndex = keys.indexOf(WifiNetworkHistory.SHARED_KEY);
524        assertTrue(sharedIndex != -1);
525        assertEquals(Boolean.toString(CONFIGS.get(network).shared), values.get(sharedIndex));
526
527        // Verify that no networkHistory.txt entries were written for any other network
528        // configurations.
529        final int lastConfigIndex = keys.lastIndexOf(WifiNetworkHistory.CONFIG_KEY);
530        assertEquals(0, lastConfigIndex);
531    }
532
533    /**
534     * Verifies that saveNetwork() correctly stores a regular network configuration.
535     */
536    @Test
537    public void testSaveNetworkRegular() throws Exception {
538        verifySaveNetwork(0);
539    }
540
541    /**
542     * Verifies that saveNetwork() correctly stores a HotSpot 2.0 network configuration.
543     */
544    @Test
545    public void testSaveNetworkHotspot20() throws Exception {
546        verifySaveNetwork(1);
547    }
548
549    /**
550     * Verifies that saveNetwork() correctly stores a private network configuration.
551     */
552    @Test
553    public void testSaveNetworkPrivate() throws Exception {
554        verifySaveNetwork(2);
555    }
556
557    /**
558     * Verifies that loadConfiguredNetworks() correctly reads data from the wpa_supplicant, the
559     * networkHistory.txt file and the MOManager, correlating the three sources based on the
560     * configKey and the FQDN for HotSpot 2.0 networks.
561     * TODO: Test all variables. Currently, only the following variables are tested:
562     * - In the wpa_supplicant: "ssid", "id_str"
563     * - In networkHistory.txt: "CONFIG", "CREATOR_UID_KEY", "SHARED"
564     */
565    @Test
566    public void testLoadConfiguredNetworks() throws Exception {
567        // Set up list of network configurations returned by wpa_supplicant.
568        final String header = "network id / ssid / bssid / flags";
569        String networks = header;
570        for (WifiConfiguration config : CONFIGS) {
571            networks += "\n" + Integer.toString(config.networkId) + "\t" + config.SSID + "\tany";
572        }
573        when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
574        when(mWifiNative.listNetworks(-1)).thenReturn(networks);
575
576        // Set up variables returned by wpa_supplicant for the individual network configurations.
577        for (int i = 0; i < CONFIGS.size(); ++i) {
578            when(mWifiNative.getNetworkVariable(i, WifiConfiguration.ssidVarName))
579                .thenReturn(encodeConfigSSID(CONFIGS.get(i)));
580        }
581        // Legacy regular network configuration: No "id_str".
582        when(mWifiNative.getNetworkExtra(0, WifiConfigManager.ID_STRING_VAR_NAME))
583            .thenReturn(null);
584        // Legacy Hotspot 2.0 network configuration: Quoted FQDN in "id_str".
585        when(mWifiNative.getNetworkExtra(1, WifiConfigManager.ID_STRING_VAR_NAME))
586            .thenReturn(null);
587        when(mWifiNative.getNetworkVariable(1, WifiConfigManager.ID_STRING_VAR_NAME))
588            .thenReturn('"' + CONFIGS.get(1).FQDN + '"');
589        // Up-to-date Hotspot 2.0 network configuration: Metadata in "id_str".
590        Map<String, String> metadata = new HashMap<String, String>();
591        metadata.put(WifiConfigManager.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(2).configKey());
592        metadata.put(WifiConfigManager.ID_STRING_KEY_CREATOR_UID,
593                Integer.toString(CONFIGS.get(2).creatorUid));
594        metadata.put(WifiConfigManager.ID_STRING_KEY_FQDN, CONFIGS.get(2).FQDN);
595        when(mWifiNative.getNetworkExtra(2, WifiConfigManager.ID_STRING_VAR_NAME))
596            .thenReturn(metadata);
597        // Up-to-date regular network configuration: Metadata in "id_str".
598        metadata = new HashMap<String, String>();
599        metadata.put(WifiConfigManager.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(3).configKey());
600        metadata.put(WifiConfigManager.ID_STRING_KEY_CREATOR_UID,
601                Integer.toString(CONFIGS.get(3).creatorUid));
602        when(mWifiNative.getNetworkExtra(3, WifiConfigManager.ID_STRING_VAR_NAME))
603            .thenReturn(metadata);
604
605        // Set up networkHistory.txt file.
606        final File file = File.createTempFile("networkHistory.txt", null);
607        file.deleteOnExit();
608
609        Field wifiNetworkHistoryConfigFile =
610                WifiNetworkHistory.class.getDeclaredField("NETWORK_HISTORY_CONFIG_FILE");
611        wifiNetworkHistoryConfigFile.setAccessible(true);
612        wifiNetworkHistoryConfigFile.set(null, file.getAbsolutePath());
613
614        final DataOutputStream stream = new DataOutputStream(new FileOutputStream(file));
615        for (WifiConfiguration config : CONFIGS) {
616            stream.writeUTF(WifiNetworkHistory.CONFIG_KEY + ":  " + config.configKey() + '\n');
617            stream.writeUTF(WifiNetworkHistory.CREATOR_UID_KEY + ":  "
618                    + Integer.toString(config.creatorUid) + '\n');
619            stream.writeUTF(WifiNetworkHistory.SHARED_KEY + ":  "
620                    + Boolean.toString(config.shared) + '\n');
621        }
622        stream.close();
623
624        // Set up list of home service providers returned by MOManager.
625        final List<HomeSP> homeSPs = new ArrayList<HomeSP>();
626        for (WifiConfiguration config : CONFIGS) {
627            if (config.FQDN != null) {
628                homeSPs.add(new HomeSP(null, config.FQDN, new HashSet<Long>(),
629                        new HashSet<String>(),
630                        new HashSet<Long>(), new ArrayList<Long>(),
631                        config.providerFriendlyName, null,
632                        new Credential(0, 0, null, false, null, null),
633                        null, 0, null, null, null, 0));
634            }
635        }
636        when(mMOManager.loadAllSPs()).thenReturn(homeSPs);
637
638        // Load network configurations.
639        mWifiConfigManager.loadConfiguredNetworks();
640
641        // Verify that network configurations were loaded and correlated correctly across the three
642        // sources.
643        verifyNetworkConfigs(CONFIGS, mConfiguredNetworks.valuesForAllUsers());
644    }
645
646    /**
647     * Verifies that loadConfiguredNetworks() correctly handles duplicates when reading network
648     * configurations from the wpa_supplicant: The second configuration overwrites the first.
649     */
650    @Test
651    public void testLoadConfiguredNetworksEliminatesDuplicates() throws Exception {
652        final WifiConfiguration config = new WifiConfiguration(CONFIGS.get(0));
653        config.networkId = 1;
654
655        // Set up list of network configurations returned by wpa_supplicant. The two configurations
656        // are identical except for their network IDs.
657        final String header = "network id / ssid / bssid / flags";
658        final String networks =
659                header + "\n0\t" + config.SSID + "\tany\n1\t" + config.SSID + "\tany";
660        when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
661        when(mWifiNative.listNetworks(-1)).thenReturn(networks);
662
663        // Set up variables returned by wpa_supplicant.
664        when(mWifiNative.getNetworkVariable(anyInt(), eq(WifiConfiguration.ssidVarName)))
665            .thenReturn(encodeConfigSSID(config));
666        final Map<String, String> metadata = new HashMap<String, String>();
667        metadata.put(WifiConfigManager.ID_STRING_KEY_CONFIG_KEY, config.configKey());
668        metadata.put(WifiConfigManager.ID_STRING_KEY_CREATOR_UID,
669                Integer.toString(config.creatorUid));
670        when(mWifiNative.getNetworkExtra(anyInt(), eq(WifiConfigManager.ID_STRING_VAR_NAME)))
671            .thenReturn(metadata);
672
673        // Load network configurations.
674        mWifiConfigManager.loadConfiguredNetworks();
675
676        // Verify that the second network configuration (network ID 1) overwrote the first (network
677        // ID 0).
678        verifyNetworkConfigs(Arrays.asList(config), mConfiguredNetworks.valuesForAllUsers());
679    }
680
681    /**
682     * Verifies that handleUserSwitch() removes ephemeral network configurations, disables network
683     * configurations that should no longer be visible and enables network configurations that
684     * should become visible.
685     */
686    private void verifyHandleUserSwitch(int oldUserId, int newUserId,
687            boolean makeOneConfigEphemeral) throws Exception {
688        addNetworks();
689        switchUser(oldUserId);
690
691        final WifiNative wifiNative = createNewWifiNativeMock();
692        final Field lastSelectedConfigurationField =
693                WifiConfigManager.class.getDeclaredField("lastSelectedConfiguration");
694        lastSelectedConfigurationField.setAccessible(true);
695        WifiConfiguration removedEphemeralConfig = null;
696        final Set<WifiConfiguration> oldUserOnlyConfigs = new HashSet<>();
697        final Set<WifiConfiguration> newUserOnlyConfigs = new HashSet<>();
698        final Set<WifiConfiguration> neitherUserConfigs = new HashSet<>();
699        final Collection<WifiConfiguration> oldConfigs = mConfiguredNetworks.valuesForAllUsers();
700        int expectedNumberOfConfigs = oldConfigs.size();
701        for (WifiConfiguration config : oldConfigs) {
702            if (WifiConfigurationUtil.isVisibleToAnyProfile(config, USER_PROFILES.get(oldUserId))) {
703                config.status = WifiConfiguration.Status.ENABLED;
704                if (WifiConfigurationUtil.isVisibleToAnyProfile(config,
705                        USER_PROFILES.get(newUserId))) {
706                    if (makeOneConfigEphemeral && removedEphemeralConfig == null) {
707                        config.ephemeral = true;
708                        lastSelectedConfigurationField.set(mWifiConfigManager, config.configKey());
709                        removedEphemeralConfig = config;
710                    }
711                } else {
712                    oldUserOnlyConfigs.add(config);
713                }
714            } else {
715                config.status = WifiConfiguration.Status.DISABLED;
716                if (WifiConfigurationUtil.isVisibleToAnyProfile(config,
717                        USER_PROFILES.get(newUserId))) {
718                    newUserOnlyConfigs.add(config);
719                } else {
720                    neitherUserConfigs.add(config);
721                }
722            }
723        }
724        when(wifiNative.disableNetwork(anyInt())).thenReturn(true);
725
726        switchUser(newUserId);
727        if (makeOneConfigEphemeral) {
728            // Verify that the ephemeral network configuration was removed.
729            assertNotNull(removedEphemeralConfig);
730            assertNull(mConfiguredNetworks.getForAllUsers(removedEphemeralConfig.networkId));
731            assertNull(lastSelectedConfigurationField.get(mWifiConfigManager));
732            verify(wifiNative).removeNetwork(removedEphemeralConfig.networkId);
733            --expectedNumberOfConfigs;
734        } else {
735            assertNull(removedEphemeralConfig);
736        }
737
738        // Verify that the other network configurations were revealed/hidden and enabled/disabled as
739        // appropriate.
740        final Collection<WifiConfiguration> newConfigs = mConfiguredNetworks.valuesForAllUsers();
741        assertEquals(expectedNumberOfConfigs, newConfigs.size());
742        for (WifiConfiguration config : newConfigs) {
743            if (oldUserOnlyConfigs.contains(config)) {
744                verify(wifiNative).disableNetwork(config.networkId);
745                assertEquals(WifiConfiguration.Status.DISABLED, config.status);
746            } else {
747                verify(wifiNative, never()).disableNetwork(config.networkId);
748                if (neitherUserConfigs.contains(config)) {
749                    assertEquals(WifiConfiguration.Status.DISABLED, config.status);
750                } else {
751                    // Only enabled in networkSelection.
752                    assertTrue(config.getNetworkSelectionStatus().isNetworkEnabled());
753                }
754
755            }
756        }
757    }
758
759    /**
760     * Verifies that handleUserSwitch() behaves correctly when the user switch removes an ephemeral
761     * network configuration and reveals a private network configuration.
762     */
763    @Test
764    public void testHandleUserSwitchWithEphemeral() throws Exception {
765        verifyHandleUserSwitch(USER_IDS[2], USER_IDS[0], true);
766    }
767
768    /**
769     * Verifies that handleUserSwitch() behaves correctly when the user switch hides a private
770     * network configuration.
771     */
772    @Test
773    public void testHandleUserSwitchWithoutEphemeral() throws Exception {
774        verifyHandleUserSwitch(USER_IDS[0], USER_IDS[2], false);
775    }
776
777    @Test
778    public void testSaveLoadEapNetworks() {
779        testSaveLoadSingleEapNetwork("eap network", new EnterpriseConfig(Eap.TTLS)
780                .setPhase2(Phase2.MSCHAPV2)
781                .setIdentity("username", "password")
782                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0}));
783        testSaveLoadSingleEapNetwork("eap network", new EnterpriseConfig(Eap.TTLS)
784                .setPhase2(Phase2.MSCHAPV2)
785                .setIdentity("username", "password")
786                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT1, FakeKeys.CA_CERT0}));
787
788    }
789
790    private void testSaveLoadSingleEapNetwork(String ssid, EnterpriseConfig eapConfig) {
791        final HashMap<String, String> networkVariables = new HashMap<String, String>();
792        reset(mWifiNative);
793        when(mWifiNative.addNetwork()).thenReturn(0);
794        when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString())).thenAnswer(
795                new AnswerWithArguments() {
796                    public boolean answer(int netId, String name, String value) {
797                        // Verify that no wpa_supplicant variables were written for any other
798                        // network configurations.
799                        assertEquals(netId, 0);
800                        networkVariables.put(name, value);
801                        return true;
802                    }
803                });
804        when(mWifiNative.getNetworkVariable(anyInt(), anyString())).then(
805                new AnswerWithArguments() {
806                    public String answer(int netId, String name) {
807                        // Verify that no wpa_supplicant variables were read for any other
808                        // network configurations.
809                        assertEquals(netId, 0);
810                        return networkVariables.get(name);
811                    }
812                });
813        when(mWifiNative.setNetworkExtra(eq(0), anyString(), (Map<String, String>) anyObject()))
814                .thenReturn(true);
815
816        WifiConfiguration config = new WifiConfiguration();
817        config.SSID = ssid;
818        config.creatorUid = Process.WIFI_UID;
819        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
820        config.enterpriseConfig = eapConfig.enterpriseConfig;
821
822        // Store a network configuration.
823        mWifiConfigManager.saveNetwork(config, Process.WIFI_UID);
824
825        // Verify that wpa_supplicant variables were written correctly for the network
826        // configuration.
827        verify(mWifiNative).addNetwork();
828        assertEquals(eapConfig.eap,
829                unquote(networkVariables.get(WifiEnterpriseConfig.EAP_KEY)));
830        assertEquals(eapConfig.phase2,
831                unquote(networkVariables.get(WifiEnterpriseConfig.PHASE2_KEY)));
832        assertEquals(eapConfig.identity,
833                unquote(networkVariables.get(WifiEnterpriseConfig.IDENTITY_KEY)));
834        assertEquals(eapConfig.password,
835                unquote(networkVariables.get(WifiEnterpriseConfig.PASSWORD_KEY)));
836        assertSavedCaCerts(eapConfig,
837                unquote(networkVariables.get(WifiEnterpriseConfig.CA_CERT_KEY)));
838
839        // Prepare the scan result.
840        final String header = "network id / ssid / bssid / flags";
841        String networks = header + "\n" + Integer.toString(0) + "\t" + ssid + "\tany";
842        when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
843        when(mWifiNative.listNetworks(-1)).thenReturn(networks);
844
845        // Load back the configuration.
846        mWifiConfigManager.loadConfiguredNetworks();
847        List<WifiConfiguration> configs = mWifiConfigManager.getConfiguredNetworks();
848        assertEquals(1, configs.size());
849        WifiConfiguration loadedConfig = configs.get(0);
850        assertEquals(ssid, unquote(loadedConfig.SSID));
851        BitSet keyMgmt = new BitSet();
852        keyMgmt.set(KeyMgmt.WPA_EAP);
853        assertEquals(keyMgmt, loadedConfig.allowedKeyManagement);
854        assertEquals(eapConfig.enterpriseConfig.getEapMethod(),
855                loadedConfig.enterpriseConfig.getEapMethod());
856        assertEquals(eapConfig.enterpriseConfig.getPhase2Method(),
857                loadedConfig.enterpriseConfig.getPhase2Method());
858        assertEquals(eapConfig.enterpriseConfig.getIdentity(),
859                loadedConfig.enterpriseConfig.getIdentity());
860        assertEquals(eapConfig.enterpriseConfig.getPassword(),
861                loadedConfig.enterpriseConfig.getPassword());
862        asserCaCertsAliasesMatch(eapConfig.caCerts,
863                loadedConfig.enterpriseConfig.getCaCertificateAliases());
864    }
865
866    private String unquote(String value) {
867        if (value == null) {
868            return null;
869        }
870        int length = value.length();
871        if ((length > 1) && (value.charAt(0) == '"')
872                && (value.charAt(length - 1) == '"')) {
873            return value.substring(1, length - 1);
874        } else {
875            return value;
876        }
877    }
878
879    private void asserCaCertsAliasesMatch(X509Certificate[] certs, String[] aliases) {
880        assertEquals(certs.length, aliases.length);
881        List<String> aliasList = new ArrayList<String>(Arrays.asList(aliases));
882        try {
883            for (int i = 0; i < certs.length; i++) {
884                byte[] certPem = Credentials.convertToPem(certs[i]);
885                boolean found = false;
886                for (int j = 0; j < aliasList.size(); j++) {
887                    byte[] keystoreCert = mMockKeyStore.getKeyBlob(Process.WIFI_UID,
888                            Credentials.CA_CERTIFICATE + aliasList.get(j)).blob;
889                    if (Arrays.equals(keystoreCert, certPem)) {
890                        found = true;
891                        aliasList.remove(j);
892                        break;
893                    }
894                }
895                assertTrue(found);
896            }
897        } catch (CertificateEncodingException | IOException e) {
898            fail("Cannot convert CA certificate to encoded form.");
899        }
900    }
901
902    private void assertSavedCaCerts(EnterpriseConfig eapConfig, String caCertVariable) {
903        ArrayList<String> aliases = new ArrayList<String>();
904        if (TextUtils.isEmpty(caCertVariable)) {
905            // Do nothing.
906        } else if (caCertVariable.startsWith(WifiEnterpriseConfig.CA_CERT_PREFIX)) {
907            aliases.add(caCertVariable.substring(WifiEnterpriseConfig.CA_CERT_PREFIX.length()));
908        } else if (caCertVariable.startsWith(WifiEnterpriseConfig.KEYSTORES_URI)) {
909            String[] encodedAliases = TextUtils.split(
910                    caCertVariable.substring(WifiEnterpriseConfig.KEYSTORES_URI.length()),
911                    WifiEnterpriseConfig.CA_CERT_ALIAS_DELIMITER);
912            for (String encodedAlias : encodedAliases) {
913                String alias = WifiEnterpriseConfig.decodeCaCertificateAlias(encodedAlias);
914                assertTrue(alias.startsWith(Credentials.CA_CERTIFICATE));
915                aliases.add(alias.substring(Credentials.CA_CERTIFICATE.length()));
916            }
917        } else {
918            fail("Unrecognized ca_cert variable: " + caCertVariable);
919        }
920        asserCaCertsAliasesMatch(eapConfig.caCerts, aliases.toArray(new String[aliases.size()]));
921    }
922
923    private static class EnterpriseConfig {
924        public String eap;
925        public String phase2;
926        public String identity;
927        public String password;
928        public X509Certificate[] caCerts;
929        public WifiEnterpriseConfig enterpriseConfig;
930
931        public EnterpriseConfig(int eapMethod) {
932            enterpriseConfig = new WifiEnterpriseConfig();
933            enterpriseConfig.setEapMethod(eapMethod);
934            eap = Eap.strings[eapMethod];
935        }
936        public EnterpriseConfig setPhase2(int phase2Method) {
937            enterpriseConfig.setPhase2Method(phase2Method);
938            phase2 = "auth=" + Phase2.strings[phase2Method];
939            return this;
940        }
941        public EnterpriseConfig setIdentity(String identity, String password) {
942            enterpriseConfig.setIdentity(identity);
943            enterpriseConfig.setPassword(password);
944            this.identity = identity;
945            this.password = password;
946            return this;
947        }
948        public EnterpriseConfig setCaCerts(X509Certificate[] certs) {
949            enterpriseConfig.setCaCertificates(certs);
950            caCerts = certs;
951            return this;
952        }
953    }
954
955    /**
956     * Generates an array of unique random numbers below the specified maxValue.
957     * Values range from 0 to maxValue-1.
958     */
959    private static ArrayDeque<Integer> getUniqueRandomNumberValues(
960            int seed,
961            int maxValue,
962            int numValues) {
963        assertTrue(numValues <= maxValue);
964        Random rand = new Random(WifiTestUtil.getTestMethod().hashCode() + seed);
965        ArrayDeque<Integer> randomNumberList = new ArrayDeque<>();
966        for (int i = 0; i < numValues; i++) {
967            int num = rand.nextInt(maxValue);
968            while (randomNumberList.contains(num)) {
969                num = rand.nextInt(maxValue);
970            }
971            randomNumberList.push(num);
972        }
973        return randomNumberList;
974    }
975
976    /**
977     * Verifies that the networks in pnoNetworkList is sorted in the same order as the
978     * network in expectedNetworkIDOrder list.
979     */
980    private static void verifyPnoNetworkListOrder(
981            ArrayList<WifiNative.WifiPnoNetwork> pnoNetworkList,
982            ArrayList<Integer> expectedNetworkIdOrder) throws Exception  {
983        int i = 0;
984        for (WifiNative.WifiPnoNetwork pnoNetwork : pnoNetworkList) {
985            Log.i(TAG, "PNO Network List Index: " + i + ", networkID: " + pnoNetwork.networkId);
986            assertEquals("Expected network ID: " + pnoNetwork.networkId,
987                    pnoNetwork.networkId, expectedNetworkIdOrder.get(i++).intValue());
988        }
989    }
990
991    /**
992     * Verifies the retrieveDisconnectedWifiPnoNetworkList API. The test verifies that the list
993     * returned from the API is sorted as expected.
994     */
995    @Test
996    public void testDisconnectedWifiPnoNetworkListCreation() throws Exception {
997        addNetworks();
998
999        Random rand = new Random(WifiTestUtil.getTestMethod().hashCode());
1000
1001        // First assign random |numAssociation| values and verify that the list is sorted
1002        // in descending order of |numAssociation| values. Keep NetworkSelectionStatus
1003        // values constant.
1004        for (int userId : USER_IDS) {
1005            switchUser(userId);
1006            TreeMap<Integer, Integer> numAssociationToNetworkIdMap =
1007                    new TreeMap<>(Collections.reverseOrder());
1008            ArrayDeque<Integer> numAssociationValues =
1009                    getUniqueRandomNumberValues(
1010                            1, 10000, mConfiguredNetworks.valuesForCurrentUser().size());
1011            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1012                config.numAssociation = numAssociationValues.pop();
1013                config.priority = rand.nextInt(10000);
1014                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1015                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1016                numAssociationToNetworkIdMap.put(config.numAssociation, config.networkId);
1017                Log.i(TAG, "networkID: " + config.networkId + ", numAssociation: "
1018                        + config.numAssociation);
1019            }
1020            ArrayList<WifiNative.WifiPnoNetwork> pnoNetworkList =
1021                    mWifiConfigManager.retrieveDisconnectedWifiPnoNetworkList();
1022            verifyPnoNetworkListOrder(pnoNetworkList,
1023                    new ArrayList(numAssociationToNetworkIdMap.values()));
1024        }
1025
1026        // Assign random |priority| values and verify that the list is sorted in descending order
1027        // of |priority| values. Keep numAssociation/NetworkSelectionStatus values constant.
1028        for (int userId : USER_IDS) {
1029            switchUser(userId);
1030            TreeMap<Integer, Integer> priorityToNetworkIdMap =
1031                    new TreeMap<>(Collections.reverseOrder());
1032            ArrayDeque<Integer> priorityValues =
1033                    getUniqueRandomNumberValues(
1034                            2, 10000, mConfiguredNetworks.valuesForCurrentUser().size());
1035            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1036                config.numAssociation = 0;
1037                config.priority = priorityValues.pop();
1038                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1039                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1040                priorityToNetworkIdMap.put(config.priority, config.networkId);
1041                Log.i(TAG, "networkID: " + config.networkId + ", priority: " + config.priority);
1042            }
1043            ArrayList<WifiNative.WifiPnoNetwork> pnoNetworkList =
1044                    mWifiConfigManager.retrieveDisconnectedWifiPnoNetworkList();
1045            verifyPnoNetworkListOrder(pnoNetworkList,
1046                    new ArrayList(priorityToNetworkIdMap.values()));
1047        }
1048
1049        // Now assign random |NetworkSelectionStatus| values and verify that the list is sorted in
1050        // ascending order of |NetworkSelectionStatus| values.
1051        for (int userId : USER_IDS) {
1052            switchUser(userId);
1053            TreeMap<Integer, Integer> networkSelectionStatusToNetworkIdMap = new TreeMap<>();
1054            ArrayDeque<Integer> networkSelectionStatusValues =
1055                    getUniqueRandomNumberValues(
1056                            3,
1057                            WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_STATUS_MAX,
1058                            mConfiguredNetworks.valuesForCurrentUser().size());
1059            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1060                config.numAssociation = rand.nextInt(10000);
1061                config.priority = rand.nextInt(10000);
1062                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1063                        networkSelectionStatusValues.pop());
1064                networkSelectionStatusToNetworkIdMap.put(
1065                        config.getNetworkSelectionStatus().getNetworkSelectionStatus(),
1066                        config.networkId);
1067                Log.i(TAG, "networkID: " + config.networkId + ", NetworkSelectionStatus: "
1068                        + config.getNetworkSelectionStatus().getNetworkSelectionStatus());
1069            }
1070            ArrayList<WifiNative.WifiPnoNetwork> pnoNetworkList =
1071                    mWifiConfigManager.retrieveDisconnectedWifiPnoNetworkList();
1072            verifyPnoNetworkListOrder(pnoNetworkList,
1073                    new ArrayList(networkSelectionStatusToNetworkIdMap.values()));
1074        }
1075    }
1076
1077    /**
1078     * Verifies the retrieveConnectedWifiPnoNetworkList API. The test verifies that the list
1079     * returned from the API is sorted as expected.
1080     */
1081    @Test
1082    public void testConnectedWifiPnoNetworkListCreation() throws Exception {
1083        addNetworks();
1084
1085        Random rand = new Random(WifiTestUtil.getTestMethod().hashCode());
1086
1087        // First assign |lastSeen| values and verify that the list is sorted
1088        // in descending order of |lastSeen| values. Keep NetworkSelectionStatus
1089        // values constant.
1090        for (int userId : USER_IDS) {
1091            switchUser(userId);
1092            TreeMap<Boolean, Integer> lastSeenToNetworkIdMap =
1093                    new TreeMap<>(Collections.reverseOrder());
1094            ArrayDeque<Integer> lastSeenValues = getUniqueRandomNumberValues(1, 2, 2);
1095            if (mConfiguredNetworks.valuesForCurrentUser().size() > 2) continue;
1096            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1097                config.numAssociation = rand.nextInt(10000);
1098                config.priority = rand.nextInt(10000);
1099                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1100                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1101                boolean lastSeenValue = (lastSeenValues.pop()  == 1);
1102                config.getNetworkSelectionStatus().setSeenInLastQualifiedNetworkSelection(
1103                        lastSeenValue);
1104                lastSeenToNetworkIdMap.put(lastSeenValue, config.networkId);
1105                Log.i(TAG, "networkID: " + config.networkId + ", lastSeen: " + lastSeenValue);
1106            }
1107            ArrayList<WifiNative.WifiPnoNetwork> pnoNetworkList =
1108                    mWifiConfigManager.retrieveConnectedWifiPnoNetworkList();
1109            verifyPnoNetworkListOrder(pnoNetworkList,
1110                    new ArrayList(lastSeenToNetworkIdMap.values()));
1111        }
1112
1113        // Assign random |numAssociation| values and verify that the list is sorted
1114        // in descending order of |numAssociation| values. Keep NetworkSelectionStatus/lastSeen
1115        // values constant.
1116        for (int userId : USER_IDS) {
1117            switchUser(userId);
1118            TreeMap<Integer, Integer> numAssociationToNetworkIdMap =
1119                    new TreeMap<>(Collections.reverseOrder());
1120            ArrayDeque<Integer> numAssociationValues =
1121                    getUniqueRandomNumberValues(
1122                            1, 10000, mConfiguredNetworks.valuesForCurrentUser().size());
1123            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1124                config.numAssociation = numAssociationValues.pop();
1125                config.priority = rand.nextInt(10000);
1126                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1127                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1128                config.getNetworkSelectionStatus().setSeenInLastQualifiedNetworkSelection(true);
1129                numAssociationToNetworkIdMap.put(config.numAssociation, config.networkId);
1130                Log.i(TAG, "networkID: " + config.networkId + ", numAssociation: "
1131                        + config.numAssociation);
1132            }
1133            ArrayList<WifiNative.WifiPnoNetwork> pnoNetworkList =
1134                    mWifiConfigManager.retrieveConnectedWifiPnoNetworkList();
1135            verifyPnoNetworkListOrder(pnoNetworkList,
1136                    new ArrayList(numAssociationToNetworkIdMap.values()));
1137        }
1138
1139        // Now assign random |NetworkSelectionStatus| values and verify that the list is sorted in
1140        // ascending order of |NetworkSelectionStatus| values.
1141        for (int userId : USER_IDS) {
1142            switchUser(userId);
1143            TreeMap<Integer, Integer> networkSelectionStatusToNetworkIdMap = new TreeMap<>();
1144            ArrayDeque<Integer> networkSelectionStatusValues =
1145                    getUniqueRandomNumberValues(
1146                            3,
1147                            WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_STATUS_MAX,
1148                            mConfiguredNetworks.valuesForCurrentUser().size());
1149            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1150                config.numAssociation = rand.nextInt(10000);
1151                config.priority = rand.nextInt(10000);
1152                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1153                        networkSelectionStatusValues.pop());
1154                networkSelectionStatusToNetworkIdMap.put(
1155                        config.getNetworkSelectionStatus().getNetworkSelectionStatus(),
1156                        config.networkId);
1157                Log.i(TAG, "networkID: " + config.networkId + ", NetworkSelectionStatus: "
1158                        + config.getNetworkSelectionStatus().getNetworkSelectionStatus());
1159            }
1160            ArrayList<WifiNative.WifiPnoNetwork> pnoNetworkList =
1161                    mWifiConfigManager.retrieveConnectedWifiPnoNetworkList();
1162            verifyPnoNetworkListOrder(pnoNetworkList,
1163                    new ArrayList(networkSelectionStatusToNetworkIdMap.values()));
1164        }
1165    }
1166}
1167