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