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