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