WifiConfigManagerTest.java revision e70ba4d25583efb1528f5e7bb32e0fea39a7ab41
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.getSavedNetworks());
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.getPrivilegedSavedNetworks());
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
436                    // a connection attempt was made to it. This does not modify the status of
437                    // other networks.
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                    assertEquals(WifiConfiguration.Status.ENABLED, config.status);
444                }
445            }
446        }
447    }
448
449    /**
450     * Verifies that saveNetwork() correctly stores a network configuration in wpa_supplicant
451     * variables and the networkHistory.txt file.
452     * TODO: Test all variables. Currently, only the following variables are tested:
453     * - In the wpa_supplicant: "ssid", "id_str"
454     * - In networkHistory.txt: "CONFIG", "CREATOR_UID_KEY", "SHARED"
455     */
456    private void verifySaveNetwork(int network) throws Exception {
457        // Switch to the correct user.
458        switchUserToCreatorOrParentOf(CONFIGS.get(network));
459
460        // Set up wpa_supplicant.
461        when(mWifiNative.addNetwork()).thenReturn(0);
462        when(mWifiNative.setNetworkVariable(eq(network), anyString(), anyString()))
463                .thenReturn(true);
464        when(mWifiNative.setNetworkExtra(eq(network), anyString(),
465                (Map<String, String>) anyObject())).thenReturn(true);
466        when(mWifiNative.getNetworkVariable(network, WifiConfiguration.ssidVarName))
467                .thenReturn(encodeConfigSSID(CONFIGS.get(network)));
468        when(mWifiNative.getNetworkVariable(network, WifiConfiguration.pmfVarName))
469                .thenReturn("");
470
471        // Store a network configuration.
472        mWifiConfigManager.saveNetwork(CONFIGS.get(network), CONFIGS.get(network).creatorUid);
473
474        // Verify that wpa_supplicant variables were written correctly for the network
475        // configuration.
476        final Map<String, String> metadata = new HashMap<String, String>();
477        if (CONFIGS.get(network).FQDN != null) {
478            metadata.put(WifiConfigStore.ID_STRING_KEY_FQDN, CONFIGS.get(network).FQDN);
479        }
480        metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(network).configKey());
481        metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
482                Integer.toString(CONFIGS.get(network).creatorUid));
483        verify(mWifiNative).setNetworkExtra(network, WifiConfigStore.ID_STRING_VAR_NAME,
484                metadata);
485
486        // Verify that an attempt to read back the requirePMF variable was made.
487        verify(mWifiNative).getNetworkVariable(network, WifiConfiguration.pmfVarName);
488
489        // Verify that no wpa_supplicant variables were read or written for any other network
490        // configurations.
491        verify(mWifiNative, never()).setNetworkExtra(intThat(not(network)), anyString(),
492                (Map<String, String>) anyObject());
493        verify(mWifiNative, never()).setNetworkVariable(intThat(not(network)), anyString(),
494                anyString());
495        verify(mWifiNative, never()).getNetworkVariable(intThat(not(network)), anyString());
496
497        // Parse networkHistory.txt.
498        assertNotNull(mNetworkHistoryBytes);
499        final DataInputStream stream =
500                new DataInputStream(new ByteArrayInputStream(mNetworkHistoryBytes));
501        List<String> keys = new ArrayList<>();
502        List<String> values = new ArrayList<>();
503        try {
504            while (true) {
505                final String[] tokens = stream.readUTF().split(":", 2);
506                if (tokens.length == 2) {
507                    keys.add(tokens[0].trim());
508                    values.add(tokens[1].trim());
509                }
510            }
511        } catch (EOFException e) {
512            // Ignore. This is expected.
513        }
514
515        // Verify that a networkHistory.txt entry was written correctly for the network
516        // configuration.
517        assertTrue(keys.size() >= 3);
518        assertEquals(WifiNetworkHistory.CONFIG_KEY, keys.get(0));
519        assertEquals(CONFIGS.get(network).configKey(), values.get(0));
520        final int creatorUidIndex = keys.indexOf(WifiNetworkHistory.CREATOR_UID_KEY);
521        assertTrue(creatorUidIndex != -1);
522        assertEquals(Integer.toString(CONFIGS.get(network).creatorUid),
523                values.get(creatorUidIndex));
524        final int sharedIndex = keys.indexOf(WifiNetworkHistory.SHARED_KEY);
525        assertTrue(sharedIndex != -1);
526        assertEquals(Boolean.toString(CONFIGS.get(network).shared), values.get(sharedIndex));
527
528        // Verify that no networkHistory.txt entries were written for any other network
529        // configurations.
530        final int lastConfigIndex = keys.lastIndexOf(WifiNetworkHistory.CONFIG_KEY);
531        assertEquals(0, lastConfigIndex);
532    }
533
534    /**
535     * Verifies that saveNetwork() correctly stores a regular network configuration.
536     */
537    @Test
538    public void testSaveNetworkRegular() throws Exception {
539        verifySaveNetwork(0);
540    }
541
542    /**
543     * Verifies that saveNetwork() correctly stores a HotSpot 2.0 network configuration.
544     */
545    @Test
546    public void testSaveNetworkHotspot20() throws Exception {
547        verifySaveNetwork(1);
548    }
549
550    /**
551     * Verifies that saveNetwork() correctly stores a private network configuration.
552     */
553    @Test
554    public void testSaveNetworkPrivate() throws Exception {
555        verifySaveNetwork(2);
556    }
557
558    /**
559     * Verifies that loadConfiguredNetworks() correctly reads data from the wpa_supplicant, the
560     * networkHistory.txt file and the MOManager, correlating the three sources based on the
561     * configKey and the FQDN for HotSpot 2.0 networks.
562     * TODO: Test all variables. Currently, only the following variables are tested:
563     * - In the wpa_supplicant: "ssid", "id_str"
564     * - In networkHistory.txt: "CONFIG", "CREATOR_UID_KEY", "SHARED"
565     */
566    @Test
567    public void testLoadConfiguredNetworks() throws Exception {
568        // Set up list of network configurations returned by wpa_supplicant.
569        final String header = "network id / ssid / bssid / flags";
570        String networks = header;
571        for (WifiConfiguration config : CONFIGS) {
572            networks += "\n" + Integer.toString(config.networkId) + "\t" + config.SSID + "\tany";
573        }
574        when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
575        when(mWifiNative.listNetworks(-1)).thenReturn(networks);
576
577        // Set up variables returned by wpa_supplicant for the individual network configurations.
578        for (int i = 0; i < CONFIGS.size(); ++i) {
579            when(mWifiNative.getNetworkVariable(i, WifiConfiguration.ssidVarName))
580                .thenReturn(encodeConfigSSID(CONFIGS.get(i)));
581        }
582        // Legacy regular network configuration: No "id_str".
583        when(mWifiNative.getNetworkExtra(0, WifiConfigStore.ID_STRING_VAR_NAME))
584            .thenReturn(null);
585        // Legacy Hotspot 2.0 network configuration: Quoted FQDN in "id_str".
586        when(mWifiNative.getNetworkExtra(1, WifiConfigStore.ID_STRING_VAR_NAME))
587            .thenReturn(null);
588        when(mWifiNative.getNetworkVariable(1, WifiConfigStore.ID_STRING_VAR_NAME))
589            .thenReturn('"' + CONFIGS.get(1).FQDN + '"');
590        // Up-to-date Hotspot 2.0 network configuration: Metadata in "id_str".
591        Map<String, String> metadata = new HashMap<String, String>();
592        metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(2).configKey());
593        metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
594                Integer.toString(CONFIGS.get(2).creatorUid));
595        metadata.put(WifiConfigStore.ID_STRING_KEY_FQDN, CONFIGS.get(2).FQDN);
596        when(mWifiNative.getNetworkExtra(2, WifiConfigStore.ID_STRING_VAR_NAME))
597            .thenReturn(metadata);
598        // Up-to-date regular network configuration: Metadata in "id_str".
599        metadata = new HashMap<String, String>();
600        metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, CONFIGS.get(3).configKey());
601        metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
602                Integer.toString(CONFIGS.get(3).creatorUid));
603        when(mWifiNative.getNetworkExtra(3, WifiConfigStore.ID_STRING_VAR_NAME))
604            .thenReturn(metadata);
605
606        // Set up networkHistory.txt file.
607        final File file = File.createTempFile("networkHistory.txt", null);
608        file.deleteOnExit();
609
610        Field wifiNetworkHistoryConfigFile =
611                WifiNetworkHistory.class.getDeclaredField("NETWORK_HISTORY_CONFIG_FILE");
612        wifiNetworkHistoryConfigFile.setAccessible(true);
613        wifiNetworkHistoryConfigFile.set(null, file.getAbsolutePath());
614
615        final DataOutputStream stream = new DataOutputStream(new FileOutputStream(file));
616        for (WifiConfiguration config : CONFIGS) {
617            stream.writeUTF(WifiNetworkHistory.CONFIG_KEY + ":  " + config.configKey() + '\n');
618            stream.writeUTF(WifiNetworkHistory.CREATOR_UID_KEY + ":  "
619                    + Integer.toString(config.creatorUid) + '\n');
620            stream.writeUTF(WifiNetworkHistory.SHARED_KEY + ":  "
621                    + Boolean.toString(config.shared) + '\n');
622        }
623        stream.close();
624
625        // Set up list of home service providers returned by MOManager.
626        final List<HomeSP> homeSPs = new ArrayList<HomeSP>();
627        for (WifiConfiguration config : CONFIGS) {
628            if (config.FQDN != null) {
629                homeSPs.add(new HomeSP(null, config.FQDN, new HashSet<Long>(),
630                        new HashSet<String>(),
631                        new HashSet<Long>(), new ArrayList<Long>(),
632                        config.providerFriendlyName, null,
633                        new Credential(0, 0, null, false, null, null),
634                        null, 0, null, null, null, 0));
635            }
636        }
637        when(mMOManager.loadAllSPs()).thenReturn(homeSPs);
638
639        // Load network configurations.
640        mWifiConfigManager.loadConfiguredNetworks();
641
642        // Verify that network configurations were loaded and correlated correctly across the three
643        // sources.
644        verifyNetworkConfigs(CONFIGS, mConfiguredNetworks.valuesForAllUsers());
645    }
646
647    /**
648     * Verifies that loadConfiguredNetworks() correctly handles duplicates when reading network
649     * configurations from the wpa_supplicant: The second configuration overwrites the first.
650     */
651    @Test
652    public void testLoadConfiguredNetworksEliminatesDuplicates() throws Exception {
653        final WifiConfiguration config = new WifiConfiguration(CONFIGS.get(0));
654        config.networkId = 1;
655
656        // Set up list of network configurations returned by wpa_supplicant. The two configurations
657        // are identical except for their network IDs.
658        final String header = "network id / ssid / bssid / flags";
659        final String networks =
660                header + "\n0\t" + config.SSID + "\tany\n1\t" + config.SSID + "\tany";
661        when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
662        when(mWifiNative.listNetworks(-1)).thenReturn(networks);
663
664        // Set up variables returned by wpa_supplicant.
665        when(mWifiNative.getNetworkVariable(anyInt(), eq(WifiConfiguration.ssidVarName)))
666            .thenReturn(encodeConfigSSID(config));
667        final Map<String, String> metadata = new HashMap<String, String>();
668        metadata.put(WifiConfigStore.ID_STRING_KEY_CONFIG_KEY, config.configKey());
669        metadata.put(WifiConfigStore.ID_STRING_KEY_CREATOR_UID,
670                Integer.toString(config.creatorUid));
671        when(mWifiNative.getNetworkExtra(anyInt(), eq(WifiConfigStore.ID_STRING_VAR_NAME)))
672            .thenReturn(metadata);
673
674        // Load network configurations.
675        mWifiConfigManager.loadConfiguredNetworks();
676
677        // Verify that the second network configuration (network ID 1) overwrote the first (network
678        // ID 0).
679        verifyNetworkConfigs(Arrays.asList(config), mConfiguredNetworks.valuesForAllUsers());
680    }
681
682    /**
683     * Verifies that handleUserSwitch() removes ephemeral network configurations, disables network
684     * configurations that should no longer be visible and enables network configurations that
685     * should become visible.
686     */
687    private void verifyHandleUserSwitch(int oldUserId, int newUserId,
688            boolean makeOneConfigEphemeral) throws Exception {
689        addNetworks();
690        switchUser(oldUserId);
691
692        reset(mWifiNative);
693        final Field lastSelectedConfigurationField =
694                WifiConfigManager.class.getDeclaredField("mLastSelectedConfiguration");
695        lastSelectedConfigurationField.setAccessible(true);
696        WifiConfiguration removedEphemeralConfig = null;
697        final Set<WifiConfiguration> oldUserOnlyConfigs = new HashSet<>();
698        final Set<WifiConfiguration> newUserOnlyConfigs = new HashSet<>();
699        final Set<WifiConfiguration> neitherUserConfigs = new HashSet<>();
700        final Collection<WifiConfiguration> oldConfigs = mConfiguredNetworks.valuesForAllUsers();
701        int expectedNumberOfConfigs = oldConfigs.size();
702        for (WifiConfiguration config : oldConfigs) {
703            if (WifiConfigurationUtil.isVisibleToAnyProfile(config, USER_PROFILES.get(oldUserId))) {
704                config.status = WifiConfiguration.Status.ENABLED;
705                if (WifiConfigurationUtil.isVisibleToAnyProfile(config,
706                        USER_PROFILES.get(newUserId))) {
707                    if (makeOneConfigEphemeral && removedEphemeralConfig == null) {
708                        config.ephemeral = true;
709                        lastSelectedConfigurationField.set(mWifiConfigManager, config.configKey());
710                        removedEphemeralConfig = config;
711                    }
712                } else {
713                    oldUserOnlyConfigs.add(config);
714                }
715            } else {
716                config.status = WifiConfiguration.Status.DISABLED;
717                if (WifiConfigurationUtil.isVisibleToAnyProfile(config,
718                        USER_PROFILES.get(newUserId))) {
719                    newUserOnlyConfigs.add(config);
720                } else {
721                    neitherUserConfigs.add(config);
722                }
723            }
724        }
725
726        when(mWifiNative.disableNetwork(anyInt())).thenReturn(true);
727        when(mWifiNative.removeNetwork(anyInt())).thenReturn(true);
728
729        switchUser(newUserId);
730        if (makeOneConfigEphemeral) {
731            // Verify that the ephemeral network configuration was removed.
732            assertNotNull(removedEphemeralConfig);
733            assertNull(mConfiguredNetworks.getForAllUsers(removedEphemeralConfig.networkId));
734            assertNull(lastSelectedConfigurationField.get(mWifiConfigManager));
735            verify(mWifiNative).removeNetwork(removedEphemeralConfig.networkId);
736            --expectedNumberOfConfigs;
737        } else {
738            assertNull(removedEphemeralConfig);
739        }
740
741        // Verify that the other network configurations were revealed/hidden and enabled/disabled as
742        // appropriate.
743        final Collection<WifiConfiguration> newConfigs = mConfiguredNetworks.valuesForAllUsers();
744        assertEquals(expectedNumberOfConfigs, newConfigs.size());
745        for (WifiConfiguration config : newConfigs) {
746            if (oldUserOnlyConfigs.contains(config)) {
747                verify(mWifiNative).disableNetwork(config.networkId);
748                assertNetworkStatus(
749                        config,
750                        WifiConfiguration.NetworkSelectionStatus.DISABLED_DUE_TO_USER_SWITCH);
751            } else {
752                verify(mWifiNative, never()).disableNetwork(config.networkId);
753                if (neitherUserConfigs.contains(config)) {
754                    assertNetworkStatus(
755                            config,
756                            WifiConfiguration.NetworkSelectionStatus.DISABLED_DUE_TO_USER_SWITCH);
757                } else {
758                    assertNetworkStatus(
759                            config,
760                            WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE);
761                }
762            }
763        }
764    }
765
766    /**
767     * Verifies that handleUserSwitch() behaves correctly when the user switch removes an ephemeral
768     * network configuration and reveals a private network configuration.
769     */
770    @Test
771    public void testHandleUserSwitchWithEphemeral() throws Exception {
772        verifyHandleUserSwitch(USER_IDS[2], USER_IDS[0], true);
773    }
774
775    /**
776     * Verifies that handleUserSwitch() behaves correctly when the user switch hides a private
777     * network configuration.
778     */
779    @Test
780    public void testHandleUserSwitchWithoutEphemeral() throws Exception {
781        verifyHandleUserSwitch(USER_IDS[0], USER_IDS[2], false);
782    }
783
784    @Test
785    public void testSaveLoadEapNetworks() {
786        testSaveLoadSingleEapNetwork("eap network", new EnterpriseConfig(Eap.TTLS)
787                .setPhase2(Phase2.MSCHAPV2)
788                .setIdentity("username", "password")
789                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0}));
790        testSaveLoadSingleEapNetwork("eap network", new EnterpriseConfig(Eap.TTLS)
791                .setPhase2(Phase2.MSCHAPV2)
792                .setIdentity("username", "password")
793                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT1, FakeKeys.CA_CERT0}));
794
795    }
796
797    private void testSaveLoadSingleEapNetwork(String ssid, EnterpriseConfig eapConfig) {
798        final HashMap<String, String> networkVariables = new HashMap<String, String>();
799        reset(mWifiNative);
800        when(mWifiNative.addNetwork()).thenReturn(0);
801        when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString())).thenAnswer(
802                new AnswerWithArguments() {
803                    public boolean answer(int netId, String name, String value) {
804                        // Verify that no wpa_supplicant variables were written for any other
805                        // network configurations.
806                        assertEquals(netId, 0);
807                        networkVariables.put(name, value);
808                        return true;
809                    }
810                });
811        when(mWifiNative.getNetworkVariable(anyInt(), anyString())).then(
812                new AnswerWithArguments() {
813                    public String answer(int netId, String name) {
814                        // Verify that no wpa_supplicant variables were read for any other
815                        // network configurations.
816                        assertEquals(netId, 0);
817                        return networkVariables.get(name);
818                    }
819                });
820        when(mWifiNative.setNetworkExtra(eq(0), anyString(), (Map<String, String>) anyObject()))
821                .thenReturn(true);
822
823        WifiConfiguration config = new WifiConfiguration();
824        config.SSID = ssid;
825        config.creatorUid = Process.WIFI_UID;
826        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
827        config.enterpriseConfig = eapConfig.enterpriseConfig;
828
829        // Store a network configuration.
830        mWifiConfigManager.saveNetwork(config, Process.WIFI_UID);
831
832        // Verify that wpa_supplicant variables were written correctly for the network
833        // configuration.
834        verify(mWifiNative).addNetwork();
835        assertEquals(eapConfig.eap,
836                unquote(networkVariables.get(WifiEnterpriseConfig.EAP_KEY)));
837        assertEquals(eapConfig.phase2,
838                unquote(networkVariables.get(WifiEnterpriseConfig.PHASE2_KEY)));
839        assertEquals(eapConfig.identity,
840                unquote(networkVariables.get(WifiEnterpriseConfig.IDENTITY_KEY)));
841        assertEquals(eapConfig.password,
842                unquote(networkVariables.get(WifiEnterpriseConfig.PASSWORD_KEY)));
843        assertSavedCaCerts(eapConfig,
844                unquote(networkVariables.get(WifiEnterpriseConfig.CA_CERT_KEY)));
845
846        // Prepare the scan result.
847        final String header = "network id / ssid / bssid / flags";
848        String networks = header + "\n" + Integer.toString(0) + "\t" + ssid + "\tany";
849        when(mWifiNative.listNetworks(anyInt())).thenReturn(header);
850        when(mWifiNative.listNetworks(-1)).thenReturn(networks);
851
852        // Load back the configuration.
853        mWifiConfigManager.loadConfiguredNetworks();
854        List<WifiConfiguration> configs = mWifiConfigManager.getSavedNetworks();
855        assertEquals(1, configs.size());
856        WifiConfiguration loadedConfig = configs.get(0);
857        assertEquals(ssid, unquote(loadedConfig.SSID));
858        BitSet keyMgmt = new BitSet();
859        keyMgmt.set(KeyMgmt.WPA_EAP);
860        assertEquals(keyMgmt, loadedConfig.allowedKeyManagement);
861        assertEquals(eapConfig.enterpriseConfig.getEapMethod(),
862                loadedConfig.enterpriseConfig.getEapMethod());
863        assertEquals(eapConfig.enterpriseConfig.getPhase2Method(),
864                loadedConfig.enterpriseConfig.getPhase2Method());
865        assertEquals(eapConfig.enterpriseConfig.getIdentity(),
866                loadedConfig.enterpriseConfig.getIdentity());
867        assertEquals(eapConfig.enterpriseConfig.getPassword(),
868                loadedConfig.enterpriseConfig.getPassword());
869        asserCaCertsAliasesMatch(eapConfig.caCerts,
870                loadedConfig.enterpriseConfig.getCaCertificateAliases());
871    }
872
873    private String unquote(String value) {
874        if (value == null) {
875            return null;
876        }
877        int length = value.length();
878        if ((length > 1) && (value.charAt(0) == '"')
879                && (value.charAt(length - 1) == '"')) {
880            return value.substring(1, length - 1);
881        } else {
882            return value;
883        }
884    }
885
886    private void asserCaCertsAliasesMatch(X509Certificate[] certs, String[] aliases) {
887        assertEquals(certs.length, aliases.length);
888        List<String> aliasList = new ArrayList<String>(Arrays.asList(aliases));
889        try {
890            for (int i = 0; i < certs.length; i++) {
891                byte[] certPem = Credentials.convertToPem(certs[i]);
892                boolean found = false;
893                for (int j = 0; j < aliasList.size(); j++) {
894                    byte[] keystoreCert = mMockKeyStore.getKeyBlob(Process.WIFI_UID,
895                            Credentials.CA_CERTIFICATE + aliasList.get(j)).blob;
896                    if (Arrays.equals(keystoreCert, certPem)) {
897                        found = true;
898                        aliasList.remove(j);
899                        break;
900                    }
901                }
902                assertTrue(found);
903            }
904        } catch (CertificateEncodingException | IOException e) {
905            fail("Cannot convert CA certificate to encoded form.");
906        }
907    }
908
909    private void assertSavedCaCerts(EnterpriseConfig eapConfig, String caCertVariable) {
910        ArrayList<String> aliases = new ArrayList<String>();
911        if (TextUtils.isEmpty(caCertVariable)) {
912            // Do nothing.
913        } else if (caCertVariable.startsWith(WifiEnterpriseConfig.CA_CERT_PREFIX)) {
914            aliases.add(caCertVariable.substring(WifiEnterpriseConfig.CA_CERT_PREFIX.length()));
915        } else if (caCertVariable.startsWith(WifiEnterpriseConfig.KEYSTORES_URI)) {
916            String[] encodedAliases = TextUtils.split(
917                    caCertVariable.substring(WifiEnterpriseConfig.KEYSTORES_URI.length()),
918                    WifiEnterpriseConfig.CA_CERT_ALIAS_DELIMITER);
919            for (String encodedAlias : encodedAliases) {
920                String alias = WifiEnterpriseConfig.decodeCaCertificateAlias(encodedAlias);
921                assertTrue(alias.startsWith(Credentials.CA_CERTIFICATE));
922                aliases.add(alias.substring(Credentials.CA_CERTIFICATE.length()));
923            }
924        } else {
925            fail("Unrecognized ca_cert variable: " + caCertVariable);
926        }
927        asserCaCertsAliasesMatch(eapConfig.caCerts, aliases.toArray(new String[aliases.size()]));
928    }
929
930    private static class EnterpriseConfig {
931        public String eap;
932        public String phase2;
933        public String identity;
934        public String password;
935        public X509Certificate[] caCerts;
936        public WifiEnterpriseConfig enterpriseConfig;
937
938        public EnterpriseConfig(int eapMethod) {
939            enterpriseConfig = new WifiEnterpriseConfig();
940            enterpriseConfig.setEapMethod(eapMethod);
941            eap = Eap.strings[eapMethod];
942        }
943        public EnterpriseConfig setPhase2(int phase2Method) {
944            enterpriseConfig.setPhase2Method(phase2Method);
945            phase2 = "auth=" + Phase2.strings[phase2Method];
946            return this;
947        }
948        public EnterpriseConfig setIdentity(String identity, String password) {
949            enterpriseConfig.setIdentity(identity);
950            enterpriseConfig.setPassword(password);
951            this.identity = identity;
952            this.password = password;
953            return this;
954        }
955        public EnterpriseConfig setCaCerts(X509Certificate[] certs) {
956            enterpriseConfig.setCaCertificates(certs);
957            caCerts = certs;
958            return this;
959        }
960    }
961
962    /**
963     * Generates an array of unique random numbers below the specified maxValue.
964     * Values range from 0 to maxValue-1.
965     */
966    private static ArrayDeque<Integer> getUniqueRandomNumberValues(
967            int seed,
968            int maxValue,
969            int numValues) {
970        assertTrue(numValues <= maxValue);
971        Random rand = new Random(WifiTestUtil.getTestMethod().hashCode() + seed);
972        ArrayDeque<Integer> randomNumberList = new ArrayDeque<>();
973        for (int i = 0; i < numValues; i++) {
974            int num = rand.nextInt(maxValue);
975            while (randomNumberList.contains(num)) {
976                num = rand.nextInt(maxValue);
977            }
978            randomNumberList.push(num);
979        }
980        return randomNumberList;
981    }
982
983    /**
984     * Verifies that the networks in pnoNetworkList is sorted in the same order as the
985     * network in expectedNetworkIDOrder list.
986     */
987    private static void verifyPnoNetworkListOrder(
988            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList,
989            ArrayList<Integer> expectedNetworkIdOrder) throws Exception  {
990        int i = 0;
991        for (WifiScanner.PnoSettings.PnoNetwork pnoNetwork : pnoNetworkList) {
992            Log.i(TAG, "PNO Network List Index: " + i + ", networkID: " + pnoNetwork.networkId);
993            assertEquals("Expected network ID: " + pnoNetwork.networkId,
994                    pnoNetwork.networkId, expectedNetworkIdOrder.get(i++).intValue());
995        }
996    }
997
998    /**
999     * Verifies the retrieveDisconnectedPnoNetworkList API. The test verifies that the list
1000     * returned from the API is sorted as expected.
1001     */
1002    @Test
1003    public void testDisconnectedPnoNetworkListCreation() throws Exception {
1004        addNetworks();
1005
1006        Random rand = new Random(WifiTestUtil.getTestMethod().hashCode());
1007
1008        // First assign random |numAssociation| values and verify that the list is sorted
1009        // in descending order of |numAssociation| values. Keep NetworkSelectionStatus
1010        // values constant.
1011        for (int userId : USER_IDS) {
1012            switchUser(userId);
1013            TreeMap<Integer, Integer> numAssociationToNetworkIdMap =
1014                    new TreeMap<>(Collections.reverseOrder());
1015            ArrayDeque<Integer> numAssociationValues =
1016                    getUniqueRandomNumberValues(
1017                            1, 10000, mConfiguredNetworks.valuesForCurrentUser().size());
1018            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1019                config.numAssociation = numAssociationValues.pop();
1020                config.priority = rand.nextInt(10000);
1021                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1022                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1023                numAssociationToNetworkIdMap.put(config.numAssociation, config.networkId);
1024                Log.i(TAG, "networkID: " + config.networkId + ", numAssociation: "
1025                        + config.numAssociation);
1026            }
1027            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1028                    mWifiConfigManager.retrieveDisconnectedPnoNetworkList();
1029            verifyPnoNetworkListOrder(pnoNetworkList,
1030                    new ArrayList(numAssociationToNetworkIdMap.values()));
1031        }
1032
1033        // Assign random |priority| values and verify that the list is sorted in descending order
1034        // of |priority| values. Keep numAssociation/NetworkSelectionStatus values constant.
1035        for (int userId : USER_IDS) {
1036            switchUser(userId);
1037            TreeMap<Integer, Integer> priorityToNetworkIdMap =
1038                    new TreeMap<>(Collections.reverseOrder());
1039            ArrayDeque<Integer> priorityValues =
1040                    getUniqueRandomNumberValues(
1041                            2, 10000, mConfiguredNetworks.valuesForCurrentUser().size());
1042            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1043                config.numAssociation = 0;
1044                config.priority = priorityValues.pop();
1045                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1046                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1047                priorityToNetworkIdMap.put(config.priority, config.networkId);
1048                Log.i(TAG, "networkID: " + config.networkId + ", priority: " + config.priority);
1049            }
1050            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1051                    mWifiConfigManager.retrieveDisconnectedPnoNetworkList();
1052            verifyPnoNetworkListOrder(pnoNetworkList,
1053                    new ArrayList(priorityToNetworkIdMap.values()));
1054        }
1055
1056        // Now assign random |NetworkSelectionStatus| values and verify that the list is sorted in
1057        // ascending order of |NetworkSelectionStatus| values.
1058        for (int userId : USER_IDS) {
1059            switchUser(userId);
1060            TreeMap<Integer, Integer> networkSelectionStatusToNetworkIdMap = new TreeMap<>();
1061            ArrayDeque<Integer> networkSelectionStatusValues =
1062                    getUniqueRandomNumberValues(
1063                            3,
1064                            WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_STATUS_MAX,
1065                            mConfiguredNetworks.valuesForCurrentUser().size());
1066            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1067                config.numAssociation = rand.nextInt(10000);
1068                config.priority = rand.nextInt(10000);
1069                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1070                        networkSelectionStatusValues.pop());
1071                networkSelectionStatusToNetworkIdMap.put(
1072                        config.getNetworkSelectionStatus().getNetworkSelectionStatus(),
1073                        config.networkId);
1074                Log.i(TAG, "networkID: " + config.networkId + ", NetworkSelectionStatus: "
1075                        + config.getNetworkSelectionStatus().getNetworkSelectionStatus());
1076            }
1077            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1078                    mWifiConfigManager.retrieveDisconnectedPnoNetworkList();
1079            verifyPnoNetworkListOrder(pnoNetworkList,
1080                    new ArrayList(networkSelectionStatusToNetworkIdMap.values()));
1081        }
1082    }
1083
1084    /**
1085     * Verifies the retrieveConnectedPnoNetworkList API. The test verifies that the list
1086     * returned from the API is sorted as expected.
1087     */
1088    @Test
1089    public void testConnectedPnoNetworkListCreation() throws Exception {
1090        addNetworks();
1091
1092        Random rand = new Random(WifiTestUtil.getTestMethod().hashCode());
1093
1094        // First assign |lastSeen| values and verify that the list is sorted
1095        // in descending order of |lastSeen| values. Keep NetworkSelectionStatus
1096        // values constant.
1097        for (int userId : USER_IDS) {
1098            switchUser(userId);
1099            TreeMap<Boolean, Integer> lastSeenToNetworkIdMap =
1100                    new TreeMap<>(Collections.reverseOrder());
1101            ArrayDeque<Integer> lastSeenValues = getUniqueRandomNumberValues(1, 2, 2);
1102            if (mConfiguredNetworks.valuesForCurrentUser().size() > 2) continue;
1103            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1104                config.numAssociation = rand.nextInt(10000);
1105                config.priority = rand.nextInt(10000);
1106                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1107                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1108                boolean lastSeenValue = (lastSeenValues.pop()  == 1);
1109                config.getNetworkSelectionStatus().setSeenInLastQualifiedNetworkSelection(
1110                        lastSeenValue);
1111                lastSeenToNetworkIdMap.put(lastSeenValue, config.networkId);
1112                Log.i(TAG, "networkID: " + config.networkId + ", lastSeen: " + lastSeenValue);
1113            }
1114            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1115                    mWifiConfigManager.retrieveConnectedPnoNetworkList();
1116            verifyPnoNetworkListOrder(pnoNetworkList,
1117                    new ArrayList(lastSeenToNetworkIdMap.values()));
1118        }
1119
1120        // Assign random |numAssociation| values and verify that the list is sorted
1121        // in descending order of |numAssociation| values. Keep NetworkSelectionStatus/lastSeen
1122        // values constant.
1123        for (int userId : USER_IDS) {
1124            switchUser(userId);
1125            TreeMap<Integer, Integer> numAssociationToNetworkIdMap =
1126                    new TreeMap<>(Collections.reverseOrder());
1127            ArrayDeque<Integer> numAssociationValues =
1128                    getUniqueRandomNumberValues(
1129                            1, 10000, mConfiguredNetworks.valuesForCurrentUser().size());
1130            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1131                config.numAssociation = numAssociationValues.pop();
1132                config.priority = rand.nextInt(10000);
1133                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1134                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED);
1135                config.getNetworkSelectionStatus().setSeenInLastQualifiedNetworkSelection(true);
1136                numAssociationToNetworkIdMap.put(config.numAssociation, config.networkId);
1137                Log.i(TAG, "networkID: " + config.networkId + ", numAssociation: "
1138                        + config.numAssociation);
1139            }
1140            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1141                    mWifiConfigManager.retrieveConnectedPnoNetworkList();
1142            verifyPnoNetworkListOrder(pnoNetworkList,
1143                    new ArrayList(numAssociationToNetworkIdMap.values()));
1144        }
1145
1146        // Now assign random |NetworkSelectionStatus| values and verify that the list is sorted in
1147        // ascending order of |NetworkSelectionStatus| values.
1148        for (int userId : USER_IDS) {
1149            switchUser(userId);
1150            TreeMap<Integer, Integer> networkSelectionStatusToNetworkIdMap = new TreeMap<>();
1151            ArrayDeque<Integer> networkSelectionStatusValues =
1152                    getUniqueRandomNumberValues(
1153                            3,
1154                            WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_STATUS_MAX,
1155                            mConfiguredNetworks.valuesForCurrentUser().size());
1156            for (WifiConfiguration config : mConfiguredNetworks.valuesForCurrentUser()) {
1157                config.numAssociation = rand.nextInt(10000);
1158                config.priority = rand.nextInt(10000);
1159                config.getNetworkSelectionStatus().setNetworkSelectionStatus(
1160                        networkSelectionStatusValues.pop());
1161                networkSelectionStatusToNetworkIdMap.put(
1162                        config.getNetworkSelectionStatus().getNetworkSelectionStatus(),
1163                        config.networkId);
1164                Log.i(TAG, "networkID: " + config.networkId + ", NetworkSelectionStatus: "
1165                        + config.getNetworkSelectionStatus().getNetworkSelectionStatus());
1166            }
1167            ArrayList<WifiScanner.PnoSettings.PnoNetwork> pnoNetworkList =
1168                    mWifiConfigManager.retrieveConnectedPnoNetworkList();
1169            verifyPnoNetworkListOrder(pnoNetworkList,
1170                    new ArrayList(networkSelectionStatusToNetworkIdMap.values()));
1171        }
1172    }
1173
1174    /**
1175     * Verifies that hasEverConnected is false for a newly added network
1176     */
1177    @Test
1178    public void testAddNetworkHasEverConnectedFalse() throws Exception {
1179        addNetwork(BASE_HAS_EVER_CONNECTED_CONFIG);
1180        WifiConfiguration checkConfig = mWifiConfigManager.getWifiConfiguration(
1181                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1182        assertFalse("Adding a new network should not have hasEverConnected set to true.",
1183                checkConfig.getNetworkSelectionStatus().getHasEverConnected());
1184    }
1185
1186
1187    /**
1188     * Verifies that hasEverConnected is false for a newly added network even when new config has
1189     * mistakenly set HasEverConnected to true.
1190    */
1191    @Test
1192    public void testAddNetworkOverridesHasEverConnectedWhenTrueInNewConfig() throws Exception {
1193        WifiConfiguration newNetworkWithHasEverConnectedTrue =
1194                new WifiConfiguration(BASE_HAS_EVER_CONNECTED_CONFIG);
1195        newNetworkWithHasEverConnectedTrue.getNetworkSelectionStatus().setHasEverConnected(true);
1196        addNetwork(newNetworkWithHasEverConnectedTrue);
1197        // check if addNetwork clears the bit.
1198        WifiConfiguration checkConfig = mWifiConfigManager.getWifiConfiguration(
1199                newNetworkWithHasEverConnectedTrue.networkId);
1200        assertFalse("Adding a new network should not have hasEverConnected set to true.",
1201                checkConfig.getNetworkSelectionStatus().getHasEverConnected());
1202    }
1203
1204
1205    /**
1206     * Verify that setting HasEverConnected with a config update can be read back.
1207     */
1208    @Test
1209    public void testUpdateConfigToHasEverConnectedTrue() throws Exception {
1210        addNetwork(BASE_HAS_EVER_CONNECTED_CONFIG);
1211
1212        // Get the newly saved config and update HasEverConnected
1213        WifiConfiguration checkConfig = mWifiConfigManager.getWifiConfiguration(
1214                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1215        assertFalse("Adding a new network should not have hasEverConnected set to true.",
1216                checkConfig.getNetworkSelectionStatus().getHasEverConnected());
1217        checkConfig.getNetworkSelectionStatus().setHasEverConnected(true);
1218        mWifiConfigManager.addOrUpdateNetwork(checkConfig, HAS_EVER_CONNECTED_USER);
1219
1220        // verify that HasEverConnected was properly written and read back
1221        checkHasEverConnectedTrue(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1222    }
1223
1224
1225    /**
1226     * Verifies that hasEverConnected is cleared when a network config preSharedKey is updated.
1227     */
1228    @Test
1229    public void testUpdatePreSharedKeyClearsHasEverConnected() throws Exception {
1230        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1231
1232        testUpdateConfigToHasEverConnectedTrue();
1233
1234        WifiConfiguration original = mWifiConfigManager.getWifiConfiguration(
1235                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1236
1237        WifiConfiguration updatePreSharedKeyConfig = new WifiConfiguration();
1238        updatePreSharedKeyConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1239        updatePreSharedKeyConfig.SSID = original.SSID;
1240        updatePreSharedKeyConfig.preSharedKey = "newpassword";
1241        switchUserToCreatorOrParentOf(original);
1242        mWifiConfigManager.addOrUpdateNetwork(updatePreSharedKeyConfig,
1243                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1244
1245        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1246        switchUser(originalUserId);
1247    }
1248
1249    /**
1250     * Verifies that hasEverConnected is cleared when a network config allowedKeyManagement is
1251     * updated.
1252     */
1253    @Test
1254    public void testUpdateAllowedKeyManagementChanged() throws Exception {
1255        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1256
1257        testUpdateConfigToHasEverConnectedTrue();
1258
1259        WifiConfiguration updateAllowedKeyManagementConfig = new WifiConfiguration();
1260        updateAllowedKeyManagementConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1261        updateAllowedKeyManagementConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1262        updateAllowedKeyManagementConfig.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
1263
1264        // Set up mock to allow the new value to be read back into the config
1265        String allowedKeyManagementString = makeString(
1266                updateAllowedKeyManagementConfig.allowedKeyManagement,
1267                    WifiConfiguration.KeyMgmt.strings);
1268        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1269                KeyMgmt.varName)).thenReturn(allowedKeyManagementString);
1270
1271        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1272        mWifiConfigManager.addOrUpdateNetwork(updateAllowedKeyManagementConfig,
1273                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1274
1275        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1276        switchUser(originalUserId);
1277    }
1278
1279    /**
1280     * Verifies that hasEverConnected is cleared when a network config allowedProtocols is
1281     * updated.
1282     */
1283    @Test
1284    public void testUpdateAllowedProtocolsChanged() throws Exception {
1285        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1286
1287        testUpdateConfigToHasEverConnectedTrue();
1288
1289        WifiConfiguration updateAllowedProtocolsConfig = new WifiConfiguration();
1290        updateAllowedProtocolsConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1291        updateAllowedProtocolsConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1292        updateAllowedProtocolsConfig.allowedProtocols.set(
1293                WifiConfiguration.Protocol.RSN);
1294
1295        // Set up mock to allow the new value to be read back into the config
1296        String allowedProtocolsString = makeString(
1297                updateAllowedProtocolsConfig.allowedProtocols,
1298                    WifiConfiguration.Protocol.strings);
1299        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1300                Protocol.varName)).thenReturn(allowedProtocolsString);
1301
1302        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1303        mWifiConfigManager.addOrUpdateNetwork(updateAllowedProtocolsConfig,
1304                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1305
1306        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1307        switchUser(originalUserId);
1308    }
1309
1310    /**
1311     * Verifies that hasEverConnected is cleared when a network config allowedAuthAlgorithms is
1312     * updated.
1313     */
1314    @Test
1315    public void testUpdateAllowedAuthAlgorithmsChanged() throws Exception {
1316        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1317
1318        testUpdateConfigToHasEverConnectedTrue();
1319
1320        WifiConfiguration updateAllowedAuthAlgorithmsConfig = new WifiConfiguration();
1321        updateAllowedAuthAlgorithmsConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1322        updateAllowedAuthAlgorithmsConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1323        updateAllowedAuthAlgorithmsConfig.allowedAuthAlgorithms.set(
1324                WifiConfiguration.AuthAlgorithm.SHARED);
1325
1326        // Set up mock to allow the new value to be read back into the config
1327        String allowedAuthAlgorithmsString = makeString(
1328                updateAllowedAuthAlgorithmsConfig.allowedAuthAlgorithms,
1329                    WifiConfiguration.AuthAlgorithm.strings);
1330        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1331                AuthAlgorithm.varName)).thenReturn(allowedAuthAlgorithmsString);
1332
1333        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1334        mWifiConfigManager.addOrUpdateNetwork(updateAllowedAuthAlgorithmsConfig,
1335                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1336
1337        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1338        switchUser(originalUserId);
1339    }
1340
1341    /**
1342     * Verifies that hasEverConnected is cleared when a network config allowedPairwiseCiphers is
1343     * updated.
1344     */
1345    @Test
1346    public void testUpdateAllowedPairwiseCiphersChanged() throws Exception {
1347        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1348
1349        testUpdateConfigToHasEverConnectedTrue();
1350
1351        WifiConfiguration updateAllowedPairwiseCiphersConfig = new WifiConfiguration();
1352        updateAllowedPairwiseCiphersConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1353        updateAllowedPairwiseCiphersConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1354        updateAllowedPairwiseCiphersConfig.allowedPairwiseCiphers.set(
1355                WifiConfiguration.PairwiseCipher.CCMP);
1356
1357        // Set up mock to allow the new value to be read back into the config
1358        String allowedPairwiseCiphersString = makeString(
1359                updateAllowedPairwiseCiphersConfig.allowedPairwiseCiphers,
1360                    WifiConfiguration.PairwiseCipher.strings);
1361        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1362                PairwiseCipher.varName)).thenReturn(allowedPairwiseCiphersString);
1363
1364        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1365        mWifiConfigManager.addOrUpdateNetwork(updateAllowedPairwiseCiphersConfig,
1366                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1367
1368        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1369        switchUser(originalUserId);
1370    }
1371
1372    /**
1373     * Verifies that hasEverConnected is cleared when a network config allowedGroupCiphers is
1374     * updated.
1375     */
1376    @Test
1377    public void testUpdateAllowedGroupCiphersChanged() throws Exception {
1378        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1379
1380        testUpdateConfigToHasEverConnectedTrue();
1381
1382        WifiConfiguration updateAllowedGroupCiphersConfig = new WifiConfiguration();
1383        updateAllowedGroupCiphersConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1384        updateAllowedGroupCiphersConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1385        updateAllowedGroupCiphersConfig.allowedGroupCiphers.set(
1386                WifiConfiguration.GroupCipher.CCMP);
1387
1388        // Set up mock to allow the new value to be read back into the config
1389        String allowedGroupCiphersString = makeString(
1390                updateAllowedGroupCiphersConfig.allowedGroupCiphers,
1391                    WifiConfiguration.GroupCipher.strings);
1392        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1393                GroupCipher.varName)).thenReturn(allowedGroupCiphersString);
1394
1395        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1396        mWifiConfigManager.addOrUpdateNetwork(updateAllowedGroupCiphersConfig,
1397                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1398
1399        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1400        switchUser(originalUserId);
1401    }
1402
1403    /**
1404     * Verifies that hasEverConnected is cleared when a network config wepKeys is
1405     * updated.
1406     */
1407    @Test
1408    public void testUpdateWepKeysChanged() throws Exception {
1409        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1410
1411        testUpdateConfigToHasEverConnectedTrue();
1412
1413        String tempKey = "hereisakey";
1414        WifiConfiguration updateWepKeysConfig = new WifiConfiguration();
1415        updateWepKeysConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1416        updateWepKeysConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1417        updateWepKeysConfig.wepKeys = new String[] {tempKey};
1418
1419        // Set up mock to allow the new value to be read back into the config
1420        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1421                WifiConfiguration.wepKeyVarNames[0])).thenReturn(tempKey);
1422
1423        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1424        mWifiConfigManager.addOrUpdateNetwork(updateWepKeysConfig,
1425                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1426
1427        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1428        switchUser(originalUserId);
1429    }
1430
1431    /**
1432     * Verifies that hasEverConnected is cleared when a network config hiddenSSID is
1433     * updated.
1434     */
1435    @Test
1436    public void testUpdateHiddenSSIDChanged() throws Exception {
1437        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1438
1439        testUpdateConfigToHasEverConnectedTrue();
1440
1441        WifiConfiguration updateHiddenSSIDConfig = new WifiConfiguration();
1442        updateHiddenSSIDConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1443        updateHiddenSSIDConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1444        updateHiddenSSIDConfig.hiddenSSID = true;
1445
1446        // Set up mock to allow the new value to be read back into the config
1447        when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1448                WifiConfiguration.hiddenSSIDVarName)).thenReturn("1");
1449
1450        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1451        mWifiConfigManager.addOrUpdateNetwork(updateHiddenSSIDConfig,
1452                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1453
1454        checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1455        switchUser(originalUserId);
1456    }
1457
1458    /**
1459     * Verifies that hasEverConnected is cleared when a network config pmfVarName is
1460     * updated.
1461     */
1462    @Test
1463    public void testUpdateRequirePMFChanged() throws Exception {
1464        final int originalUserId = mWifiConfigManager.getCurrentUserId();
1465
1466        testUpdateConfigToHasEverConnectedTrue();
1467
1468        WifiConfiguration updateRequirePMFConfig = new WifiConfiguration();
1469        updateRequirePMFConfig.networkId = BASE_HAS_EVER_CONNECTED_CONFIG.networkId;
1470        updateRequirePMFConfig.SSID = BASE_HAS_EVER_CONNECTED_CONFIG.SSID;
1471        updateRequirePMFConfig.requirePMF = true;
1472
1473        // Set up mock to allow the new value to be read back into the config
1474        // TODO: please see b/28088226  - this test is implemented as if WifiConfigStore correctly
1475        // read back the boolean value.  When fixed, uncomment the following line and the
1476        // checkHasEverConnectedFalse below.
1477        //when(mWifiNative.getNetworkVariable(BASE_HAS_EVER_CONNECTED_CONFIG.networkId,
1478        //        WifiConfiguration.pmfVarName)).thenReturn("2");
1479
1480        switchUserToCreatorOrParentOf(BASE_HAS_EVER_CONNECTED_CONFIG);
1481        mWifiConfigManager.addOrUpdateNetwork(updateRequirePMFConfig,
1482                BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1483
1484        //checkHasEverConnectedFalse(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1485        checkHasEverConnectedTrue(BASE_HAS_EVER_CONNECTED_CONFIG.networkId);
1486        switchUser(originalUserId);
1487    }
1488
1489    /**
1490     * Verify WifiEnterpriseConfig changes are detected in WifiConfigManager.
1491     */
1492    @Test
1493    public void testEnterpriseConfigAdded() {
1494        EnterpriseConfig eapConfig =  new EnterpriseConfig(Eap.TTLS)
1495                .setPhase2(Phase2.MSCHAPV2)
1496                .setIdentity("username", "password")
1497                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0});
1498
1499        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(null, eapConfig.enterpriseConfig));
1500    }
1501
1502    /**
1503     * Verify WifiEnterpriseConfig eap change is detected.
1504     */
1505    @Test
1506    public void testEnterpriseConfigEapChangeDetected() {
1507        EnterpriseConfig eapConfig = new EnterpriseConfig(Eap.TTLS);
1508        EnterpriseConfig peapConfig = new EnterpriseConfig(Eap.PEAP);
1509
1510        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(eapConfig.enterpriseConfig,
1511                peapConfig.enterpriseConfig));
1512    }
1513
1514    /**
1515     * Verify WifiEnterpriseConfig phase2 method change is detected.
1516     */
1517    @Test
1518    public void testEnterpriseConfigPhase2ChangeDetected() {
1519        EnterpriseConfig eapConfig = new EnterpriseConfig(Eap.TTLS).setPhase2(Phase2.MSCHAPV2);
1520        EnterpriseConfig papConfig = new EnterpriseConfig(Eap.TTLS).setPhase2(Phase2.PAP);
1521
1522        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(eapConfig.enterpriseConfig,
1523                papConfig.enterpriseConfig));
1524    }
1525
1526    /**
1527     * Verify WifiEnterpriseConfig added Certificate is detected.
1528     */
1529    @Test
1530    public void testCaCertificateAddedDetected() {
1531        EnterpriseConfig eapConfigNoCerts =  new EnterpriseConfig(Eap.TTLS)
1532                .setPhase2(Phase2.MSCHAPV2)
1533                .setIdentity("username", "password");
1534
1535        EnterpriseConfig eapConfig1Cert =  new EnterpriseConfig(Eap.TTLS)
1536                .setPhase2(Phase2.MSCHAPV2)
1537                .setIdentity("username", "password")
1538                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0});
1539
1540        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(eapConfigNoCerts.enterpriseConfig,
1541                eapConfig1Cert.enterpriseConfig));
1542    }
1543
1544    /**
1545     * Verify WifiEnterpriseConfig Certificate change is detected.
1546     */
1547    @Test
1548    public void testDifferentCaCertificateDetected() {
1549        EnterpriseConfig eapConfig =  new EnterpriseConfig(Eap.TTLS)
1550                .setPhase2(Phase2.MSCHAPV2)
1551                .setIdentity("username", "password")
1552                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0});
1553
1554        EnterpriseConfig eapConfigNewCert =  new EnterpriseConfig(Eap.TTLS)
1555                .setPhase2(Phase2.MSCHAPV2)
1556                .setIdentity("username", "password")
1557                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT1});
1558
1559        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(eapConfig.enterpriseConfig,
1560                eapConfigNewCert.enterpriseConfig));
1561    }
1562
1563    /**
1564     * Verify WifiEnterpriseConfig added Certificate changes are detected.
1565     */
1566    @Test
1567    public void testCaCertificateChangesDetected() {
1568        EnterpriseConfig eapConfig =  new EnterpriseConfig(Eap.TTLS)
1569                .setPhase2(Phase2.MSCHAPV2)
1570                .setIdentity("username", "password")
1571                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0});
1572
1573        EnterpriseConfig eapConfigAddedCert =  new EnterpriseConfig(Eap.TTLS)
1574                .setPhase2(Phase2.MSCHAPV2)
1575                .setIdentity("username", "password")
1576                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0, FakeKeys.CA_CERT1});
1577
1578        assertTrue(mWifiConfigManager.wasEnterpriseConfigChange(eapConfig.enterpriseConfig,
1579                eapConfigAddedCert.enterpriseConfig));
1580    }
1581
1582    /**
1583     * Verify that WifiEnterpriseConfig does not detect changes for identical configs.
1584     */
1585    @Test
1586    public void testWifiEnterpriseConfigNoChanges() {
1587        EnterpriseConfig eapConfig =  new EnterpriseConfig(Eap.TTLS)
1588                .setPhase2(Phase2.MSCHAPV2)
1589                .setIdentity("username", "password")
1590                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0, FakeKeys.CA_CERT1});
1591
1592        // Just to be clear that check is not against the same object
1593        EnterpriseConfig eapConfigSame =  new EnterpriseConfig(Eap.TTLS)
1594                .setPhase2(Phase2.MSCHAPV2)
1595                .setIdentity("username", "password")
1596                .setCaCerts(new X509Certificate[] {FakeKeys.CA_CERT0, FakeKeys.CA_CERT1});
1597
1598        assertFalse(mWifiConfigManager.wasEnterpriseConfigChange(eapConfig.enterpriseConfig,
1599                eapConfigSame.enterpriseConfig));
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     * Test whether enableNetwork with the disableOthers flag set to false enables the
1639     * input network, but does not attempt a connection.
1640     */
1641    @Test
1642    public void testEnableNetworkWithoutDisableOthers() throws Exception {
1643        addNetworks();
1644
1645        for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
1646            switchUser(entry.getKey());
1647            // Iterate through all the configs for the current user and invoke |enableNetwork|
1648            // on the corresponding config retrieved from WifiConfigManager.
1649            for (WifiConfiguration config : entry.getValue()) {
1650                WifiConfiguration retrievedConfig =
1651                        mWifiConfigManager.getWifiConfiguration(config.networkId);
1652                assertTrue(mWifiConfigManager.enableNetwork(retrievedConfig, false, 0));
1653                assertNetworkStatus(retrievedConfig,
1654                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE);
1655                verify(mWifiNative, never()).selectNetwork(anyInt());
1656            }
1657        }
1658    }
1659
1660    /**
1661     * Test whether enableNetwork without the disableOthers flag set to true enables the input
1662     * network and attempts a connection to it immediately. It also checks if all the other
1663     * networks are disabled.
1664     */
1665    @Test
1666    public void testEnableNetworkWithDisableOthers() throws Exception {
1667        addNetworks();
1668
1669        for (Map.Entry<Integer, List<WifiConfiguration>> entry : VISIBLE_CONFIGS.entrySet()) {
1670            switchUser(entry.getKey());
1671            // Iterate through all the configs for the current user and invoke |enableNetwork|
1672            // on the corresponding config retrieved from WifiConfigManager.
1673            for (WifiConfiguration config : entry.getValue()) {
1674                reset(mWifiNative);
1675                when(mWifiNative.selectNetwork(anyInt())).thenReturn(true);
1676                WifiConfiguration retrievedConfig =
1677                        mWifiConfigManager.getWifiConfiguration(config.networkId);
1678                assertTrue(mWifiConfigManager.enableNetwork(retrievedConfig, true, 0));
1679                assertNetworkStatus(retrievedConfig,
1680                        WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE);
1681                assertAllNetworksDisabledExcept(retrievedConfig.networkId,
1682                        WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WIFI_MANAGER);
1683                verify(mWifiNative).selectNetwork(retrievedConfig.networkId);
1684                verify(mWifiNative, never()).selectNetwork(intThat(not(retrievedConfig.networkId)));
1685            }
1686        }
1687    }
1688
1689    private void assertNetworkStatus(WifiConfiguration config, int disableReason) {
1690        final WifiConfiguration.NetworkSelectionStatus status = config.getNetworkSelectionStatus();
1691        assertEquals(disableReason, status.getNetworkSelectionDisableReason());
1692        if (disableReason
1693                == WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE) {
1694            assertEquals(WifiConfiguration.Status.ENABLED, config.status);
1695            assertTrue(config.getNetworkSelectionStatus().isNetworkEnabled());
1696        } else if (disableReason
1697                < WifiConfiguration.NetworkSelectionStatus.DISABLED_TLS_VERSION_MISMATCH) {
1698            assertEquals(WifiConfiguration.Status.ENABLED, config.status);
1699            assertTrue(config.getNetworkSelectionStatus().isNetworkTemporaryDisabled());
1700        } else {
1701            assertEquals(WifiConfiguration.Status.DISABLED, config.status);
1702            assertTrue(config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled());
1703        }
1704    }
1705
1706    private void assertAllNetworksDisabledExcept(int netId, int disableReason) {
1707        for (WifiConfiguration config : mWifiConfigManager.getSavedNetworks()) {
1708            if (config.networkId != netId) {
1709                assertNetworkStatus(config, disableReason);
1710            }
1711        }
1712    }
1713}
1714