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