WifiConfigManagerTest.java revision 2d65b9aaaa740ecf66bf4734c12aea3df88e352a
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.os.Process;
46import android.os.UserHandle;
47import android.os.UserManager;
48import android.security.Credentials;
49import android.support.test.InstrumentationRegistry;
50import android.test.suitebuilder.annotation.SmallTest;
51import android.text.TextUtils;
52import android.util.Log;
53import android.util.SparseArray;
54
55import com.android.server.net.DelayedDiskWrite;
56import com.android.server.wifi.MockAnswerUtil.AnswerWithArguments;
57import com.android.server.wifi.hotspot2.omadm.PasspointManagementObjectManager;
58import com.android.server.wifi.hotspot2.pps.Credential;
59import com.android.server.wifi.hotspot2.pps.HomeSP;
60
61import org.junit.Before;
62import org.junit.Test;
63import org.mockito.Mock;
64import org.mockito.MockitoAnnotations;
65
66import java.io.ByteArrayInputStream;
67import java.io.ByteArrayOutputStream;
68import java.io.DataInputStream;
69import java.io.DataOutputStream;
70import java.io.EOFException;
71import java.io.File;
72import java.io.FileOutputStream;
73import java.io.IOException;
74import java.lang.reflect.Field;
75import java.math.BigInteger;
76import java.security.cert.CertificateEncodingException;
77import java.security.cert.X509Certificate;
78import java.util.ArrayDeque;
79import java.util.ArrayList;
80import java.util.Arrays;
81import java.util.BitSet;
82import java.util.Collection;
83import java.util.Collections;
84import java.util.HashMap;
85import java.util.HashSet;
86import java.util.List;
87import java.util.Map;
88import java.util.Random;
89import java.util.Set;
90import java.util.TreeMap;
91
92/**
93 * Unit tests for {@link com.android.server.wifi.WifiConfigManager}.
94 */
95@SmallTest
96public class WifiConfigManagerTest {
97    private static final List<WifiConfiguration> CONFIGS = Arrays.asList(
98            WifiConfigurationTestUtil.generateWifiConfig(
99                    0, 1000000, "\"red\"", true, true, null, null),
100            WifiConfigurationTestUtil.generateWifiConfig(
101                    1, 1000001, "\"green\"", true, true, "example.com", "Green"),
102            WifiConfigurationTestUtil.generateWifiConfig(
103                    2, 1100000, "\"blue\"", false, true, "example.org", "Blue"),
104            WifiConfigurationTestUtil.generateWifiConfig(
105                    3, 1200000, "\"cyan\"", false, true, null, null));
106
107    private static final int[] USER_IDS = {0, 10, 11};
108    private static final int MANAGED_PROFILE_USER_ID = 12;
109    private static final int MANAGED_PROFILE_PARENT_USER_ID = 0;
110    private static final SparseArray<List<UserInfo>> USER_PROFILES = new SparseArray<>();
111    static {
112        USER_PROFILES.put(0, Arrays.asList(new UserInfo(0, "Owner", 0),
113                new UserInfo(12, "Managed Profile", 0)));
114        USER_PROFILES.put(10, Arrays.asList(new UserInfo(10, "Alice", 0)));
115        USER_PROFILES.put(11, Arrays.asList(new UserInfo(11, "Bob", 0)));
116    }
117
118    private static final Map<Integer, List<WifiConfiguration>> VISIBLE_CONFIGS = new HashMap<>();
119    static {
120        for (int userId : USER_IDS) {
121            List<WifiConfiguration> configs = new ArrayList<>();
122            for (int i = 0; i < CONFIGS.size(); ++i) {
123                if (WifiConfigurationUtil.isVisibleToAnyProfile(CONFIGS.get(i),
124                        USER_PROFILES.get(userId))) {
125                    configs.add(CONFIGS.get(i));
126                }
127            }
128            VISIBLE_CONFIGS.put(userId, configs);
129        }
130    }
131
132    public static final String TAG = "WifiConfigManagerTest";
133    @Mock private Context mContext;
134    @Mock private WifiStateMachine mWifiStateMachine;
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(mWifiStateMachine.getCurrentUserId()).thenReturn(UserHandle.USER_SYSTEM);
159        when(mWifiStateMachine.getCurrentUserProfiles())
160                .thenReturn(USER_PROFILES.get(UserHandle.USER_SYSTEM));
161
162        for (int userId : USER_IDS) {
163            when(mUserManager.getProfiles(userId)).thenReturn(USER_PROFILES.get(userId));
164        }
165
166        mMockKeyStore = new MockKeyStore();
167
168        mWifiConfigManager = new WifiConfigManager(mContext, mWifiStateMachine, mWifiNative,
169                mFrameworkFacade, mClock, mUserManager, mMockKeyStore.createMock());
170
171        final Field configuredNetworksField =
172                WifiConfigManager.class.getDeclaredField("mConfiguredNetworks");
173        configuredNetworksField.setAccessible(true);
174        mConfiguredNetworks = (ConfigurationMap) configuredNetworksField.get(mWifiConfigManager);
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                mNetworkHistoryBytes = buffer.toByteArray();
184            }}).when(mWriter).write(anyString(), (DelayedDiskWrite.Writer) anyObject());
185        final Field writerField = WifiConfigManager.class.getDeclaredField("mWriter");
186        writerField.setAccessible(true);
187        writerField.set(mWifiConfigManager, mWriter);
188        final Field networkHistoryField =
189                WifiConfigManager.class.getDeclaredField("mWifiNetworkHistory");
190        networkHistoryField.setAccessible(true);
191        WifiNetworkHistory wifiNetworkHistory =
192                (WifiNetworkHistory) networkHistoryField.get(mWifiConfigManager);
193        final Field networkHistoryWriterField =
194                WifiNetworkHistory.class.getDeclaredField("mWriter");
195        networkHistoryWriterField.setAccessible(true);
196        networkHistoryWriterField.set(wifiNetworkHistory, mWriter);
197
198        when(mMOManager.isEnabled()).thenReturn(true);
199        final Field moManagerField = WifiConfigManager.class.getDeclaredField("mMOManager");
200        moManagerField.setAccessible(true);
201        moManagerField.set(mWifiConfigManager, mMOManager);
202    }
203
204    private void switchUser(int newUserId) {
205        when(mWifiStateMachine.getCurrentUserId()).thenReturn(newUserId);
206        when(mWifiStateMachine.getCurrentUserProfiles())
207                .thenReturn(USER_PROFILES.get(newUserId));
208        mWifiConfigManager.handleUserSwitch();
209    }
210
211    private void switchUserToCreatorOrParentOf(WifiConfiguration config) {
212        final int creatorUserId = UserHandle.getUserId(config.creatorUid);
213        if (creatorUserId == MANAGED_PROFILE_USER_ID) {
214            switchUser(MANAGED_PROFILE_PARENT_USER_ID);
215        } else {
216            switchUser(creatorUserId);
217        }
218    }
219
220    private void addNetworks() throws Exception {
221        final int originalUserId = mWifiStateMachine.getCurrentUserId();
222
223        when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString())).thenReturn(true);
224        when(mWifiNative.setNetworkExtra(anyInt(), anyString(), (Map<String, String>) anyObject()))
225                .thenReturn(true);
226        for (int i = 0; i < CONFIGS.size(); ++i) {
227            assertEquals(i, CONFIGS.get(i).networkId);
228            switchUserToCreatorOrParentOf(CONFIGS.get(i));
229            final WifiConfiguration config = new WifiConfiguration(CONFIGS.get(i));
230            config.networkId = -1;
231            when(mWifiNative.addNetwork()).thenReturn(i);
232            when(mWifiNative.getNetworkVariable(i, WifiConfiguration.ssidVarName))
233                .thenReturn(encodeConfigSSID(CONFIGS.get(i)));
234            mWifiConfigManager.saveNetwork(config, config.creatorUid);
235        }
236
237        switchUser(originalUserId);
238    }
239
240    private String encodeConfigSSID(WifiConfiguration config) throws Exception {
241        return new BigInteger(1, config.SSID.substring(1, config.SSID.length() - 1)
242                .getBytes("UTF-8")).toString(16);
243    }
244
245    /**
246     * Verifies that getConfiguredNetworksSize() returns the number of network configurations
247     * visible to the current user.
248     */
249    @Test
250    public void testGetConfiguredNetworksSize() throws Exception {
251        addNetworks();
252        for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
253            switchUser(entry.getKey());
254            assertEquals(entry.getValue().size(), mWifiConfigManager.getConfiguredNetworksSize());
255        }
256    }
257
258    private void verifyNetworkConfig(WifiConfiguration expectedConfig,
259            WifiConfiguration actualConfig) {
260        assertNotNull(actualConfig);
261        assertEquals(expectedConfig.SSID, actualConfig.SSID);
262        assertEquals(expectedConfig.FQDN, actualConfig.FQDN);
263        assertEquals(expectedConfig.providerFriendlyName,
264                actualConfig.providerFriendlyName);
265        assertEquals(expectedConfig.configKey(), actualConfig.configKey(false));
266    }
267
268    private void verifyNetworkConfigs(Collection<WifiConfiguration> expectedConfigs,
269            Collection<WifiConfiguration> actualConfigs) {
270        assertEquals(expectedConfigs.size(), actualConfigs.size());
271        for (WifiConfiguration expectedConfig : expectedConfigs) {
272            WifiConfiguration actualConfig = null;
273            // Find the network configuration to test (assume that |actualConfigs| contains them in
274            // undefined order).
275            for (final WifiConfiguration candidate : actualConfigs) {
276                if (candidate.networkId == expectedConfig.networkId) {
277                    actualConfig = candidate;
278                    break;
279                }
280            }
281            verifyNetworkConfig(expectedConfig, actualConfig);
282        }
283    }
284
285    /**
286     * Verifies that getConfiguredNetworksSize() returns the network configurations visible to the
287     * current user.
288     */
289    @Test
290    public void testGetConfiguredNetworks() throws Exception {
291        addNetworks();
292        for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
293            switchUser(entry.getKey());
294            verifyNetworkConfigs(entry.getValue(), mWifiConfigManager.getConfiguredNetworks());
295        }
296    }
297
298    /**
299     * Verifies that getPrivilegedConfiguredNetworks() returns the network configurations visible to
300     * the current user.
301     */
302    @Test
303    public void testGetPrivilegedConfiguredNetworks() throws Exception {
304        addNetworks();
305        for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
306            switchUser(entry.getKey());
307            verifyNetworkConfigs(entry.getValue(),
308                    mWifiConfigManager.getPrivilegedConfiguredNetworks());
309        }
310    }
311
312    /**
313     * Verifies that getWifiConfiguration(int netId) can be used to access network configurations
314     * visible to the current user only.
315     */
316    @Test
317    public void testGetWifiConfigurationByNetworkId() throws Exception {
318        addNetworks();
319        for (int userId : USER_IDS) {
320            switchUser(userId);
321            for (WifiConfiguration expectedConfig: CONFIGS) {
322                final WifiConfiguration actualConfig =
323                        mWifiConfigManager.getWifiConfiguration(expectedConfig.networkId);
324                if (WifiConfigurationUtil.isVisibleToAnyProfile(expectedConfig,
325                        USER_PROFILES.get(userId))) {
326                    verifyNetworkConfig(expectedConfig, actualConfig);
327                } else {
328                    assertNull(actualConfig);
329                }
330            }
331        }
332    }
333
334    /**
335     * Verifies that getWifiConfiguration(String key) can be used to access network configurations
336     * visible to the current user only.
337     */
338    @Test
339    public void testGetWifiConfigurationByConfigKey() throws Exception {
340        addNetworks();
341        for (int userId : USER_IDS) {
342            switchUser(userId);
343            for (WifiConfiguration expectedConfig: CONFIGS) {
344                final WifiConfiguration actualConfig =
345                        mWifiConfigManager.getWifiConfiguration(expectedConfig.configKey());
346                if (WifiConfigurationUtil.isVisibleToAnyProfile(expectedConfig,
347                        USER_PROFILES.get(userId))) {
348                    verifyNetworkConfig(expectedConfig, actualConfig);
349                } else {
350                    assertNull(actualConfig);
351                }
352            }
353        }
354    }
355
356    /**
357     * Verifies that enableAllNetworks() enables all temporarily disabled network configurations
358     * visible to the current user.
359     */
360    @Test
361    public void testEnableAllNetworks() throws Exception {
362        addNetworks();
363        for (int userId : USER_IDS) {
364            switchUser(userId);
365
366            for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
367                final WifiConfiguration.NetworkSelectionStatus status =
368                        config.getNetworkSelectionStatus();
369                status.setNetworkSelectionStatus(WifiConfiguration.NetworkSelectionStatus
370                        .NETWORK_SELECTION_TEMPORARY_DISABLED);
371                status.setNetworkSelectionDisableReason(
372                        WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE);
373                status.setDisableTime(System.currentTimeMillis() - 60 * 60 * 1000);
374            }
375
376            mWifiConfigManager.enableAllNetworks();
377
378            for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
379                assertEquals(WifiConfigurationUtil.isVisibleToAnyProfile(config,
380                        USER_PROFILES.get(userId)),
381                        config.getNetworkSelectionStatus().isNetworkEnabled());
382            }
383        }
384    }
385
386    /**
387     * Verifies that selectNetwork() disables all network configurations visible to the current user
388     * except the selected one.
389     */
390    @Test
391    public void testSelectNetwork() throws Exception {
392        addNetworks();
393
394        for (int userId : USER_IDS) {
395            switchUser(userId);
396
397            for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
398                // Enable all network configurations.
399                for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) {
400                    config2.status = WifiConfiguration.Status.ENABLED;
401                }
402
403                // Try to select a network configuration.
404                reset(mWifiNative);
405                when(mWifiNative.selectNetwork(config.networkId)).thenReturn(true);
406                final boolean success =
407                        mWifiConfigManager.selectNetwork(config, false, config.creatorUid);
408                if (!WifiConfigurationUtil.isVisibleToAnyProfile(config,
409                        USER_PROFILES.get(userId))) {
410                    // If the network configuration is not visible to the current user, verify that
411                    // nothing changed.
412                    assertFalse(success);
413                    verify(mWifiNative, never()).selectNetwork(anyInt());
414                    verify(mWifiNative, never()).enableNetwork(anyInt());
415                    for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) {
416                        assertEquals(WifiConfiguration.Status.ENABLED, config2.status);
417                    }
418                } else {
419                    // If the network configuration is visible to the current user, verify that it
420                    // was enabled and all other network configurations visible to the user were
421                    // disabled.
422                    assertTrue(success);
423                    verify(mWifiNative).selectNetwork(config.networkId);
424                    verify(mWifiNative, never()).selectNetwork(intThat(not(config.networkId)));
425                    verify(mWifiNative, never()).enableNetwork(config.networkId);
426                    verify(mWifiNative, never()).enableNetwork(intThat(not(config.networkId)));
427                    for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) {
428                        if (WifiConfigurationUtil.isVisibleToAnyProfile(config2,
429                                USER_PROFILES.get(userId))
430                                && config2.networkId != config.networkId) {
431                            assertEquals(WifiConfiguration.Status.DISABLED, config2.status);
432                        } else {
433                            assertEquals(WifiConfiguration.Status.ENABLED, config2.status);
434                        }
435                    }
436                }
437            }
438        }
439    }
440
441    /**
442     * Verifies that saveNetwork() correctly stores a network configuration in wpa_supplicant
443     * variables and the networkHistory.txt file.
444     * TODO: Test all variables. Currently, only the following variables are tested:
445     * - In the wpa_supplicant: "ssid", "id_str"
446     * - In networkHistory.txt: "CONFIG", "CREATOR_UID_KEY", "SHARED"
447     */
448    private void verifySaveNetwork(int network) throws Exception {
449        // Switch to the correct user.
450        switchUserToCreatorOrParentOf(CONFIGS.get(network));
451
452        // Set up wpa_supplicant.
453        when(mWifiNative.addNetwork()).thenReturn(0);
454        when(mWifiNative.setNetworkVariable(eq(network), anyString(), anyString()))
455                .thenReturn(true);
456        when(mWifiNative.setNetworkExtra(eq(network), anyString(),
457                (Map<String, String>) anyObject())).thenReturn(true);
458        when(mWifiNative.getNetworkVariable(network, WifiConfiguration.ssidVarName))
459                .thenReturn(encodeConfigSSID(CONFIGS.get(network)));
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 no wpa_supplicant variables were read or written for any other network
477        // configurations.
478        verify(mWifiNative, never()).setNetworkExtra(intThat(not(network)), anyString(),
479                (Map<String, String>) anyObject());
480        verify(mWifiNative, never()).setNetworkVariable(intThat(not(network)), anyString(),
481                anyString());
482        verify(mWifiNative, never()).getNetworkVariable(intThat(not(network)), anyString());
483
484        // Parse networkHistory.txt.
485        assertNotNull(mNetworkHistoryBytes);
486        final DataInputStream stream =
487                new DataInputStream(new ByteArrayInputStream(mNetworkHistoryBytes));
488        List<String> keys = new ArrayList<>();
489        List<String> values = new ArrayList<>();
490        try {
491            while (true) {
492                final String[] tokens = stream.readUTF().split(":", 2);
493                if (tokens.length == 2) {
494                    keys.add(tokens[0].trim());
495                    values.add(tokens[1].trim());
496                }
497            }
498        } catch (EOFException e) {
499            // Ignore. This is expected.
500        }
501
502        // Verify that a networkHistory.txt entry was written correctly for the network
503        // configuration.
504        assertTrue(keys.size() >= 3);
505        assertEquals(WifiNetworkHistory.CONFIG_KEY, keys.get(0));
506        assertEquals(CONFIGS.get(network).configKey(), values.get(0));
507        final int creatorUidIndex = keys.indexOf(WifiNetworkHistory.CREATOR_UID_KEY);
508        assertTrue(creatorUidIndex != -1);
509        assertEquals(Integer.toString(CONFIGS.get(network).creatorUid),
510                values.get(creatorUidIndex));
511        final int sharedIndex = keys.indexOf(WifiNetworkHistory.SHARED_KEY);
512        assertTrue(sharedIndex != -1);
513        assertEquals(Boolean.toString(CONFIGS.get(network).shared), values.get(sharedIndex));
514
515        // Verify that no networkHistory.txt entries were written for any other network
516        // configurations.
517        final int lastConfigIndex = keys.lastIndexOf(WifiNetworkHistory.CONFIG_KEY);
518        assertEquals(0, lastConfigIndex);
519    }
520
521    /**
522     * Verifies that saveNetwork() correctly stores a regular network configuration.
523     */
524    @Test
525    public void testSaveNetworkRegular() throws Exception {
526        verifySaveNetwork(0);
527    }
528
529    /**
530     * Verifies that saveNetwork() correctly stores a HotSpot 2.0 network configuration.
531     */
532    @Test
533    public void testSaveNetworkHotspot20() throws Exception {
534        verifySaveNetwork(1);
535    }
536
537    /**
538     * Verifies that saveNetwork() correctly stores a private network configuration.
539     */
540    @Test
541    public void testSaveNetworkPrivate() throws Exception {
542        verifySaveNetwork(2);
543    }
544
545    /**
546     * Verifies that loadConfiguredNetworks() correctly reads data from the wpa_supplicant, the
547     * networkHistory.txt file and the MOManager, correlating the three sources based on the
548     * configKey and the FQDN for HotSpot 2.0 networks.
549     * TODO: Test all variables. Currently, only the following variables are tested:
550     * - In the wpa_supplicant: "ssid", "id_str"
551     * - In networkHistory.txt: "CONFIG", "CREATOR_UID_KEY", "SHARED"
552     */
553    @Test
554    public void testLoadConfiguredNetworks() throws Exception {
555        // Set up list of network configurations returned by wpa_supplicant.
556        final String header = "network id / ssid / bssid / flags";
557        String networks = header;
558        for (WifiConfiguration config : CONFIGS) {
559            networks += "\n" + Integer.toString(config.networkId) + "\t" + config.SSID + "\tany";
560        }
561        when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
562        when(mWifiNative.listNetworks(-1)).thenReturn(networks);
563
564        // Set up variables returned by wpa_supplicant for the individual network configurations.
565        for (int i = 0; i < CONFIGS.size(); ++i) {
566            when(mWifiNative.getNetworkVariable(i, WifiConfiguration.ssidVarName))
567                .thenReturn(encodeConfigSSID(CONFIGS.get(i)));
568        }
569        // Legacy regular network configuration: No "id_str".
570        when(mWifiNative.getNetworkExtra(0, WifiConfigStore.ID_STRING_VAR_NAME))
571            .thenReturn(null);
572        // Legacy Hotspot 2.0 network configuration: Quoted FQDN in "id_str".
573        when(mWifiNative.getNetworkExtra(1, WifiConfigStore.ID_STRING_VAR_NAME))
574            .thenReturn(null);
575        when(mWifiNative.getNetworkVariable(1, WifiConfigStore.ID_STRING_VAR_NAME))
576            .thenReturn('"' + CONFIGS.get(1).FQDN + '"');
577        // Up-to-date Hotspot 2.0 network configuration: Metadata in "id_str".
578        Map<String, String> metadata = new HashMap<String, String>();
579        metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(2).configKey());
580        metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
581                Integer.toString(CONFIGS.get(2).creatorUid));
582        metadata.put(WifiConfigStore.ID_STRING_KEY_FQDN, CONFIGS.get(2).FQDN);
583        when(mWifiNative.getNetworkExtra(2, WifiConfigStore.ID_STRING_VAR_NAME))
584            .thenReturn(metadata);
585        // Up-to-date regular network configuration: Metadata in "id_str".
586        metadata = new HashMap<String, String>();
587        metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(3).configKey());
588        metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
589                Integer.toString(CONFIGS.get(3).creatorUid));
590        when(mWifiNative.getNetworkExtra(3, WifiConfigStore.ID_STRING_VAR_NAME))
591            .thenReturn(metadata);
592
593        // Set up networkHistory.txt file.
594        final File file = File.createTempFile("networkHistory.txt", null);
595        file.deleteOnExit();
596
597        Field wifiNetworkHistoryConfigFile =
598                WifiNetworkHistory.class.getDeclaredField("NETWORK_HISTORY_CONFIG_FILE");
599        wifiNetworkHistoryConfigFile.setAccessible(true);
600        wifiNetworkHistoryConfigFile.set(null, file.getAbsolutePath());
601
602        final DataOutputStream stream = new DataOutputStream(new FileOutputStream(file));
603        for (WifiConfiguration config : CONFIGS) {
604            stream.writeUTF(WifiNetworkHistory.CONFIG_KEY + ":  " + config.configKey() + '\n');
605            stream.writeUTF(WifiNetworkHistory.CREATOR_UID_KEY + ":  "
606                    + Integer.toString(config.creatorUid) + '\n');
607            stream.writeUTF(WifiNetworkHistory.SHARED_KEY + ":  "
608                    + Boolean.toString(config.shared) + '\n');
609        }
610        stream.close();
611
612        // Set up list of home service providers returned by MOManager.
613        final List<HomeSP> homeSPs = new ArrayList<HomeSP>();
614        for (WifiConfiguration config : CONFIGS) {
615            if (config.FQDN != null) {
616                homeSPs.add(new HomeSP(null, config.FQDN, new HashSet<Long>(),
617                        new HashSet<String>(),
618                        new HashSet<Long>(), new ArrayList<Long>(),
619                        config.providerFriendlyName, null,
620                        new Credential(0, 0, null, false, null, null),
621                        null, 0, null, null, null, 0));
622            }
623        }
624        when(mMOManager.loadAllSPs()).thenReturn(homeSPs);
625
626        // Load network configurations.
627        mWifiConfigManager.loadConfiguredNetworks();
628
629        // Verify that network configurations were loaded and correlated correctly across the three
630        // sources.
631        verifyNetworkConfigs(CONFIGS, mConfiguredNetworks.valuesForAllUsers());
632    }
633
634    /**
635     * Verifies that loadConfiguredNetworks() correctly handles duplicates when reading network
636     * configurations from the wpa_supplicant: The second configuration overwrites the first.
637     */
638    @Test
639    public void testLoadConfiguredNetworksEliminatesDuplicates() throws Exception {
640        final WifiConfiguration config = new WifiConfiguration(CONFIGS.get(0));
641        config.networkId = 1;
642
643        // Set up list of network configurations returned by wpa_supplicant. The two configurations
644        // are identical except for their network IDs.
645        final String header = "network id / ssid / bssid / flags";
646        final String networks =
647                header + "\n0\t" + config.SSID + "\tany\n1\t" + config.SSID + "\tany";
648        when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
649        when(mWifiNative.listNetworks(-1)).thenReturn(networks);
650
651        // Set up variables returned by wpa_supplicant.
652        when(mWifiNative.getNetworkVariable(anyInt(), eq(WifiConfiguration.ssidVarName)))
653            .thenReturn(encodeConfigSSID(config));
654        final Map<String, String> metadata = new HashMap<String, String>();
655        metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, config.configKey());
656        metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
657                Integer.toString(config.creatorUid));
658        when(mWifiNative.getNetworkExtra(anyInt(), eq(WifiConfigStore.ID_STRING_VAR_NAME)))
659            .thenReturn(metadata);
660
661        // Load network configurations.
662        mWifiConfigManager.loadConfiguredNetworks();
663
664        // Verify that the second network configuration (network ID 1) overwrote the first (network
665        // ID 0).
666        verifyNetworkConfigs(Arrays.asList(config), mConfiguredNetworks.valuesForAllUsers());
667    }
668
669    /**
670     * Verifies that handleUserSwitch() removes ephemeral network configurations, disables network
671     * configurations that should no longer be visible and enables network configurations that
672     * should become visible.
673     */
674    private void verifyHandleUserSwitch(int oldUserId, int newUserId,
675            boolean makeOneConfigEphemeral) throws Exception {
676        addNetworks();
677        switchUser(oldUserId);
678
679        reset(mWifiNative);
680        final Field lastSelectedConfigurationField =
681                WifiConfigManager.class.getDeclaredField("lastSelectedConfiguration");
682        lastSelectedConfigurationField.setAccessible(true);
683        WifiConfiguration removedEphemeralConfig = null;
684        final Set<WifiConfiguration> oldUserOnlyConfigs = new HashSet<>();
685        final Set<WifiConfiguration> newUserOnlyConfigs = new HashSet<>();
686        final Set<WifiConfiguration> neitherUserConfigs = new HashSet<>();
687        final Collection<WifiConfiguration> oldConfigs = mConfiguredNetworks.valuesForAllUsers();
688        int expectedNumberOfConfigs = oldConfigs.size();
689        for (WifiConfiguration config : oldConfigs) {
690            if (WifiConfigurationUtil.isVisibleToAnyProfile(config, USER_PROFILES.get(oldUserId))) {
691                config.status = WifiConfiguration.Status.ENABLED;
692                if (WifiConfigurationUtil.isVisibleToAnyProfile(config,
693                        USER_PROFILES.get(newUserId))) {
694                    if (makeOneConfigEphemeral && removedEphemeralConfig == null) {
695                        config.ephemeral = true;
696                        lastSelectedConfigurationField.set(mWifiConfigManager, config.configKey());
697                        removedEphemeralConfig = config;
698                    }
699                } else {
700                    oldUserOnlyConfigs.add(config);
701                }
702            } else {
703                config.status = WifiConfiguration.Status.DISABLED;
704                if (WifiConfigurationUtil.isVisibleToAnyProfile(config,
705                        USER_PROFILES.get(newUserId))) {
706                    newUserOnlyConfigs.add(config);
707                } else {
708                    neitherUserConfigs.add(config);
709                }
710            }
711        }
712
713        when(mWifiNative.disableNetwork(anyInt())).thenReturn(true);
714
715        switchUser(newUserId);
716        if (makeOneConfigEphemeral) {
717            // Verify that the ephemeral network configuration was removed.
718            assertNotNull(removedEphemeralConfig);
719            assertNull(mConfiguredNetworks.getForAllUsers(removedEphemeralConfig.networkId));
720            assertNull(lastSelectedConfigurationField.get(mWifiConfigManager));
721            verify(mWifiNative).removeNetwork(removedEphemeralConfig.networkId);
722            --expectedNumberOfConfigs;
723        } else {
724            assertNull(removedEphemeralConfig);
725        }
726
727        // Verify that the other network configurations were revealed/hidden and enabled/disabled as
728        // appropriate.
729        final Collection<WifiConfiguration> newConfigs = mConfiguredNetworks.valuesForAllUsers();
730        assertEquals(expectedNumberOfConfigs, newConfigs.size());
731        for (WifiConfiguration config : newConfigs) {
732            if (oldUserOnlyConfigs.contains(config)) {
733                verify(mWifiNative).disableNetwork(config.networkId);
734                assertEquals(WifiConfiguration.Status.DISABLED, config.status);
735            } else {
736                verify(mWifiNative, never()).disableNetwork(config.networkId);
737                if (neitherUserConfigs.contains(config)) {
738                    assertEquals(WifiConfiguration.Status.DISABLED, config.status);
739                } else {
740                    // Only enabled in networkSelection.
741                    assertTrue(config.getNetworkSelectionStatus().isNetworkEnabled());
742                }
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        mWifiConfigManager.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        mWifiConfigManager.loadConfiguredNetworks();
836        List<WifiConfiguration> configs = mWifiConfigManager.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                    mWifiConfigManager.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                    mWifiConfigManager.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                    mWifiConfigManager.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                    mWifiConfigManager.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                    mWifiConfigManager.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                    mWifiConfigManager.retrieveConnectedWifiPnoNetworkList();
1151            verifyPnoNetworkListOrder(pnoNetworkList,
1152                    new ArrayList(networkSelectionStatusToNetworkIdMap.values()));
1153        }
1154    }
1155}
1156