WifiConfigManagerTest.java revision dc61ad4fe8a84909a288af50a8b187c98e2194b6
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        when(mWifiNative.removeNetwork(anyInt())).thenReturn(true);
715
716        switchUser(newUserId);
717        if (makeOneConfigEphemeral) {
718            // Verify that the ephemeral network configuration was removed.
719            assertNotNull(removedEphemeralConfig);
720            assertNull(mConfiguredNetworks.getForAllUsers(removedEphemeralConfig.networkId));
721            assertNull(lastSelectedConfigurationField.get(mWifiConfigManager));
722            verify(mWifiNative).removeNetwork(removedEphemeralConfig.networkId);
723            --expectedNumberOfConfigs;
724        } else {
725            assertNull(removedEphemeralConfig);
726        }
727
728        // Verify that the other network configurations were revealed/hidden and enabled/disabled as
729        // appropriate.
730        final Collection<WifiConfiguration> newConfigs = mConfiguredNetworks.valuesForAllUsers();
731        assertEquals(expectedNumberOfConfigs, newConfigs.size());
732        for (WifiConfiguration config : newConfigs) {
733            if (oldUserOnlyConfigs.contains(config)) {
734                verify(mWifiNative).disableNetwork(config.networkId);
735                assertEquals(WifiConfiguration.Status.DISABLED, config.status);
736            } else {
737                verify(mWifiNative, never()).disableNetwork(config.networkId);
738                if (neitherUserConfigs.contains(config)) {
739                    assertEquals(WifiConfiguration.Status.DISABLED, config.status);
740                } else {
741                    // Only enabled in networkSelection.
742                    assertTrue(config.getNetworkSelectionStatus().isNetworkEnabled());
743                }
744
745            }
746        }
747    }
748
749    /**
750     * Verifies that handleUserSwitch() behaves correctly when the user switch removes an ephemeral
751     * network configuration and reveals a private network configuration.
752     */
753    @Test
754    public void testHandleUserSwitchWithEphemeral() throws Exception {
755        verifyHandleUserSwitch(USER_IDS[2], USER_IDS[0], true);
756    }
757
758    /**
759     * Verifies that handleUserSwitch() behaves correctly when the user switch hides a private
760     * network configuration.
761     */
762    @Test
763    public void testHandleUserSwitchWithoutEphemeral() throws Exception {
764        verifyHandleUserSwitch(USER_IDS[0], USER_IDS[2], false);
765    }
766
767    @Test
768    public void testSaveLoadEapNetworks() {
769        testSaveLoadSingleEapNetwork("eap network", new EnterpriseConfig(Eap.TTLS)
770                .setPhase2(Phase2.MSCHAPV2)
771                .setIdentity("username", "password")
772                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0}));
773        testSaveLoadSingleEapNetwork("eap network", new EnterpriseConfig(Eap.TTLS)
774                .setPhase2(Phase2.MSCHAPV2)
775                .setIdentity("username", "password")
776                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT1, FakeKeys.CA_CERT0}));
777
778    }
779
780    private void testSaveLoadSingleEapNetwork(String ssid, EnterpriseConfig eapConfig) {
781        final HashMap<String, String> networkVariables = new HashMap<String, String>();
782        reset(mWifiNative);
783        when(mWifiNative.addNetwork()).thenReturn(0);
784        when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString())).thenAnswer(
785                new AnswerWithArguments() {
786                    public boolean answer(int netId, String name, String value) {
787                        // Verify that no wpa_supplicant variables were written for any other
788                        // network configurations.
789                        assertEquals(netId, 0);
790                        networkVariables.put(name, value);
791                        return true;
792                    }
793                });
794        when(mWifiNative.getNetworkVariable(anyInt(), anyString())).then(
795                new AnswerWithArguments() {
796                    public String answer(int netId, String name) {
797                        // Verify that no wpa_supplicant variables were read for any other
798                        // network configurations.
799                        assertEquals(netId, 0);
800                        return networkVariables.get(name);
801                    }
802                });
803        when(mWifiNative.setNetworkExtra(eq(0), anyString(), (Map<String, String>) anyObject()))
804                .thenReturn(true);
805
806        WifiConfiguration config = new WifiConfiguration();
807        config.SSID = ssid;
808        config.creatorUid = Process.WIFI_UID;
809        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
810        config.enterpriseConfig = eapConfig.enterpriseConfig;
811
812        // Store a network configuration.
813        mWifiConfigManager.saveNetwork(config, Process.WIFI_UID);
814
815        // Verify that wpa_supplicant variables were written correctly for the network
816        // configuration.
817        verify(mWifiNative).addNetwork();
818        assertEquals(eapConfig.eap,
819                unquote(networkVariables.get(WifiEnterpriseConfig.EAP_KEY)));
820        assertEquals(eapConfig.phase2,
821                unquote(networkVariables.get(WifiEnterpriseConfig.PHASE2_KEY)));
822        assertEquals(eapConfig.identity,
823                unquote(networkVariables.get(WifiEnterpriseConfig.IDENTITY_KEY)));
824        assertEquals(eapConfig.password,
825                unquote(networkVariables.get(WifiEnterpriseConfig.PASSWORD_KEY)));
826        assertSavedCaCerts(eapConfig,
827                unquote(networkVariables.get(WifiEnterpriseConfig.CA_CERT_KEY)));
828
829        // Prepare the scan result.
830        final String header = "network id / ssid / bssid / flags";
831        String networks = header + "\n" + Integer.toString(0) + "\t" + ssid + "\tany";
832        when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
833        when(mWifiNative.listNetworks(-1)).thenReturn(networks);
834
835        // Load back the configuration.
836        mWifiConfigManager.loadConfiguredNetworks();
837        List<WifiConfiguration> configs = mWifiConfigManager.getConfiguredNetworks();
838        assertEquals(1, configs.size());
839        WifiConfiguration loadedConfig = configs.get(0);
840        assertEquals(ssid, unquote(loadedConfig.SSID));
841        BitSet keyMgmt = new BitSet();
842        keyMgmt.set(KeyMgmt.WPA_EAP);
843        assertEquals(keyMgmt, loadedConfig.allowedKeyManagement);
844        assertEquals(eapConfig.enterpriseConfig.getEapMethod(),
845                loadedConfig.enterpriseConfig.getEapMethod());
846        assertEquals(eapConfig.enterpriseConfig.getPhase2Method(),
847                loadedConfig.enterpriseConfig.getPhase2Method());
848        assertEquals(eapConfig.enterpriseConfig.getIdentity(),
849                loadedConfig.enterpriseConfig.getIdentity());
850        assertEquals(eapConfig.enterpriseConfig.getPassword(),
851                loadedConfig.enterpriseConfig.getPassword());
852        asserCaCertsAliasesMatch(eapConfig.caCerts,
853                loadedConfig.enterpriseConfig.getCaCertificateAliases());
854    }
855
856    private String unquote(String value) {
857        if (value == null) {
858            return null;
859        }
860        int length = value.length();
861        if ((length > 1) && (value.charAt(0) == '"')
862                && (value.charAt(length - 1) == '"')) {
863            return value.substring(1, length - 1);
864        } else {
865            return value;
866        }
867    }
868
869    private void asserCaCertsAliasesMatch(X509Certificate[] certs, String[] aliases) {
870        assertEquals(certs.length, aliases.length);
871        List<String> aliasList = new ArrayList<String>(Arrays.asList(aliases));
872        try {
873            for (int i = 0; i < certs.length; i++) {
874                byte[] certPem = Credentials.convertToPem(certs[i]);
875                boolean found = false;
876                for (int j = 0; j < aliasList.size(); j++) {
877                    byte[] keystoreCert = mMockKeyStore.getKeyBlob(Process.WIFI_UID,
878                            Credentials.CA_CERTIFICATE + aliasList.get(j)).blob;
879                    if (Arrays.equals(keystoreCert, certPem)) {
880                        found = true;
881                        aliasList.remove(j);
882                        break;
883                    }
884                }
885                assertTrue(found);
886            }
887        } catch (CertificateEncodingException | IOException e) {
888            fail("Cannot convert CA certificate to encoded form.");
889        }
890    }
891
892    private void assertSavedCaCerts(EnterpriseConfig eapConfig, String caCertVariable) {
893        ArrayList<String> aliases = new ArrayList<String>();
894        if (TextUtils.isEmpty(caCertVariable)) {
895            // Do nothing.
896        } else if (caCertVariable.startsWith(WifiEnterpriseConfig.CA_CERT_PREFIX)) {
897            aliases.add(caCertVariable.substring(WifiEnterpriseConfig.CA_CERT_PREFIX.length()));
898        } else if (caCertVariable.startsWith(WifiEnterpriseConfig.KEYSTORES_URI)) {
899            String[] encodedAliases = TextUtils.split(
900                    caCertVariable.substring(WifiEnterpriseConfig.KEYSTORES_URI.length()),
901                    WifiEnterpriseConfig.CA_CERT_ALIAS_DELIMITER);
902            for (String encodedAlias : encodedAliases) {
903                String alias = WifiEnterpriseConfig.decodeCaCertificateAlias(encodedAlias);
904                assertTrue(alias.startsWith(Credentials.CA_CERTIFICATE));
905                aliases.add(alias.substring(Credentials.CA_CERTIFICATE.length()));
906            }
907        } else {
908            fail("Unrecognized ca_cert variable: " + caCertVariable);
909        }
910        asserCaCertsAliasesMatch(eapConfig.caCerts, aliases.toArray(new String[aliases.size()]));
911    }
912
913    private static class EnterpriseConfig {
914        public String eap;
915        public String phase2;
916        public String identity;
917        public String password;
918        public X509Certificate[] caCerts;
919        public WifiEnterpriseConfig enterpriseConfig;
920
921        public EnterpriseConfig(int eapMethod) {
922            enterpriseConfig = new WifiEnterpriseConfig();
923            enterpriseConfig.setEapMethod(eapMethod);
924            eap = Eap.strings[eapMethod];
925        }
926        public EnterpriseConfig setPhase2(int phase2Method) {
927            enterpriseConfig.setPhase2Method(phase2Method);
928            phase2 = "auth=" + Phase2.strings[phase2Method];
929            return this;
930        }
931        public EnterpriseConfig setIdentity(String identity, String password) {
932            enterpriseConfig.setIdentity(identity);
933            enterpriseConfig.setPassword(password);
934            this.identity = identity;
935            this.password = password;
936            return this;
937        }
938        public EnterpriseConfig setCaCerts(X509Certificate[] certs) {
939            enterpriseConfig.setCaCertificates(certs);
940            caCerts = certs;
941            return this;
942        }
943    }
944
945    /**
946     * Generates an array of unique random numbers below the specified maxValue.
947     * Values range from 0 to maxValue-1.
948     */
949    private static ArrayDeque<Integer> getUniqueRandomNumberValues(
950            int seed,
951            int maxValue,
952            int numValues) {
953        assertTrue(numValues <= maxValue);
954        Random rand = new Random(WifiTestUtil.getTestMethod().hashCode() + seed);
955        ArrayDeque<Integer> randomNumberList = new ArrayDeque<>();
956        for (int i = 0; i < numValues; i++) {
957            int num = rand.nextInt(maxValue);
958            while (randomNumberList.contains(num)) {
959                num = rand.nextInt(maxValue);
960            }
961            randomNumberList.push(num);
962        }
963        return randomNumberList;
964    }
965
966    /**
967     * Verifies that the networks in pnoNetworkList is sorted in the same order as the
968     * network in expectedNetworkIDOrder list.
969     */
970    private static void verifyPnoNetworkListOrder(
971            ArrayList<WifiNative.WifiPnoNetwork> pnoNetworkList,
972            ArrayList<Integer> expectedNetworkIdOrder) throws Exception  {
973        int i = 0;
974        for (WifiNative.WifiPnoNetwork pnoNetwork : pnoNetworkList) {
975            Log.i(TAG, "PNO Network List Index: " + i + ", networkID: " + pnoNetwork.networkId);
976            assertEquals("Expected network ID: " + pnoNetwork.networkId,
977                    pnoNetwork.networkId, expectedNetworkIdOrder.get(i++).intValue());
978        }
979    }
980
981    /**
982     * Verifies the retrieveDisconnectedWifiPnoNetworkList API. The test verifies that the list
983     * returned from the API is sorted as expected.
984     */
985    @Test
986    public void testDisconnectedWifiPnoNetworkListCreation() throws Exception {
987        addNetworks();
988
989        Random rand = new Random(WifiTestUtil.getTestMethod().hashCode());
990
991        // First assign random |numAssociation| values and verify that the list is sorted
992        // in descending order of |numAssociation| values. Keep NetworkSelectionStatus
993        // values constant.
994        for (int userId : USER_IDS) {
995            switchUser(userId);
996            TreeMap<Integer, Integer> numAssociationToNetworkIdMap =
997                    new TreeMap<>(Collections.reverseOrder());
998            ArrayDeque<Integer> numAssociationValues =
999                    getUniqueRandomNumberValues(
1000                            1, 10000, mConfiguredNetworks.valuesForCurrentUser().size());
1001            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1002                config.numAssociation = numAssociationValues.pop();
1003                config.priority = rand.nextInt(10000);
1004                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1005                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1006                numAssociationToNetworkIdMap.put(config.numAssociation, config.networkId);
1007                Log.i(TAG, "networkID: " + config.networkId + ", numAssociation: "
1008                        + config.numAssociation);
1009            }
1010            ArrayList<WifiNative.WifiPnoNetwork> pnoNetworkList =
1011                    mWifiConfigManager.retrieveDisconnectedWifiPnoNetworkList();
1012            verifyPnoNetworkListOrder(pnoNetworkList,
1013                    new ArrayList(numAssociationToNetworkIdMap.values()));
1014        }
1015
1016        // Assign random |priority| values and verify that the list is sorted in descending order
1017        // of |priority| values. Keep numAssociation/NetworkSelectionStatus values constant.
1018        for (int userId : USER_IDS) {
1019            switchUser(userId);
1020            TreeMap<Integer, Integer> priorityToNetworkIdMap =
1021                    new TreeMap<>(Collections.reverseOrder());
1022            ArrayDeque<Integer> priorityValues =
1023                    getUniqueRandomNumberValues(
1024                            2, 10000, mConfiguredNetworks.valuesForCurrentUser().size());
1025            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1026                config.numAssociation = 0;
1027                config.priority = priorityValues.pop();
1028                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1029                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1030                priorityToNetworkIdMap.put(config.priority, config.networkId);
1031                Log.i(TAG, "networkID: " + config.networkId + ", priority: " + config.priority);
1032            }
1033            ArrayList<WifiNative.WifiPnoNetwork> pnoNetworkList =
1034                    mWifiConfigManager.retrieveDisconnectedWifiPnoNetworkList();
1035            verifyPnoNetworkListOrder(pnoNetworkList,
1036                    new ArrayList(priorityToNetworkIdMap.values()));
1037        }
1038
1039        // Now assign random |NetworkSelectionStatus| values and verify that the list is sorted in
1040        // ascending order of |NetworkSelectionStatus| values.
1041        for (int userId : USER_IDS) {
1042            switchUser(userId);
1043            TreeMap<Integer, Integer> networkSelectionStatusToNetworkIdMap = new TreeMap<>();
1044            ArrayDeque<Integer> networkSelectionStatusValues =
1045                    getUniqueRandomNumberValues(
1046                            3,
1047                            WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_STATUS_MAX,
1048                            mConfiguredNetworks.valuesForCurrentUser().size());
1049            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1050                config.numAssociation = rand.nextInt(10000);
1051                config.priority = rand.nextInt(10000);
1052                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1053                        networkSelectionStatusValues.pop());
1054                networkSelectionStatusToNetworkIdMap.put(
1055                        config.getNetworkSelectionStatus().getNetworkSelectionStatus(),
1056                        config.networkId);
1057                Log.i(TAG, "networkID: " + config.networkId + ", NetworkSelectionStatus: "
1058                        + config.getNetworkSelectionStatus().getNetworkSelectionStatus());
1059            }
1060            ArrayList<WifiNative.WifiPnoNetwork> pnoNetworkList =
1061                    mWifiConfigManager.retrieveDisconnectedWifiPnoNetworkList();
1062            verifyPnoNetworkListOrder(pnoNetworkList,
1063                    new ArrayList(networkSelectionStatusToNetworkIdMap.values()));
1064        }
1065    }
1066
1067    /**
1068     * Verifies the retrieveConnectedWifiPnoNetworkList API. The test verifies that the list
1069     * returned from the API is sorted as expected.
1070     */
1071    @Test
1072    public void testConnectedWifiPnoNetworkListCreation() throws Exception {
1073        addNetworks();
1074
1075        Random rand = new Random(WifiTestUtil.getTestMethod().hashCode());
1076
1077        // First assign |lastSeen| values and verify that the list is sorted
1078        // in descending order of |lastSeen| values. Keep NetworkSelectionStatus
1079        // values constant.
1080        for (int userId : USER_IDS) {
1081            switchUser(userId);
1082            TreeMap<Boolean, Integer> lastSeenToNetworkIdMap =
1083                    new TreeMap<>(Collections.reverseOrder());
1084            ArrayDeque<Integer> lastSeenValues = getUniqueRandomNumberValues(1, 2, 2);
1085            if (mConfiguredNetworks.valuesForCurrentUser().size() > 2) continue;
1086            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1087                config.numAssociation = rand.nextInt(10000);
1088                config.priority = rand.nextInt(10000);
1089                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1090                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1091                boolean lastSeenValue = (lastSeenValues.pop()  == 1);
1092                config.getNetworkSelectionStatus().setSeenInLastQualifiedNetworkSelection(
1093                        lastSeenValue);
1094                lastSeenToNetworkIdMap.put(lastSeenValue, config.networkId);
1095                Log.i(TAG, "networkID: " + config.networkId + ", lastSeen: " + lastSeenValue);
1096            }
1097            ArrayList<WifiNative.WifiPnoNetwork> pnoNetworkList =
1098                    mWifiConfigManager.retrieveConnectedWifiPnoNetworkList();
1099            verifyPnoNetworkListOrder(pnoNetworkList,
1100                    new ArrayList(lastSeenToNetworkIdMap.values()));
1101        }
1102
1103        // Assign random |numAssociation| values and verify that the list is sorted
1104        // in descending order of |numAssociation| values. Keep NetworkSelectionStatus/lastSeen
1105        // values constant.
1106        for (int userId : USER_IDS) {
1107            switchUser(userId);
1108            TreeMap<Integer, Integer> numAssociationToNetworkIdMap =
1109                    new TreeMap<>(Collections.reverseOrder());
1110            ArrayDeque<Integer> numAssociationValues =
1111                    getUniqueRandomNumberValues(
1112                            1, 10000, mConfiguredNetworks.valuesForCurrentUser().size());
1113            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1114                config.numAssociation = numAssociationValues.pop();
1115                config.priority = rand.nextInt(10000);
1116                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1117                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1118                config.getNetworkSelectionStatus().setSeenInLastQualifiedNetworkSelection(true);
1119                numAssociationToNetworkIdMap.put(config.numAssociation, config.networkId);
1120                Log.i(TAG, "networkID: " + config.networkId + ", numAssociation: "
1121                        + config.numAssociation);
1122            }
1123            ArrayList<WifiNative.WifiPnoNetwork> pnoNetworkList =
1124                    mWifiConfigManager.retrieveConnectedWifiPnoNetworkList();
1125            verifyPnoNetworkListOrder(pnoNetworkList,
1126                    new ArrayList(numAssociationToNetworkIdMap.values()));
1127        }
1128
1129        // Now assign random |NetworkSelectionStatus| values and verify that the list is sorted in
1130        // ascending order of |NetworkSelectionStatus| values.
1131        for (int userId : USER_IDS) {
1132            switchUser(userId);
1133            TreeMap<Integer, Integer> networkSelectionStatusToNetworkIdMap = new TreeMap<>();
1134            ArrayDeque<Integer> networkSelectionStatusValues =
1135                    getUniqueRandomNumberValues(
1136                            3,
1137                            WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_STATUS_MAX,
1138                            mConfiguredNetworks.valuesForCurrentUser().size());
1139            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1140                config.numAssociation = rand.nextInt(10000);
1141                config.priority = rand.nextInt(10000);
1142                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1143                        networkSelectionStatusValues.pop());
1144                networkSelectionStatusToNetworkIdMap.put(
1145                        config.getNetworkSelectionStatus().getNetworkSelectionStatus(),
1146                        config.networkId);
1147                Log.i(TAG, "networkID: " + config.networkId + ", NetworkSelectionStatus: "
1148                        + config.getNetworkSelectionStatus().getNetworkSelectionStatus());
1149            }
1150            ArrayList<WifiNative.WifiPnoNetwork> pnoNetworkList =
1151                    mWifiConfigManager.retrieveConnectedWifiPnoNetworkList();
1152            verifyPnoNetworkListOrder(pnoNetworkList,
1153                    new ArrayList(networkSelectionStatusToNetworkIdMap.values()));
1154        }
1155    }
1156}
1157