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