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