WifiConfigManagerTest.java revision 93332917bf29ddbe853a495816e486150f49da40
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.AuthAlgorithm;
42import android.net.wifi.WifiConfiguration.GroupCipher;
43import android.net.wifi.WifiConfiguration.KeyMgmt;
44import android.net.wifi.WifiConfiguration.PairwiseCipher;
45import android.net.wifi.WifiConfiguration.Protocol;
46import android.net.wifi.WifiEnterpriseConfig;
47import android.net.wifi.WifiEnterpriseConfig.Eap;
48import android.net.wifi.WifiEnterpriseConfig.Phase2;
49import android.net.wifi.WifiScanner;
50import android.os.Process;
51import android.os.UserHandle;
52import android.os.UserManager;
53import android.security.Credentials;
54import android.support.test.InstrumentationRegistry;
55import android.test.suitebuilder.annotation.SmallTest;
56import android.text.TextUtils;
57import android.util.Log;
58import android.util.SparseArray;
59
60import com.android.server.net.DelayedDiskWrite;
61import com.android.server.wifi.MockAnswerUtil.AnswerWithArguments;
62import com.android.server.wifi.hotspot2.omadm.PasspointManagementObjectManager;
63import com.android.server.wifi.hotspot2.pps.Credential;
64import com.android.server.wifi.hotspot2.pps.HomeSP;
65
66import org.junit.Before;
67import org.junit.Test;
68import org.mockito.Mock;
69import org.mockito.MockitoAnnotations;
70
71import java.io.ByteArrayInputStream;
72import java.io.ByteArrayOutputStream;
73import java.io.DataInputStream;
74import java.io.DataOutputStream;
75import java.io.EOFException;
76import java.io.File;
77import java.io.FileOutputStream;
78import java.io.IOException;
79import java.lang.reflect.Field;
80import java.math.BigInteger;
81import java.security.cert.CertificateEncodingException;
82import java.security.cert.X509Certificate;
83import java.util.ArrayDeque;
84import java.util.ArrayList;
85import java.util.Arrays;
86import java.util.BitSet;
87import java.util.Collection;
88import java.util.Collections;
89import java.util.HashMap;
90import java.util.HashSet;
91import java.util.List;
92import java.util.Map;
93import java.util.Random;
94import java.util.Set;
95import java.util.TreeMap;
96
97/**
98 * Unit tests for {@link com.android.server.wifi.WifiConfigManager}.
99 */
100@SmallTest
101public class WifiConfigManagerTest {
102    private static final List<WifiConfiguration> CONFIGS = Arrays.asList(
103            WifiConfigurationTestUtil.generateWifiConfig(
104                    0, 1000000, "\"red\"", true, true, null, null),
105            WifiConfigurationTestUtil.generateWifiConfig(
106                    1, 1000001, "\"green\"", true, true, "example.com", "Green"),
107            WifiConfigurationTestUtil.generateWifiConfig(
108                    2, 1100000, "\"blue\"", false, true, "example.org", "Blue"),
109            WifiConfigurationTestUtil.generateWifiConfig(
110                    3, 1200000, "\"cyan\"", false, true, null, null));
111
112    private static final int[] USER_IDS = {0, 10, 11};
113    private static final int MANAGED_PROFILE_USER_ID = 12;
114    private static final int MANAGED_PROFILE_PARENT_USER_ID = 0;
115    private static final SparseArray<List<UserInfo>> USER_PROFILES = new SparseArray<>();
116    static {
117        USER_PROFILES.put(0, Arrays.asList(new UserInfo(0, "Owner", 0),
118                new UserInfo(12, "Managed Profile", 0)));
119        USER_PROFILES.put(10, Arrays.asList(new UserInfo(10, "Alice", 0)));
120        USER_PROFILES.put(11, Arrays.asList(new UserInfo(11, "Bob", 0)));
121    }
122
123    private static final Map<Integer, List<WifiConfiguration>> VISIBLE_CONFIGS = new HashMap<>();
124    static {
125        for (int userId : USER_IDS) {
126            List<WifiConfiguration> configs = new ArrayList<>();
127            for (int i = 0; i < CONFIGS.size(); ++i) {
128                if (WifiConfigurationUtil.isVisibleToAnyProfile(CONFIGS.get(i),
129                        USER_PROFILES.get(userId))) {
130                    configs.add(CONFIGS.get(i));
131                }
132            }
133            VISIBLE_CONFIGS.put(userId, configs);
134        }
135    }
136
137    /**
138     * Set of WifiConfigs for HasEverConnected tests.
139     */
140    private static final int HAS_EVER_CONNECTED_USER = 20;
141    private static final WifiConfiguration BASE_HAS_EVER_CONNECTED_CONFIG =
142            WifiConfigurationTestUtil.generateWifiConfig(
143                    0, HAS_EVER_CONNECTED_USER, "testHasEverConnected", false, true, null, null, 0);
144
145    public static final String TAG = "WifiConfigManagerTest";
146    @Mock private Context mContext;
147    @Mock private WifiNative mWifiNative;
148    @Mock private FrameworkFacade mFrameworkFacade;
149    @Mock private UserManager mUserManager;
150    @Mock private DelayedDiskWrite mWriter;
151    @Mock private PasspointManagementObjectManager mMOManager;
152    @Mock private Clock mClock;
153    private WifiConfigManager mWifiConfigManager;
154    private ConfigurationMap mConfiguredNetworks;
155    public byte[] mNetworkHistoryBytes;
156    private MockKeyStore mMockKeyStore;
157
158    /**
159     * Called before each test
160     */
161    @Before
162    public void setUp() throws Exception {
163        MockitoAnnotations.initMocks(this);
164
165        final Context realContext = InstrumentationRegistry.getContext();
166        when(mContext.getPackageName()).thenReturn(realContext.getPackageName());
167        when(mContext.getResources()).thenReturn(realContext.getResources());
168        when(mContext.getPackageManager()).thenReturn(realContext.getPackageManager());
169
170        when(mUserManager.getProfiles(UserHandle.USER_SYSTEM))
171                .thenReturn(USER_PROFILES.get(UserHandle.USER_SYSTEM));
172
173        for (int userId : USER_IDS) {
174            when(mUserManager.getProfiles(userId)).thenReturn(USER_PROFILES.get(userId));
175        }
176
177        mMockKeyStore = new MockKeyStore();
178
179        mWifiConfigManager = new WifiConfigManager(mContext, mWifiNative, mFrameworkFacade, mClock,
180                mUserManager, mMockKeyStore.createMock());
181
182        final Field configuredNetworksField =
183                WifiConfigManager.class.getDeclaredField("mConfiguredNetworks");
184        configuredNetworksField.setAccessible(true);
185        mConfiguredNetworks = (ConfigurationMap) configuredNetworksField.get(mWifiConfigManager);
186
187        // Intercept writes to networkHistory.txt.
188        doAnswer(new AnswerWithArguments() {
189            public void answer(String filePath, DelayedDiskWrite.Writer writer) throws Exception {
190                final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
191                final DataOutputStream stream = new DataOutputStream(buffer);
192                writer.onWriteCalled(stream);
193                stream.close();
194                mNetworkHistoryBytes = buffer.toByteArray();
195            }}).when(mWriter).write(anyString(), (DelayedDiskWrite.Writer) anyObject());
196        final Field writerField = WifiConfigManager.class.getDeclaredField("mWriter");
197        writerField.setAccessible(true);
198        writerField.set(mWifiConfigManager, mWriter);
199        final Field networkHistoryField =
200                WifiConfigManager.class.getDeclaredField("mWifiNetworkHistory");
201        networkHistoryField.setAccessible(true);
202        WifiNetworkHistory wifiNetworkHistory =
203                (WifiNetworkHistory) networkHistoryField.get(mWifiConfigManager);
204        final Field networkHistoryWriterField =
205                WifiNetworkHistory.class.getDeclaredField("mWriter");
206        networkHistoryWriterField.setAccessible(true);
207        networkHistoryWriterField.set(wifiNetworkHistory, mWriter);
208
209        when(mMOManager.isEnabled()).thenReturn(true);
210        final Field moManagerField = WifiConfigManager.class.getDeclaredField("mMOManager");
211        moManagerField.setAccessible(true);
212        moManagerField.set(mWifiConfigManager, mMOManager);
213    }
214
215    private void switchUser(int newUserId) {
216        when(mUserManager.getProfiles(newUserId))
217                .thenReturn(USER_PROFILES.get(newUserId));
218        mWifiConfigManager.handleUserSwitch(newUserId);
219    }
220
221    private void switchUserToCreatorOrParentOf(WifiConfiguration config) {
222        final int creatorUserId = UserHandle.getUserId(config.creatorUid);
223        if (creatorUserId == MANAGED_PROFILE_USER_ID) {
224            switchUser(MANAGED_PROFILE_PARENT_USER_ID);
225        } else {
226            switchUser(creatorUserId);
227        }
228    }
229
230    private void addNetworks() throws Exception {
231        for (int i = 0; i < CONFIGS.size(); ++i) {
232            assertEquals(i, CONFIGS.get(i).networkId);
233            addNetwork(CONFIGS.get(i));
234        }
235    }
236
237    private void addNetwork(WifiConfiguration config) throws Exception {
238        final int originalUserId = mWifiConfigManager.getCurrentUserId();
239
240        when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString())).thenReturn(true);
241        when(mWifiNative.setNetworkExtra(anyInt(), anyString(), (Map<String, String>) anyObject()))
242                .thenReturn(true);
243
244        switchUserToCreatorOrParentOf(config);
245        final WifiConfiguration configCopy = new WifiConfiguration(config);
246        int networkId = config.networkId;
247        config.networkId = -1;
248        when(mWifiNative.addNetwork()).thenReturn(networkId);
249        when(mWifiNative.getNetworkVariable(networkId, WifiConfiguration.ssidVarName))
250                .thenReturn(encodeConfigSSID(config));
251        mWifiConfigManager.saveNetwork(config, configCopy.creatorUid);
252
253        switchUser(originalUserId);
254    }
255
256    private String encodeConfigSSID(WifiConfiguration config) throws Exception {
257        return new BigInteger(1, config.SSID.substring(1, config.SSID.length() - 1)
258                .getBytes("UTF-8")).toString(16);
259    }
260
261    /**
262     * Verifies that getConfiguredNetworksSize() returns the number of network configurations
263     * visible to the current user.
264     */
265    @Test
266    public void testGetConfiguredNetworksSize() throws Exception {
267        addNetworks();
268        for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
269            switchUser(entry.getKey());
270            assertEquals(entry.getValue().size(), mWifiConfigManager.getConfiguredNetworksSize());
271        }
272    }
273
274    private void verifyNetworkConfig(WifiConfiguration expectedConfig,
275            WifiConfiguration actualConfig) {
276        assertNotNull(actualConfig);
277        assertEquals(expectedConfig.SSID, actualConfig.SSID);
278        assertEquals(expectedConfig.FQDN, actualConfig.FQDN);
279        assertEquals(expectedConfig.providerFriendlyName,
280                actualConfig.providerFriendlyName);
281        assertEquals(expectedConfig.configKey(), actualConfig.configKey(false));
282    }
283
284    private void verifyNetworkConfigs(Collection<WifiConfiguration> expectedConfigs,
285            Collection<WifiConfiguration> actualConfigs) {
286        assertEquals(expectedConfigs.size(), actualConfigs.size());
287        for (WifiConfiguration expectedConfig : expectedConfigs) {
288            WifiConfiguration actualConfig = null;
289            // Find the network configuration to test (assume that |actualConfigs| contains them in
290            // undefined order).
291            for (final WifiConfiguration candidate : actualConfigs) {
292                if (candidate.networkId == expectedConfig.networkId) {
293                    actualConfig = candidate;
294                    break;
295                }
296            }
297            verifyNetworkConfig(expectedConfig, actualConfig);
298        }
299    }
300
301    /**
302     * Verifies that getConfiguredNetworksSize() returns the network configurations visible to the
303     * current user.
304     */
305    @Test
306    public void testGetConfiguredNetworks() throws Exception {
307        addNetworks();
308        for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
309            switchUser(entry.getKey());
310            verifyNetworkConfigs(entry.getValue(), mWifiConfigManager.getConfiguredNetworks());
311        }
312    }
313
314    /**
315     * Verifies that getPrivilegedConfiguredNetworks() returns the network configurations visible to
316     * the current user.
317     */
318    @Test
319    public void testGetPrivilegedConfiguredNetworks() throws Exception {
320        addNetworks();
321        for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
322            switchUser(entry.getKey());
323            verifyNetworkConfigs(entry.getValue(),
324                    mWifiConfigManager.getPrivilegedConfiguredNetworks());
325        }
326    }
327
328    /**
329     * Verifies that getWifiConfiguration(int netId) can be used to access network configurations
330     * visible to the current user only.
331     */
332    @Test
333    public void testGetWifiConfigurationByNetworkId() throws Exception {
334        addNetworks();
335        for (int userId : USER_IDS) {
336            switchUser(userId);
337            for (WifiConfiguration expectedConfig: CONFIGS) {
338                final WifiConfiguration actualConfig =
339                        mWifiConfigManager.getWifiConfiguration(expectedConfig.networkId);
340                if (WifiConfigurationUtil.isVisibleToAnyProfile(expectedConfig,
341                        USER_PROFILES.get(userId))) {
342                    verifyNetworkConfig(expectedConfig, actualConfig);
343                } else {
344                    assertNull(actualConfig);
345                }
346            }
347        }
348    }
349
350    /**
351     * Verifies that getWifiConfiguration(String key) can be used to access network configurations
352     * visible to the current user only.
353     */
354    @Test
355    public void testGetWifiConfigurationByConfigKey() throws Exception {
356        addNetworks();
357        for (int userId : USER_IDS) {
358            switchUser(userId);
359            for (WifiConfiguration expectedConfig: CONFIGS) {
360                final WifiConfiguration actualConfig =
361                        mWifiConfigManager.getWifiConfiguration(expectedConfig.configKey());
362                if (WifiConfigurationUtil.isVisibleToAnyProfile(expectedConfig,
363                        USER_PROFILES.get(userId))) {
364                    verifyNetworkConfig(expectedConfig, actualConfig);
365                } else {
366                    assertNull(actualConfig);
367                }
368            }
369        }
370    }
371
372    /**
373     * Verifies that enableAllNetworks() enables all temporarily disabled network configurations
374     * visible to the current user.
375     */
376    @Test
377    public void testEnableAllNetworks() throws Exception {
378        addNetworks();
379        for (int userId : USER_IDS) {
380            switchUser(userId);
381
382            for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
383                final WifiConfiguration.NetworkSelectionStatus status =
384                        config.getNetworkSelectionStatus();
385                status.setNetworkSelectionStatus(WifiConfiguration.NetworkSelectionStatus
386                        .NETWORK_SELECTION_TEMPORARY_DISABLED);
387                status.setNetworkSelectionDisableReason(
388                        WifiConfiguration.NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE);
389                status.setDisableTime(System.currentTimeMillis() - 60 * 60 * 1000);
390            }
391
392            mWifiConfigManager.enableAllNetworks();
393
394            for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
395                assertEquals(WifiConfigurationUtil.isVisibleToAnyProfile(config,
396                        USER_PROFILES.get(userId)),
397                        config.getNetworkSelectionStatus().isNetworkEnabled());
398            }
399        }
400    }
401
402    /**
403     * Verifies that selectNetwork() disables all network configurations visible to the current user
404     * except the selected one.
405     */
406    @Test
407    public void testSelectNetwork() throws Exception {
408        addNetworks();
409
410        for (int userId : USER_IDS) {
411            switchUser(userId);
412
413            for (WifiConfiguration config : mConfiguredNetworks.valuesForAllUsers()) {
414                // Enable all network configurations.
415                for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) {
416                    config2.status = WifiConfiguration.Status.ENABLED;
417                }
418
419                // Try to select a network configuration.
420                reset(mWifiNative);
421                when(mWifiNative.selectNetwork(config.networkId)).thenReturn(true);
422                final boolean success =
423                        mWifiConfigManager.selectNetwork(config, false, config.creatorUid);
424                if (!WifiConfigurationUtil.isVisibleToAnyProfile(config,
425                        USER_PROFILES.get(userId))) {
426                    // If the network configuration is not visible to the current user, verify that
427                    // nothing changed.
428                    assertFalse(success);
429                    verify(mWifiNative, never()).selectNetwork(anyInt());
430                    verify(mWifiNative, never()).enableNetwork(anyInt());
431                    for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) {
432                        assertEquals(WifiConfiguration.Status.ENABLED, config2.status);
433                    }
434                } else {
435                    // If the network configuration is visible to the current user, verify that it
436                    // was enabled and all other network configurations visible to the user were
437                    // disabled.
438                    assertTrue(success);
439                    verify(mWifiNative).selectNetwork(config.networkId);
440                    verify(mWifiNative, never()).selectNetwork(intThat(not(config.networkId)));
441                    verify(mWifiNative, never()).enableNetwork(config.networkId);
442                    verify(mWifiNative, never()).enableNetwork(intThat(not(config.networkId)));
443                    for (WifiConfiguration config2 : mConfiguredNetworks.valuesForAllUsers()) {
444                        if (WifiConfigurationUtil.isVisibleToAnyProfile(config2,
445                                USER_PROFILES.get(userId))
446                                && config2.networkId != config.networkId) {
447                            assertEquals(WifiConfiguration.Status.DISABLED, config2.status);
448                        } else {
449                            assertEquals(WifiConfiguration.Status.ENABLED, config2.status);
450                        }
451                    }
452                }
453            }
454        }
455    }
456
457    /**
458     * Verifies that saveNetwork() correctly stores a network configuration in wpa_supplicant
459     * variables and the networkHistory.txt file.
460     * TODO: Test all variables. Currently, only the following variables are tested:
461     * - In the wpa_supplicant: "ssid", "id_str"
462     * - In networkHistory.txt: "CONFIG", "CREATOR_UID_KEY", "SHARED"
463     */
464    private void verifySaveNetwork(int network) throws Exception {
465        // Switch to the correct user.
466        switchUserToCreatorOrParentOf(CONFIGS.get(network));
467
468        // Set up wpa_supplicant.
469        when(mWifiNative.addNetwork()).thenReturn(0);
470        when(mWifiNative.setNetworkVariable(eq(network), anyString(), anyString()))
471                .thenReturn(true);
472        when(mWifiNative.setNetworkExtra(eq(network), anyString(),
473                (Map<String, String>) anyObject())).thenReturn(true);
474        when(mWifiNative.getNetworkVariable(network, WifiConfiguration.ssidVarName))
475                .thenReturn(encodeConfigSSID(CONFIGS.get(network)));
476
477        // Store a network configuration.
478        mWifiConfigManager.saveNetwork(CONFIGS.get(network), CONFIGS.get(network).creatorUid);
479
480        // Verify that wpa_supplicant variables were written correctly for the network
481        // configuration.
482        final Map<String, String> metadata = new HashMap<String, String>();
483        if (CONFIGS.get(network).FQDN != null) {
484            metadata.put(WifiConfigStore.ID_STRING_KEY_FQDN, CONFIGS.get(network).FQDN);
485        }
486        metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(network).configKey());
487        metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
488                Integer.toString(CONFIGS.get(network).creatorUid));
489        verify(mWifiNative).setNetworkExtra(network, WifiConfigStore.ID_STRING_VAR_NAME,
490                metadata);
491
492        // Verify that no wpa_supplicant variables were read or written for any other network
493        // configurations.
494        verify(mWifiNative, never()).setNetworkExtra(intThat(not(network)), anyString(),
495                (Map<String, String>) anyObject());
496        verify(mWifiNative, never()).setNetworkVariable(intThat(not(network)), anyString(),
497                anyString());
498        verify(mWifiNative, never()).getNetworkVariable(intThat(not(network)), anyString());
499
500        // Parse networkHistory.txt.
501        assertNotNull(mNetworkHistoryBytes);
502        final DataInputStream stream =
503                new DataInputStream(new ByteArrayInputStream(mNetworkHistoryBytes));
504        List<String> keys = new ArrayList<>();
505        List<String> values = new ArrayList<>();
506        try {
507            while (true) {
508                final String[] tokens = stream.readUTF().split(":", 2);
509                if (tokens.length == 2) {
510                    keys.add(tokens[0].trim());
511                    values.add(tokens[1].trim());
512                }
513            }
514        } catch (EOFException e) {
515            // Ignore. This is expected.
516        }
517
518        // Verify that a networkHistory.txt entry was written correctly for the network
519        // configuration.
520        assertTrue(keys.size() >= 3);
521        assertEquals(WifiNetworkHistory.CONFIG_KEY, keys.get(0));
522        assertEquals(CONFIGS.get(network).configKey(), values.get(0));
523        final int creatorUidIndex = keys.indexOf(WifiNetworkHistory.CREATOR_UID_KEY);
524        assertTrue(creatorUidIndex != -1);
525        assertEquals(Integer.toString(CONFIGS.get(network).creatorUid),
526                values.get(creatorUidIndex));
527        final int sharedIndex = keys.indexOf(WifiNetworkHistory.SHARED_KEY);
528        assertTrue(sharedIndex != -1);
529        assertEquals(Boolean.toString(CONFIGS.get(network).shared), values.get(sharedIndex));
530
531        // Verify that no networkHistory.txt entries were written for any other network
532        // configurations.
533        final int lastConfigIndex = keys.lastIndexOf(WifiNetworkHistory.CONFIG_KEY);
534        assertEquals(0, lastConfigIndex);
535    }
536
537    /**
538     * Verifies that saveNetwork() correctly stores a regular network configuration.
539     */
540    @Test
541    public void testSaveNetworkRegular() throws Exception {
542        verifySaveNetwork(0);
543    }
544
545    /**
546     * Verifies that saveNetwork() correctly stores a HotSpot 2.0 network configuration.
547     */
548    @Test
549    public void testSaveNetworkHotspot20() throws Exception {
550        verifySaveNetwork(1);
551    }
552
553    /**
554     * Verifies that saveNetwork() correctly stores a private network configuration.
555     */
556    @Test
557    public void testSaveNetworkPrivate() throws Exception {
558        verifySaveNetwork(2);
559    }
560
561    /**
562     * Verifies that loadConfiguredNetworks() correctly reads data from the wpa_supplicant, the
563     * networkHistory.txt file and the MOManager, correlating the three sources based on the
564     * configKey and the FQDN for HotSpot 2.0 networks.
565     * TODO: Test all variables. Currently, only the following variables are tested:
566     * - In the wpa_supplicant: "ssid", "id_str"
567     * - In networkHistory.txt: "CONFIG", "CREATOR_UID_KEY", "SHARED"
568     */
569    @Test
570    public void testLoadConfiguredNetworks() throws Exception {
571        // Set up list of network configurations returned by wpa_supplicant.
572        final String header = "network id / ssid / bssid / flags";
573        String networks = header;
574        for (WifiConfiguration config : CONFIGS) {
575            networks += "\n" + Integer.toString(config.networkId) + "\t" + config.SSID + "\tany";
576        }
577        when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
578        when(mWifiNative.listNetworks(-1)).thenReturn(networks);
579
580        // Set up variables returned by wpa_supplicant for the individual network configurations.
581        for (int i = 0; i < CONFIGS.size(); ++i) {
582            when(mWifiNative.getNetworkVariable(i, WifiConfiguration.ssidVarName))
583                .thenReturn(encodeConfigSSID(CONFIGS.get(i)));
584        }
585        // Legacy regular network configuration: No "id_str".
586        when(mWifiNative.getNetworkExtra(0, WifiConfigStore.ID_STRING_VAR_NAME))
587            .thenReturn(null);
588        // Legacy Hotspot 2.0 network configuration: Quoted FQDN in "id_str".
589        when(mWifiNative.getNetworkExtra(1, WifiConfigStore.ID_STRING_VAR_NAME))
590            .thenReturn(null);
591        when(mWifiNative.getNetworkVariable(1, WifiConfigStore.ID_STRING_VAR_NAME))
592            .thenReturn('"' + CONFIGS.get(1).FQDN + '"');
593        // Up-to-date Hotspot 2.0 network configuration: Metadata in "id_str".
594        Map<String, String> metadata = new HashMap<String, String>();
595        metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(2).configKey());
596        metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
597                Integer.toString(CONFIGS.get(2).creatorUid));
598        metadata.put(WifiConfigStore.ID_STRING_KEY_FQDN, CONFIGS.get(2).FQDN);
599        when(mWifiNative.getNetworkExtra(2, WifiConfigStore.ID_STRING_VAR_NAME))
600            .thenReturn(metadata);
601        // Up-to-date regular network configuration: Metadata in "id_str".
602        metadata = new HashMap<String, String>();
603        metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(3).configKey());
604        metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
605                Integer.toString(CONFIGS.get(3).creatorUid));
606        when(mWifiNative.getNetworkExtra(3, WifiConfigStore.ID_STRING_VAR_NAME))
607            .thenReturn(metadata);
608
609        // Set up networkHistory.txt file.
610        final File file = File.createTempFile("networkHistory.txt", null);
611        file.deleteOnExit();
612
613        Field wifiNetworkHistoryConfigFile =
614                WifiNetworkHistory.class.getDeclaredField("NETWORK_HISTORY_CONFIG_FILE");
615        wifiNetworkHistoryConfigFile.setAccessible(true);
616        wifiNetworkHistoryConfigFile.set(null, file.getAbsolutePath());
617
618        final DataOutputStream stream = new DataOutputStream(new FileOutputStream(file));
619        for (WifiConfiguration config : CONFIGS) {
620            stream.writeUTF(WifiNetworkHistory.CONFIG_KEY + ":  " + config.configKey() + '\n');
621            stream.writeUTF(WifiNetworkHistory.CREATOR_UID_KEY + ":  "
622                    + Integer.toString(config.creatorUid) + '\n');
623            stream.writeUTF(WifiNetworkHistory.SHARED_KEY + ":  "
624                    + Boolean.toString(config.shared) + '\n');
625        }
626        stream.close();
627
628        // Set up list of home service providers returned by MOManager.
629        final List<HomeSP> homeSPs = new ArrayList<HomeSP>();
630        for (WifiConfiguration config : CONFIGS) {
631            if (config.FQDN != null) {
632                homeSPs.add(new HomeSP(null, config.FQDN, new HashSet<Long>(),
633                        new HashSet<String>(),
634                        new HashSet<Long>(), new ArrayList<Long>(),
635                        config.providerFriendlyName, null,
636                        new Credential(0, 0, null, false, null, null),
637                        null, 0, null, null, null, 0));
638            }
639        }
640        when(mMOManager.loadAllSPs()).thenReturn(homeSPs);
641
642        // Load network configurations.
643        mWifiConfigManager.loadConfiguredNetworks();
644
645        // Verify that network configurations were loaded and correlated correctly across the three
646        // sources.
647        verifyNetworkConfigs(CONFIGS, mConfiguredNetworks.valuesForAllUsers());
648    }
649
650    /**
651     * Verifies that loadConfiguredNetworks() correctly handles duplicates when reading network
652     * configurations from the wpa_supplicant: The second configuration overwrites the first.
653     */
654    @Test
655    public void testLoadConfiguredNetworksEliminatesDuplicates() throws Exception {
656        final WifiConfiguration config = new WifiConfiguration(CONFIGS.get(0));
657        config.networkId = 1;
658
659        // Set up list of network configurations returned by wpa_supplicant. The two configurations
660        // are identical except for their network IDs.
661        final String header = "network id / ssid / bssid / flags";
662        final String networks =
663                header + "\n0\t" + config.SSID + "\tany\n1\t" + config.SSID + "\tany";
664        when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
665        when(mWifiNative.listNetworks(-1)).thenReturn(networks);
666
667        // Set up variables returned by wpa_supplicant.
668        when(mWifiNative.getNetworkVariable(anyInt(), eq(WifiConfiguration.ssidVarName)))
669            .thenReturn(encodeConfigSSID(config));
670        final Map<String, String> metadata = new HashMap<String, String>();
671        metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, config.configKey());
672        metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
673                Integer.toString(config.creatorUid));
674        when(mWifiNative.getNetworkExtra(anyInt(), eq(WifiConfigStore.ID_STRING_VAR_NAME)))
675            .thenReturn(metadata);
676
677        // Load network configurations.
678        mWifiConfigManager.loadConfiguredNetworks();
679
680        // Verify that the second network configuration (network ID 1) overwrote the first (network
681        // ID 0).
682        verifyNetworkConfigs(Arrays.asList(config), mConfiguredNetworks.valuesForAllUsers());
683    }
684
685    /**
686     * Verifies that handleUserSwitch() removes ephemeral network configurations, disables network
687     * configurations that should no longer be visible and enables network configurations that
688     * should become visible.
689     */
690    private void verifyHandleUserSwitch(int oldUserId, int newUserId,
691            boolean makeOneConfigEphemeral) throws Exception {
692        addNetworks();
693        switchUser(oldUserId);
694
695        reset(mWifiNative);
696        final Field lastSelectedConfigurationField =
697                WifiConfigManager.class.getDeclaredField("mLastSelectedConfiguration");
698        lastSelectedConfigurationField.setAccessible(true);
699        WifiConfiguration removedEphemeralConfig = null;
700        final Set<WifiConfiguration> oldUserOnlyConfigs = new HashSet<>();
701        final Set<WifiConfiguration> newUserOnlyConfigs = new HashSet<>();
702        final Set<WifiConfiguration> neitherUserConfigs = new HashSet<>();
703        final Collection<WifiConfiguration> oldConfigs = mConfiguredNetworks.valuesForAllUsers();
704        int expectedNumberOfConfigs = oldConfigs.size();
705        for (WifiConfiguration config : oldConfigs) {
706            if (WifiConfigurationUtil.isVisibleToAnyProfile(config, USER_PROFILES.get(oldUserId))) {
707                config.status = WifiConfiguration.Status.ENABLED;
708                if (WifiConfigurationUtil.isVisibleToAnyProfile(config,
709                        USER_PROFILES.get(newUserId))) {
710                    if (makeOneConfigEphemeral && removedEphemeralConfig == null) {
711                        config.ephemeral = true;
712                        lastSelectedConfigurationField.set(mWifiConfigManager, config.configKey());
713                        removedEphemeralConfig = config;
714                    }
715                } else {
716                    oldUserOnlyConfigs.add(config);
717                }
718            } else {
719                config.status = WifiConfiguration.Status.DISABLED;
720                if (WifiConfigurationUtil.isVisibleToAnyProfile(config,
721                        USER_PROFILES.get(newUserId))) {
722                    newUserOnlyConfigs.add(config);
723                } else {
724                    neitherUserConfigs.add(config);
725                }
726            }
727        }
728
729        when(mWifiNative.disableNetwork(anyInt())).thenReturn(true);
730        when(mWifiNative.removeNetwork(anyInt())).thenReturn(true);
731
732        switchUser(newUserId);
733        if (makeOneConfigEphemeral) {
734            // Verify that the ephemeral network configuration was removed.
735            assertNotNull(removedEphemeralConfig);
736            assertNull(mConfiguredNetworks.getForAllUsers(removedEphemeralConfig.networkId));
737            assertNull(lastSelectedConfigurationField.get(mWifiConfigManager));
738            verify(mWifiNative).removeNetwork(removedEphemeralConfig.networkId);
739            --expectedNumberOfConfigs;
740        } else {
741            assertNull(removedEphemeralConfig);
742        }
743
744        // Verify that the other network configurations were revealed/hidden and enabled/disabled as
745        // appropriate.
746        final Collection<WifiConfiguration> newConfigs = mConfiguredNetworks.valuesForAllUsers();
747        assertEquals(expectedNumberOfConfigs, newConfigs.size());
748        for (WifiConfiguration config : newConfigs) {
749            if (oldUserOnlyConfigs.contains(config)) {
750                verify(mWifiNative).disableNetwork(config.networkId);
751                assertEquals(WifiConfiguration.Status.DISABLED, config.status);
752            } else {
753                verify(mWifiNative, never()).disableNetwork(config.networkId);
754                if (neitherUserConfigs.contains(config)) {
755                    assertEquals(WifiConfiguration.Status.DISABLED, config.status);
756                } else {
757                    // Only enabled in networkSelection.
758                    assertTrue(config.getNetworkSelectionStatus().isNetworkEnabled());
759                }
760
761            }
762        }
763    }
764
765    /**
766     * Verifies that handleUserSwitch() behaves correctly when the user switch removes an ephemeral
767     * network configuration and reveals a private network configuration.
768     */
769    @Test
770    public void testHandleUserSwitchWithEphemeral() throws Exception {
771        verifyHandleUserSwitch(USER_IDS[2], USER_IDS[0], true);
772    }
773
774    /**
775     * Verifies that handleUserSwitch() behaves correctly when the user switch hides a private
776     * network configuration.
777     */
778    @Test
779    public void testHandleUserSwitchWithoutEphemeral() throws Exception {
780        verifyHandleUserSwitch(USER_IDS[0], USER_IDS[2], false);
781    }
782
783    @Test
784    public void testSaveLoadEapNetworks() {
785        testSaveLoadSingleEapNetwork("eap network", new EnterpriseConfig(Eap.TTLS)
786                .setPhase2(Phase2.MSCHAPV2)
787                .setIdentity("username", "password")
788                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0}));
789        testSaveLoadSingleEapNetwork("eap network", new EnterpriseConfig(Eap.TTLS)
790                .setPhase2(Phase2.MSCHAPV2)
791                .setIdentity("username", "password")
792                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT1, FakeKeys.CA_CERT0}));
793
794    }
795
796    private void testSaveLoadSingleEapNetwork(String ssid, EnterpriseConfig eapConfig) {
797        final HashMap<String, String> networkVariables = new HashMap<String, String>();
798        reset(mWifiNative);
799        when(mWifiNative.addNetwork()).thenReturn(0);
800        when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString())).thenAnswer(
801                new AnswerWithArguments() {
802                    public boolean answer(int netId, String name, String value) {
803                        // Verify that no wpa_supplicant variables were written for any other
804                        // network configurations.
805                        assertEquals(netId, 0);
806                        networkVariables.put(name, value);
807                        return true;
808                    }
809                });
810        when(mWifiNative.getNetworkVariable(anyInt(), anyString())).then(
811                new AnswerWithArguments() {
812                    public String answer(int netId, String name) {
813                        // Verify that no wpa_supplicant variables were read for any other
814                        // network configurations.
815                        assertEquals(netId, 0);
816                        return networkVariables.get(name);
817                    }
818                });
819        when(mWifiNative.setNetworkExtra(eq(0), anyString(), (Map<String, String>) anyObject()))
820                .thenReturn(true);
821
822        WifiConfiguration config = new WifiConfiguration();
823        config.SSID = ssid;
824        config.creatorUid = Process.WIFI_UID;
825        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
826        config.enterpriseConfig = eapConfig.enterpriseConfig;
827
828        // Store a network configuration.
829        mWifiConfigManager.saveNetwork(config, Process.WIFI_UID);
830
831        // Verify that wpa_supplicant variables were written correctly for the network
832        // configuration.
833        verify(mWifiNative).addNetwork();
834        assertEquals(eapConfig.eap,
835                unquote(networkVariables.get(WifiEnterpriseConfig.EAP_KEY)));
836        assertEquals(eapConfig.phase2,
837                unquote(networkVariables.get(WifiEnterpriseConfig.PHASE2_KEY)));
838        assertEquals(eapConfig.identity,
839                unquote(networkVariables.get(WifiEnterpriseConfig.IDENTITY_KEY)));
840        assertEquals(eapConfig.password,
841                unquote(networkVariables.get(WifiEnterpriseConfig.PASSWORD_KEY)));
842        assertSavedCaCerts(eapConfig,
843                unquote(networkVariables.get(WifiEnterpriseConfig.CA_CERT_KEY)));
844
845        // Prepare the scan result.
846        final String header = "network id / ssid / bssid / flags";
847        String networks = header + "\n" + Integer.toString(0) + "\t" + ssid + "\tany";
848        when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
849        when(mWifiNative.listNetworks(-1)).thenReturn(networks);
850
851        // Load back the configuration.
852        mWifiConfigManager.loadConfiguredNetworks();
853        List<WifiConfiguration> configs = mWifiConfigManager.getConfiguredNetworks();
854        assertEquals(1, configs.size());
855        WifiConfiguration loadedConfig = configs.get(0);
856        assertEquals(ssid, unquote(loadedConfig.SSID));
857        BitSet keyMgmt = new BitSet();
858        keyMgmt.set(KeyMgmt.WPA_EAP);
859        assertEquals(keyMgmt, loadedConfig.allowedKeyManagement);
860        assertEquals(eapConfig.enterpriseConfig.getEapMethod(),
861                loadedConfig.enterpriseConfig.getEapMethod());
862        assertEquals(eapConfig.enterpriseConfig.getPhase2Method(),
863                loadedConfig.enterpriseConfig.getPhase2Method());
864        assertEquals(eapConfig.enterpriseConfig.getIdentity(),
865                loadedConfig.enterpriseConfig.getIdentity());
866        assertEquals(eapConfig.enterpriseConfig.getPassword(),
867                loadedConfig.enterpriseConfig.getPassword());
868        asserCaCertsAliasesMatch(eapConfig.caCerts,
869                loadedConfig.enterpriseConfig.getCaCertificateAliases());
870    }
871
872    private String unquote(String value) {
873        if (value == null) {
874            return null;
875        }
876        int length = value.length();
877        if ((length > 1) && (value.charAt(0) == '"')
878                && (value.charAt(length - 1) == '"')) {
879            return value.substring(1, length - 1);
880        } else {
881            return value;
882        }
883    }
884
885    private void asserCaCertsAliasesMatch(X509Certificate[] certs, String[] aliases) {
886        assertEquals(certs.length, aliases.length);
887        List<String> aliasList = new ArrayList<String>(Arrays.asList(aliases));
888        try {
889            for (int i = 0; i < certs.length; i++) {
890                byte[] certPem = Credentials.convertToPem(certs[i]);
891                boolean found = false;
892                for (int j = 0; j < aliasList.size(); j++) {
893                    byte[] keystoreCert = mMockKeyStore.getKeyBlob(Process.WIFI_UID,
894                            Credentials.CA_CERTIFICATE + aliasList.get(j)).blob;
895                    if (Arrays.equals(keystoreCert, certPem)) {
896                        found = true;
897                        aliasList.remove(j);
898                        break;
899                    }
900                }
901                assertTrue(found);
902            }
903        } catch (CertificateEncodingException | IOException e) {
904            fail("Cannot convert CA certificate to encoded form.");
905        }
906    }
907
908    private void assertSavedCaCerts(EnterpriseConfig eapConfig, String caCertVariable) {
909        ArrayList<String> aliases = new ArrayList<String>();
910        if (TextUtils.isEmpty(caCertVariable)) {
911            // Do nothing.
912        } else if (caCertVariable.startsWith(WifiEnterpriseConfig.CA_CERT_PREFIX)) {
913            aliases.add(caCertVariable.substring(WifiEnterpriseConfig.CA_CERT_PREFIX.length()));
914        } else if (caCertVariable.startsWith(WifiEnterpriseConfig.KEYSTORES_URI)) {
915            String[] encodedAliases = TextUtils.split(
916                    caCertVariable.substring(WifiEnterpriseConfig.KEYSTORES_URI.length()),
917                    WifiEnterpriseConfig.CA_CERT_ALIAS_DELIMITER);
918            for (String encodedAlias : encodedAliases) {
919                String alias = WifiEnterpriseConfig.decodeCaCertificateAlias(encodedAlias);
920                assertTrue(alias.startsWith(Credentials.CA_CERTIFICATE));
921                aliases.add(alias.substring(Credentials.CA_CERTIFICATE.length()));
922            }
923        } else {
924            fail("Unrecognized ca_cert variable: " + caCertVariable);
925        }
926        asserCaCertsAliasesMatch(eapConfig.caCerts, aliases.toArray(new String[aliases.size()]));
927    }
928
929    private static class EnterpriseConfig {
930        public String eap;
931        public String phase2;
932        public String identity;
933        public String password;
934        public X509Certificate[] caCerts;
935        public WifiEnterpriseConfig enterpriseConfig;
936
937        public EnterpriseConfig(int eapMethod) {
938            enterpriseConfig = new WifiEnterpriseConfig();
939            enterpriseConfig.setEapMethod(eapMethod);
940            eap = Eap.strings[eapMethod];
941        }
942        public EnterpriseConfig setPhase2(int phase2Method) {
943            enterpriseConfig.setPhase2Method(phase2Method);
944            phase2 = "auth=" + Phase2.strings[phase2Method];
945            return this;
946        }
947        public EnterpriseConfig setIdentity(String identity, String password) {
948            enterpriseConfig.setIdentity(identity);
949            enterpriseConfig.setPassword(password);
950            this.identity = identity;
951            this.password = password;
952            return this;
953        }
954        public EnterpriseConfig setCaCerts(X509Certificate[] certs) {
955            enterpriseConfig.setCaCertificates(certs);
956            caCerts = certs;
957            return this;
958        }
959    }
960
961    /**
962     * Generates an array of unique random numbers below the specified maxValue.
963     * Values range from 0 to maxValue-1.
964     */
965    private static ArrayDeque<Integer> getUniqueRandomNumberValues(
966            int seed,
967            int maxValue,
968            int numValues) {
969        assertTrue(numValues <= maxValue);
970        Random rand = new Random(WifiTestUtil.getTestMethod().hashCode() + seed);
971        ArrayDeque<Integer> randomNumberList = new ArrayDeque<>();
972        for (int i = 0; i < numValues; i++) {
973            int num = rand.nextInt(maxValue);
974            while (randomNumberList.contains(num)) {
975                num = rand.nextInt(maxValue);
976            }
977            randomNumberList.push(num);
978        }
979        return randomNumberList;
980    }
981
982    /**
983     * Verifies that the networks in pnoNetworkList is sorted in the same order as the
984     * network in expectedNetworkIDOrder list.
985     */
986    private static void verifyPnoNetworkListOrder(
987            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList,
988            ArrayList<Integer> expectedNetworkIdOrder) throws Exception  {
989        int i = 0;
990        for (WifiScanner.PnoSettings.PnoNetwork pnoNetwork : pnoNetworkList) {
991            Log.i(TAG, "PNO Network List Index: " + i + ", networkID: " + pnoNetwork.networkId);
992            assertEquals("Expected network ID: " + pnoNetwork.networkId,
993                    pnoNetwork.networkId, expectedNetworkIdOrder.get(i++).intValue());
994        }
995    }
996
997    /**
998     * Verifies the retrieveDisconnectedPnoNetworkList API. The test verifies that the list
999     * returned from the API is sorted as expected.
1000     */
1001    @Test
1002    public void testDisconnectedPnoNetworkListCreation() throws Exception {
1003        addNetworks();
1004
1005        Random rand = new Random(WifiTestUtil.getTestMethod().hashCode());
1006
1007        // First assign random |numAssociation| values and verify that the list is sorted
1008        // in descending order of |numAssociation| values. Keep NetworkSelectionStatus
1009        // values constant.
1010        for (int userId : USER_IDS) {
1011            switchUser(userId);
1012            TreeMap<Integer, Integer> numAssociationToNetworkIdMap =
1013                    new TreeMap<>(Collections.reverseOrder());
1014            ArrayDeque<Integer> numAssociationValues =
1015                    getUniqueRandomNumberValues(
1016                            1, 10000, mConfiguredNetworks.valuesForCurrentUser().size());
1017            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1018                config.numAssociation = numAssociationValues.pop();
1019                config.priority = rand.nextInt(10000);
1020                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1021                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1022                numAssociationToNetworkIdMap.put(config.numAssociation, config.networkId);
1023                Log.i(TAG, "networkID: " + config.networkId + ", numAssociation: "
1024                        + config.numAssociation);
1025            }
1026            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1027                    mWifiConfigManager.retrieveDisconnectedPnoNetworkList();
1028            verifyPnoNetworkListOrder(pnoNetworkList,
1029                    new ArrayList(numAssociationToNetworkIdMap.values()));
1030        }
1031
1032        // Assign random |priority| values and verify that the list is sorted in descending order
1033        // of |priority| values. Keep numAssociation/NetworkSelectionStatus values constant.
1034        for (int userId : USER_IDS) {
1035            switchUser(userId);
1036            TreeMap<Integer, Integer> priorityToNetworkIdMap =
1037                    new TreeMap<>(Collections.reverseOrder());
1038            ArrayDeque<Integer> priorityValues =
1039                    getUniqueRandomNumberValues(
1040                            2, 10000, mConfiguredNetworks.valuesForCurrentUser().size());
1041            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1042                config.numAssociation = 0;
1043                config.priority = priorityValues.pop();
1044                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1045                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1046                priorityToNetworkIdMap.put(config.priority, config.networkId);
1047                Log.i(TAG, "networkID: " + config.networkId + ", priority: " + config.priority);
1048            }
1049            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1050                    mWifiConfigManager.retrieveDisconnectedPnoNetworkList();
1051            verifyPnoNetworkListOrder(pnoNetworkList,
1052                    new ArrayList(priorityToNetworkIdMap.values()));
1053        }
1054
1055        // Now assign random |NetworkSelectionStatus| values and verify that the list is sorted in
1056        // ascending order of |NetworkSelectionStatus| values.
1057        for (int userId : USER_IDS) {
1058            switchUser(userId);
1059            TreeMap<Integer, Integer> networkSelectionStatusToNetworkIdMap = new TreeMap<>();
1060            ArrayDeque<Integer> networkSelectionStatusValues =
1061                    getUniqueRandomNumberValues(
1062                            3,
1063                            WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_STATUS_MAX,
1064                            mConfiguredNetworks.valuesForCurrentUser().size());
1065            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1066                config.numAssociation = rand.nextInt(10000);
1067                config.priority = rand.nextInt(10000);
1068                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1069                        networkSelectionStatusValues.pop());
1070                networkSelectionStatusToNetworkIdMap.put(
1071                        config.getNetworkSelectionStatus().getNetworkSelectionStatus(),
1072                        config.networkId);
1073                Log.i(TAG, "networkID: " + config.networkId + ", NetworkSelectionStatus: "
1074                        + config.getNetworkSelectionStatus().getNetworkSelectionStatus());
1075            }
1076            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1077                    mWifiConfigManager.retrieveDisconnectedPnoNetworkList();
1078            verifyPnoNetworkListOrder(pnoNetworkList,
1079                    new ArrayList(networkSelectionStatusToNetworkIdMap.values()));
1080        }
1081    }
1082
1083    /**
1084     * Verifies the retrieveConnectedPnoNetworkList API. The test verifies that the list
1085     * returned from the API is sorted as expected.
1086     */
1087    @Test
1088    public void testConnectedPnoNetworkListCreation() throws Exception {
1089        addNetworks();
1090
1091        Random rand = new Random(WifiTestUtil.getTestMethod().hashCode());
1092
1093        // First assign |lastSeen| values and verify that the list is sorted
1094        // in descending order of |lastSeen| values. Keep NetworkSelectionStatus
1095        // values constant.
1096        for (int userId : USER_IDS) {
1097            switchUser(userId);
1098            TreeMap<Boolean, Integer> lastSeenToNetworkIdMap =
1099                    new TreeMap<>(Collections.reverseOrder());
1100            ArrayDeque<Integer> lastSeenValues = getUniqueRandomNumberValues(1, 2, 2);
1101            if (mConfiguredNetworks.valuesForCurrentUser().size() > 2) continue;
1102            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1103                config.numAssociation = rand.nextInt(10000);
1104                config.priority = rand.nextInt(10000);
1105                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1106                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1107                boolean lastSeenValue = (lastSeenValues.pop()  == 1);
1108                config.getNetworkSelectionStatus().setSeenInLastQualifiedNetworkSelection(
1109                        lastSeenValue);
1110                lastSeenToNetworkIdMap.put(lastSeenValue, config.networkId);
1111                Log.i(TAG, "networkID: " + config.networkId + ", lastSeen: " + lastSeenValue);
1112            }
1113            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1114                    mWifiConfigManager.retrieveConnectedPnoNetworkList();
1115            verifyPnoNetworkListOrder(pnoNetworkList,
1116                    new ArrayList(lastSeenToNetworkIdMap.values()));
1117        }
1118
1119        // Assign random |numAssociation| values and verify that the list is sorted
1120        // in descending order of |numAssociation| values. Keep NetworkSelectionStatus/lastSeen
1121        // values constant.
1122        for (int userId : USER_IDS) {
1123            switchUser(userId);
1124            TreeMap<Integer, Integer> numAssociationToNetworkIdMap =
1125                    new TreeMap<>(Collections.reverseOrder());
1126            ArrayDeque<Integer> numAssociationValues =
1127                    getUniqueRandomNumberValues(
1128                            1, 10000, mConfiguredNetworks.valuesForCurrentUser().size());
1129            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1130                config.numAssociation = numAssociationValues.pop();
1131                config.priority = rand.nextInt(10000);
1132                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1133                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1134                config.getNetworkSelectionStatus().setSeenInLastQualifiedNetworkSelection(true);
1135                numAssociationToNetworkIdMap.put(config.numAssociation, config.networkId);
1136                Log.i(TAG, "networkID: " + config.networkId + ", numAssociation: "
1137                        + config.numAssociation);
1138            }
1139            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1140                    mWifiConfigManager.retrieveConnectedPnoNetworkList();
1141            verifyPnoNetworkListOrder(pnoNetworkList,
1142                    new ArrayList(numAssociationToNetworkIdMap.values()));
1143        }
1144
1145        // Now assign random |NetworkSelectionStatus| values and verify that the list is sorted in
1146        // ascending order of |NetworkSelectionStatus| values.
1147        for (int userId : USER_IDS) {
1148            switchUser(userId);
1149            TreeMap<Integer, Integer> networkSelectionStatusToNetworkIdMap = new TreeMap<>();
1150            ArrayDeque<Integer> networkSelectionStatusValues =
1151                    getUniqueRandomNumberValues(
1152                            3,
1153                            WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_STATUS_MAX,
1154                            mConfiguredNetworks.valuesForCurrentUser().size());
1155            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1156                config.numAssociation = rand.nextInt(10000);
1157                config.priority = rand.nextInt(10000);
1158                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1159                        networkSelectionStatusValues.pop());
1160                networkSelectionStatusToNetworkIdMap.put(
1161                        config.getNetworkSelectionStatus().getNetworkSelectionStatus(),
1162                        config.networkId);
1163                Log.i(TAG, "networkID: " + config.networkId + ", NetworkSelectionStatus: "
1164                        + config.getNetworkSelectionStatus().getNetworkSelectionStatus());
1165            }
1166            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1167                    mWifiConfigManager.retrieveConnectedPnoNetworkList();
1168            verifyPnoNetworkListOrder(pnoNetworkList,
1169                    new ArrayList(networkSelectionStatusToNetworkIdMap.values()));
1170        }
1171    }
1172
1173    /**
1174     * Verifies that hasEverConnected is false for a newly added network
1175     */
1176    @Test
1177    public void testAddNetworkHasEverConnectedFalse() throws Exception {
1178        addNetwork(BASE_HAS_EVER_CONNECTED_CONFIG);
1179        WifiConfiguration checkConfig = mWifiConfigManager.getWifiConfiguration(
1180                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1181        assertFalse("Adding a new network should not have hasEverConnected set to true.",
1182                checkConfig.getNetworkSelectionStatus().getHasEverConnected());
1183    }
1184
1185
1186    /**
1187     * Verifies that hasEverConnected is false for a newly added network even when new config has
1188     * mistakenly set HasEverConnected to true.
1189    */
1190    @Test
1191    public void testAddNetworkOverridesHasEverConnectedWhenTrueInNewConfig() throws Exception {
1192        WifiConfiguration newNetworkWithHasEverConnectedTrue =
1193                new WifiConfiguration(BASE_HAS_EVER_CONNECTED_CONFIG);
1194        newNetworkWithHasEverConnectedTrue.getNetworkSelectionStatus().setHasEverConnected(true);
1195        addNetwork(newNetworkWithHasEverConnectedTrue);
1196        // check if addNetwork clears the bit.
1197        WifiConfiguration checkConfig = mWifiConfigManager.getWifiConfiguration(
1198                newNetworkWithHasEverConnectedTrue.networkId);
1199        assertFalse("Adding a new network should not have hasEverConnected set to true.",
1200                checkConfig.getNetworkSelectionStatus().getHasEverConnected());
1201    }
1202
1203
1204    /**
1205     * Verify that setting HasEverConnected with a config update can be read back.
1206     */
1207    @Test
1208    public void testUpdateConfigToHasEverConnectedTrue() throws Exception {
1209        addNetwork(BASE_HAS_EVER_CONNECTED_CONFIG);
1210
1211        // Get the newly saved config and update HasEverConnected
1212        WifiConfiguration checkConfig = mWifiConfigManager.getWifiConfiguration(
1213                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1214        assertFalse("Adding a new network should not have hasEverConnected set to true.",
1215                checkConfig.getNetworkSelectionStatus().getHasEverConnected());
1216        checkConfig.getNetworkSelectionStatus().setHasEverConnected(true);
1217        mWifiConfigManager.addOrUpdateNetwork(checkConfig, HAS_EVER_CONNECTED_USER);
1218
1219        // verify that HasEverConnected was properly written and read back
1220        checkHasEverConnectedTrue(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1221    }
1222
1223
1224    /**
1225     * Verifies that hasEverConnected is cleared when a network config preSharedKey is updated.
1226     */
1227    @Test
1228    public void testUpdatePreSharedKeyClearsHasEverConnected() throws Exception {
1229        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1230
1231        testUpdateConfigToHasEverConnectedTrue();
1232
1233        WifiConfiguration original = mWifiConfigManager.getWifiConfiguration(
1234                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1235
1236        WifiConfiguration updatePreSharedKeyConfig = new WifiConfiguration();
1237        updatePreSharedKeyConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1238        updatePreSharedKeyConfig.SSID = original.SSID;
1239        updatePreSharedKeyConfig.preSharedKey = "newpassword";
1240        switchUserToCreatorOrParentOf(original);
1241        mWifiConfigManager.addOrUpdateNetwork(updatePreSharedKeyConfig,
1242                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1243
1244        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1245        switchUser(originalUserId);
1246    }
1247
1248    /**
1249     * Verifies that hasEverConnected is cleared when a network config allowedKeyManagement is
1250     * updated.
1251     */
1252    @Test
1253    public void testUpdateAllowedKeyManagementChanged() throws Exception {
1254        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1255
1256        testUpdateConfigToHasEverConnectedTrue();
1257
1258        WifiConfiguration updateAllowedKeyManagementConfig = new WifiConfiguration();
1259        updateAllowedKeyManagementConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1260        updateAllowedKeyManagementConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1261        updateAllowedKeyManagementConfig.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
1262
1263        // Set up mock to allow the new value to be read back into the config
1264        String allowedKeyManagementString = makeString(
1265                updateAllowedKeyManagementConfig.allowedKeyManagement,
1266                    WifiConfiguration.KeyMgmt.strings);
1267        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1268                KeyMgmt.varName)).thenReturn(allowedKeyManagementString);
1269
1270        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1271        mWifiConfigManager.addOrUpdateNetwork(updateAllowedKeyManagementConfig,
1272                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1273
1274        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1275        switchUser(originalUserId);
1276    }
1277
1278    /**
1279     * Verifies that hasEverConnected is cleared when a network config allowedProtocols is
1280     * updated.
1281     */
1282    @Test
1283    public void testUpdateAllowedProtocolsChanged() throws Exception {
1284        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1285
1286        testUpdateConfigToHasEverConnectedTrue();
1287
1288        WifiConfiguration updateAllowedProtocolsConfig = new WifiConfiguration();
1289        updateAllowedProtocolsConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1290        updateAllowedProtocolsConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1291        updateAllowedProtocolsConfig.allowedProtocols.set(
1292                WifiConfiguration.Protocol.RSN);
1293
1294        // Set up mock to allow the new value to be read back into the config
1295        String allowedProtocolsString = makeString(
1296                updateAllowedProtocolsConfig.allowedProtocols,
1297                    WifiConfiguration.Protocol.strings);
1298        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1299                Protocol.varName)).thenReturn(allowedProtocolsString);
1300
1301        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1302        mWifiConfigManager.addOrUpdateNetwork(updateAllowedProtocolsConfig,
1303                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1304
1305        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1306        switchUser(originalUserId);
1307    }
1308
1309    /**
1310     * Verifies that hasEverConnected is cleared when a network config allowedAuthAlgorithms is
1311     * updated.
1312     */
1313    @Test
1314    public void testUpdateAllowedAuthAlgorithmsChanged() throws Exception {
1315        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1316
1317        testUpdateConfigToHasEverConnectedTrue();
1318
1319        WifiConfiguration updateAllowedAuthAlgorithmsConfig = new WifiConfiguration();
1320        updateAllowedAuthAlgorithmsConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1321        updateAllowedAuthAlgorithmsConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1322        updateAllowedAuthAlgorithmsConfig.allowedAuthAlgorithms.set(
1323                WifiConfiguration.AuthAlgorithm.SHARED);
1324
1325        // Set up mock to allow the new value to be read back into the config
1326        String allowedAuthAlgorithmsString = makeString(
1327                updateAllowedAuthAlgorithmsConfig.allowedAuthAlgorithms,
1328                    WifiConfiguration.AuthAlgorithm.strings);
1329        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1330                AuthAlgorithm.varName)).thenReturn(allowedAuthAlgorithmsString);
1331
1332        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1333        mWifiConfigManager.addOrUpdateNetwork(updateAllowedAuthAlgorithmsConfig,
1334                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1335
1336        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1337        switchUser(originalUserId);
1338    }
1339
1340    /**
1341     * Verifies that hasEverConnected is cleared when a network config allowedPairwiseCiphers is
1342     * updated.
1343     */
1344    @Test
1345    public void testUpdateAllowedPairwiseCiphersChanged() throws Exception {
1346        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1347
1348        testUpdateConfigToHasEverConnectedTrue();
1349
1350        WifiConfiguration updateAllowedPairwiseCiphersConfig = new WifiConfiguration();
1351        updateAllowedPairwiseCiphersConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1352        updateAllowedPairwiseCiphersConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1353        updateAllowedPairwiseCiphersConfig.allowedPairwiseCiphers.set(
1354                WifiConfiguration.PairwiseCipher.CCMP);
1355
1356        // Set up mock to allow the new value to be read back into the config
1357        String allowedPairwiseCiphersString = makeString(
1358                updateAllowedPairwiseCiphersConfig.allowedPairwiseCiphers,
1359                    WifiConfiguration.PairwiseCipher.strings);
1360        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1361                PairwiseCipher.varName)).thenReturn(allowedPairwiseCiphersString);
1362
1363        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1364        mWifiConfigManager.addOrUpdateNetwork(updateAllowedPairwiseCiphersConfig,
1365                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1366
1367        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1368        switchUser(originalUserId);
1369    }
1370
1371    /**
1372     * Verifies that hasEverConnected is cleared when a network config allowedGroupCiphers is
1373     * updated.
1374     */
1375    @Test
1376    public void testUpdateAllowedGroupCiphersChanged() throws Exception {
1377        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1378
1379        testUpdateConfigToHasEverConnectedTrue();
1380
1381        WifiConfiguration updateAllowedGroupCiphersConfig = new WifiConfiguration();
1382        updateAllowedGroupCiphersConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1383        updateAllowedGroupCiphersConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1384        updateAllowedGroupCiphersConfig.allowedGroupCiphers.set(
1385                WifiConfiguration.GroupCipher.CCMP);
1386
1387        // Set up mock to allow the new value to be read back into the config
1388        String allowedGroupCiphersString = makeString(
1389                updateAllowedGroupCiphersConfig.allowedGroupCiphers,
1390                    WifiConfiguration.GroupCipher.strings);
1391        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1392                GroupCipher.varName)).thenReturn(allowedGroupCiphersString);
1393
1394        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1395        mWifiConfigManager.addOrUpdateNetwork(updateAllowedGroupCiphersConfig,
1396                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1397
1398        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1399        switchUser(originalUserId);
1400    }
1401
1402    /**
1403     * Verifies that hasEverConnected is cleared when a network config wepKeys is
1404     * updated.
1405     */
1406    @Test
1407    public void testUpdateWepKeysChanged() throws Exception {
1408        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1409
1410        testUpdateConfigToHasEverConnectedTrue();
1411
1412        String tempKey = "hereisakey";
1413        WifiConfiguration updateWepKeysConfig = new WifiConfiguration();
1414        updateWepKeysConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1415        updateWepKeysConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1416        updateWepKeysConfig.wepKeys = new String[] {tempKey};
1417
1418        // Set up mock to allow the new value to be read back into the config
1419        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1420                WifiConfiguration.wepKeyVarNames[0])).thenReturn(tempKey);
1421
1422        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1423        mWifiConfigManager.addOrUpdateNetwork(updateWepKeysConfig,
1424                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1425
1426        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1427        switchUser(originalUserId);
1428    }
1429
1430    /**
1431     * Verifies that hasEverConnected is cleared when a network config hiddenSSID is
1432     * updated.
1433     */
1434    @Test
1435    public void testUpdateHiddenSSIDChanged() throws Exception {
1436        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1437
1438        testUpdateConfigToHasEverConnectedTrue();
1439
1440        WifiConfiguration updateHiddenSSIDConfig = new WifiConfiguration();
1441        updateHiddenSSIDConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1442        updateHiddenSSIDConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1443        updateHiddenSSIDConfig.hiddenSSID = true;
1444
1445        // Set up mock to allow the new value to be read back into the config
1446        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1447                WifiConfiguration.hiddenSSIDVarName)).thenReturn("1");
1448
1449        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1450        mWifiConfigManager.addOrUpdateNetwork(updateHiddenSSIDConfig,
1451                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1452
1453        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1454        switchUser(originalUserId);
1455    }
1456
1457    /**
1458     * Verifies that hasEverConnected is cleared when a network config pmfVarName is
1459     * updated.
1460     */
1461    @Test
1462    public void testUpdateRequirePMFChanged() throws Exception {
1463        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1464
1465        testUpdateConfigToHasEverConnectedTrue();
1466
1467        WifiConfiguration updateRequirePMFConfig = new WifiConfiguration();
1468        updateRequirePMFConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1469        updateRequirePMFConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1470        updateRequirePMFConfig.requirePMF = true;
1471
1472        // Set up mock to allow the new value to be read back into the config
1473        // TODO: please see b/28088226  - this test is implemented as if WifiConfigStore correctly
1474        // read back the boolean value.  When fixed, uncomment the following line and the
1475        // checkHasEverConnectedFalse below.
1476        //when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1477        //        WifiConfiguration.pmfVarName)).thenReturn("2");
1478
1479        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1480        mWifiConfigManager.addOrUpdateNetwork(updateRequirePMFConfig,
1481                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1482
1483        //checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1484        checkHasEverConnectedTrue(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1485        switchUser(originalUserId);
1486    }
1487
1488    /**
1489     * Verify WifiEnterpriseConfig changes are detected in WifiConfigManager.
1490     */
1491    @Test
1492    public void testEnterpriseConfigAdded() {
1493        EnterpriseConfig eapConfig =  new EnterpriseConfig(Eap.TTLS)
1494                .setPhase2(Phase2.MSCHAPV2)
1495                .setIdentity("username", "password")
1496                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0});
1497
1498        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(null, eapConfig.enterpriseConfig));
1499    }
1500
1501    /**
1502     * Verify WifiEnterpriseConfig eap change is detected.
1503     */
1504    @Test
1505    public void testEnterpriseConfigEapChangeDetected() {
1506        EnterpriseConfig eapConfig = new EnterpriseConfig(Eap.TTLS);
1507        EnterpriseConfig peapConfig = new EnterpriseConfig(Eap.PEAP);
1508
1509        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(eapConfig.enterpriseConfig,
1510                peapConfig.enterpriseConfig));
1511    }
1512
1513    /**
1514     * Verify WifiEnterpriseConfig phase2 method change is detected.
1515     */
1516    @Test
1517    public void testEnterpriseConfigPhase2ChangeDetected() {
1518        EnterpriseConfig eapConfig = new EnterpriseConfig(Eap.TTLS).setPhase2(Phase2.MSCHAPV2);
1519        EnterpriseConfig papConfig = new EnterpriseConfig(Eap.TTLS).setPhase2(Phase2.PAP);
1520
1521        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(eapConfig.enterpriseConfig,
1522                papConfig.enterpriseConfig));
1523    }
1524
1525    /**
1526     * Verify WifiEnterpriseConfig added Certificate is detected.
1527     */
1528    @Test
1529    public void testCaCertificateAddedDetected() {
1530        EnterpriseConfig eapConfigNoCerts =  new EnterpriseConfig(Eap.TTLS)
1531                .setPhase2(Phase2.MSCHAPV2)
1532                .setIdentity("username", "password");
1533
1534        EnterpriseConfig eapConfig1Cert =  new EnterpriseConfig(Eap.TTLS)
1535                .setPhase2(Phase2.MSCHAPV2)
1536                .setIdentity("username", "password")
1537                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0});
1538
1539        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(eapConfigNoCerts.enterpriseConfig,
1540                eapConfig1Cert.enterpriseConfig));
1541    }
1542
1543    /**
1544     * Verify WifiEnterpriseConfig Certificate change is detected.
1545     */
1546    @Test
1547    public void testDifferentCaCertificateDetected() {
1548        EnterpriseConfig eapConfig =  new EnterpriseConfig(Eap.TTLS)
1549                .setPhase2(Phase2.MSCHAPV2)
1550                .setIdentity("username", "password")
1551                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0});
1552
1553        EnterpriseConfig eapConfigNewCert =  new EnterpriseConfig(Eap.TTLS)
1554                .setPhase2(Phase2.MSCHAPV2)
1555                .setIdentity("username", "password")
1556                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT1});
1557
1558        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(eapConfig.enterpriseConfig,
1559                eapConfigNewCert.enterpriseConfig));
1560    }
1561
1562    /**
1563     * Verify WifiEnterpriseConfig added Certificate changes are detected.
1564     */
1565    @Test
1566    public void testCaCertificateChangesDetected() {
1567        EnterpriseConfig eapConfig =  new EnterpriseConfig(Eap.TTLS)
1568                .setPhase2(Phase2.MSCHAPV2)
1569                .setIdentity("username", "password")
1570                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0});
1571
1572        EnterpriseConfig eapConfigAddedCert =  new EnterpriseConfig(Eap.TTLS)
1573                .setPhase2(Phase2.MSCHAPV2)
1574                .setIdentity("username", "password")
1575                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0, FakeKeys.CA_CERT1});
1576
1577        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(eapConfig.enterpriseConfig,
1578                eapConfigAddedCert.enterpriseConfig));
1579    }
1580
1581    /**
1582     * Verify that WifiEnterpriseConfig does not detect changes for identical configs.
1583     */
1584    @Test
1585    public void testWifiEnterpriseConfigNoChanges() {
1586        EnterpriseConfig eapConfig =  new EnterpriseConfig(Eap.TTLS)
1587                .setPhase2(Phase2.MSCHAPV2)
1588                .setIdentity("username", "password")
1589                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0, FakeKeys.CA_CERT1});
1590
1591        // Just to be clear that check is not against the same object
1592        EnterpriseConfig eapConfigSame =  new EnterpriseConfig(Eap.TTLS)
1593                .setPhase2(Phase2.MSCHAPV2)
1594                .setIdentity("username", "password")
1595                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0, FakeKeys.CA_CERT1});
1596
1597        assertFalse(mWifiConfigManager.wasEnterpriseConfigChange(eapConfig.enterpriseConfig,
1598                eapConfigSame.enterpriseConfig));
1599    }
1600
1601
1602    private void checkHasEverConnectedTrue(int networkId) {
1603        WifiConfiguration checkConfig = mWifiConfigManager.getWifiConfiguration(networkId);
1604        assertTrue("hasEverConnected expected to be true.",
1605                checkConfig.getNetworkSelectionStatus().getHasEverConnected());
1606    }
1607
1608    private void checkHasEverConnectedFalse(int networkId) {
1609        WifiConfiguration checkConfig = mWifiConfigManager.getWifiConfiguration(networkId);
1610        assertFalse("Updating credentials network config should clear hasEverConnected.",
1611                checkConfig.getNetworkSelectionStatus().getHasEverConnected());
1612    }
1613
1614    /**
1615     *  Helper function to translate from WifiConfiguration BitSet to String.
1616     */
1617    private static String makeString(BitSet set, String[] strings) {
1618        StringBuffer buf = new StringBuffer();
1619        int nextSetBit = -1;
1620
1621        /* Make sure all set bits are in [0, strings.length) to avoid
1622         * going out of bounds on strings.  (Shouldn't happen, but...) */
1623        set = set.get(0, strings.length);
1624
1625        while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
1626            buf.append(strings[nextSetBit].replace('_', '-')).append(' ');
1627        }
1628
1629        // remove trailing space
1630        if (set.cardinality() > 0) {
1631            buf.setLength(buf.length() - 1);
1632        }
1633
1634        return buf.toString();
1635    }
1636
1637
1638}
1639