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