WifiNetworkSelectorTest.java revision 42f602b9ace875b5bf25640fc4f8c708bb8a9c0e
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 com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_NONE;
20import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_PSK;
21
22import static org.junit.Assert.*;
23import static org.mockito.Mockito.*;
24
25import android.content.Context;
26import android.content.res.Resources;
27import android.net.NetworkScoreManager;
28import android.net.wifi.ScanResult;
29import android.net.wifi.WifiConfiguration;
30import android.net.wifi.WifiInfo;
31import android.os.SystemClock;
32import android.test.suitebuilder.annotation.SmallTest;
33import android.util.Pair;
34
35import com.android.internal.R;
36import com.android.server.wifi.WifiNetworkSelectorTestUtil.ScanDetailsAndWifiConfigs;
37
38import org.junit.After;
39import org.junit.Before;
40import org.junit.Test;
41
42import java.util.List;
43
44/**
45 * Unit tests for {@link com.android.server.wifi.WifiNetworkSelector}.
46 */
47@SmallTest
48public class WifiNetworkSelectorTest {
49
50    /** Sets up test. */
51    @Before
52    public void setUp() throws Exception {
53        mResource = getResource();
54        mContext = getContext();
55        mWifiConfigManager = getWifiConfigManager();
56        mWifiInfo = getWifiInfo();
57
58        mWifiNetworkSelector = new WifiNetworkSelector(mContext, mWifiConfigManager,
59                mWifiInfo, mClock);
60        mWifiNetworkSelector.registerNetworkEvaluator(mDummyEvaluator, 1);
61        when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime());
62
63        mThresholdMinimumRssi2G = mResource.getInteger(
64                R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
65        mThresholdMinimumRssi5G = mResource.getInteger(
66                R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
67        mThresholdQualifiedRssi2G = mResource.getInteger(
68                R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
69        mThresholdQualifiedRssi5G = mResource.getInteger(
70                R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz);
71    }
72
73    /** Cleans up test. */
74    @After
75    public void cleanup() {
76        validateMockitoUsage();
77    }
78
79    /**
80     * All this dummy network evaluator does is to pick the very first network
81     * in the scan results.
82     */
83    public class DummyNetworkEvaluator implements WifiNetworkSelector.NetworkEvaluator {
84        private static final String NAME = "DummyNetworkEvaluator";
85        private WifiConfigManager mConfigManager;
86
87        /**
88         * Get the evaluator name.
89         */
90        public String getName() {
91            return NAME;
92        }
93
94        /**
95         * Update thee evaluator.
96         */
97        public void update(List<ScanDetail> scanDetails) {
98        }
99
100        /**
101         * Always return the first network in the scan results for connection.
102         */
103        public WifiConfiguration evaluateNetworks(List<ScanDetail> scanDetails,
104                    WifiConfiguration currentNetwork, String currentBssid, boolean connected,
105                    boolean untrustedNetworkAllowed,
106                    List<Pair<ScanDetail, WifiConfiguration>> connectableNetworks) {
107            ScanDetail scanDetail = scanDetails.get(0);
108            mWifiConfigManager.setNetworkCandidateScanResult(0, scanDetail.getScanResult(), 100);
109
110            return mWifiConfigManager.getSavedNetworkForScanDetailAndCache(scanDetail);
111        }
112    }
113
114    private WifiNetworkSelector mWifiNetworkSelector = null;
115    private DummyNetworkEvaluator mDummyEvaluator = new DummyNetworkEvaluator();
116    private WifiConfigManager mWifiConfigManager = null;
117    private Context mContext;
118    private Resources mResource;
119    private WifiInfo mWifiInfo;
120    private Clock mClock = mock(Clock.class);
121    private int mThresholdMinimumRssi2G;
122    private int mThresholdMinimumRssi5G;
123    private int mThresholdQualifiedRssi2G;
124    private int mThresholdQualifiedRssi5G;
125
126    Context getContext() {
127        Context context = mock(Context.class);
128        Resources resource = mock(Resources.class);
129
130        when(context.getResources()).thenReturn(mResource);
131        return context;
132    }
133
134    Resources getResource() {
135        Resources resource = mock(Resources.class);
136
137        when(resource.getBoolean(
138                R.bool.config_wifi_framework_enable_associated_network_selection)).thenReturn(true);
139        when(resource.getInteger(
140                R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz))
141                .thenReturn(-70);
142        when(resource.getInteger(
143                R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz))
144                .thenReturn(-73);
145        when(resource.getInteger(
146                R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz))
147                .thenReturn(-82);
148        when(resource.getInteger(
149                R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz))
150                .thenReturn(-85);
151        return resource;
152    }
153
154    NetworkScoreManager getNetworkScoreManager() {
155        NetworkScoreManager networkScoreManager = mock(NetworkScoreManager.class);
156
157        return networkScoreManager;
158    }
159
160    WifiInfo getWifiInfo() {
161        WifiInfo wifiInfo = mock(WifiInfo.class);
162
163        // simulate a disconnected state
164        when(wifiInfo.is24GHz()).thenReturn(true);
165        when(wifiInfo.is5GHz()).thenReturn(false);
166        when(wifiInfo.getRssi()).thenReturn(-70);
167        when(wifiInfo.getNetworkId()).thenReturn(WifiConfiguration.INVALID_NETWORK_ID);
168        when(wifiInfo.getBSSID()).thenReturn(null);
169        return wifiInfo;
170    }
171
172    WifiConfigManager getWifiConfigManager() {
173        WifiConfigManager wifiConfigManager = mock(WifiConfigManager.class);
174        when(wifiConfigManager.getLastSelectedNetwork())
175                .thenReturn(WifiConfiguration.INVALID_NETWORK_ID);
176        return wifiConfigManager;
177    }
178
179
180    /**
181     * No network selection if scan result is empty.
182     *
183     * WifiStateMachine is in disconnected state.
184     * scanDetails is empty.
185     *
186     * Expected behavior: no network recommended by Network Selector
187     */
188    @Test
189    public void emptyScanResults() {
190        String[] ssids = new String[0];
191        String[] bssids = new String[0];
192        int[] freqs = new int[0];
193        String[] caps = new String[0];
194        int[] levels = new int[0];
195        int[] securities = new int[0];
196
197        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
198                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
199                    freqs, caps, levels, securities, mWifiConfigManager, mClock);
200        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
201        WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
202                false, true, false);
203        assertEquals("Expect null configuration", null, candidate);
204    }
205
206
207    /**
208     * No network selection if the RSSI values in scan result are too low.
209     *
210     * WifiStateMachine is in disconnected state.
211     * scanDetails contains a 2.4GHz and a 5GHz network, but both with RSSI lower than
212     * the threshold
213     *
214     * Expected behavior: no network recommended by Network Selector
215     */
216    @Test
217    public void verifyMinimumRssiThreshold() {
218        String[] ssids = {"\"test1\"", "\"test2\""};
219        String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
220        int[] freqs = {2437, 5180};
221        String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
222        int[] levels = {mThresholdMinimumRssi2G - 1, mThresholdMinimumRssi5G - 1};
223        int[] securities = {SECURITY_PSK, SECURITY_PSK};
224
225        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
226                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
227                    freqs, caps, levels, securities, mWifiConfigManager, mClock);
228        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
229        WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
230                false, true, false);
231        assertEquals("Expect null configuration", null, candidate);
232    }
233
234    /**
235     * No network selection if WiFi is connected and it is too short from last
236     * network selection.
237     *
238     * WifiStateMachine is in connected state.
239     * scanDetails contains two valid networks.
240     * Perform a network seletion right after the first one.
241     *
242     * Expected behavior: no network recommended by Network Selector
243     */
244    @Test
245    public void verifyMinimumTimeGapWhenConnected() {
246        String[] ssids = {"\"test1\"", "\"test2\""};
247        String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
248        int[] freqs = {2437, 5180};
249        String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
250        int[] levels = {mThresholdMinimumRssi2G + 1, mThresholdMinimumRssi5G + 1};
251        int[] securities = {SECURITY_PSK, SECURITY_PSK};
252
253        // Make a network selection.
254        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
255                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
256                    freqs, caps, levels, securities, mWifiConfigManager, mClock);
257        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
258        WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
259                false, true, false);
260
261        when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
262                + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS - 2000);
263
264        // Do another network selection with WSM in CONNECTED state.
265        candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
266                true, false, false);
267
268        assertEquals("Expect null configuration", null, candidate);
269    }
270
271    /**
272     * Perform network selection if WiFi is disconnected even if it is too short from last
273     * network selection.
274     *
275     * WifiStateMachine is in disconnected state.
276     * scanDetails contains two valid networks.
277     * Perform a network seletion right after the first one.
278     *
279     * Expected behavior: the first network is recommended by Network Selector
280     */
281    @Test
282    public void verifyNoMinimumTimeGapWhenDisconnected() {
283        String[] ssids = {"\"test1\"", "\"test2\""};
284        String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
285        int[] freqs = {2437, 5180};
286        String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
287        int[] levels = {mThresholdMinimumRssi2G + 1, mThresholdMinimumRssi5G + 1};
288        int[] securities = {SECURITY_PSK, SECURITY_PSK};
289
290        // Make a network selection.
291        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
292                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
293                    freqs, caps, levels, securities, mWifiConfigManager, mClock);
294        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
295        WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
296        WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
297                false, true, false);
298
299        when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
300                + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS - 2000);
301
302        // Do another network selection with WSM in DISCONNECTED state.
303        candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
304                false, true, false);
305
306        ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
307        WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
308        WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
309                chosenScanResult, candidate);
310    }
311
312    /**
313     * No network selection if the currently connected on is already sufficient.
314     *
315     * WifiStateMachine is connected to a qualified (5G, secure, good RSSI) network.
316     * scanDetails contains a valid network.
317     * Perform a network seletion after the first one.
318     *
319     * Expected behavior: no network recommended by Network Selector
320     */
321    @Test
322    public void noNetworkSelectionWhenCurrentOneIsSufficient() {
323        String[] ssids = {"\"test1\""};
324        String[] bssids = {"6c:f3:7f:ae:8c:f3"};
325        int[] freqs = {5180};
326        String[] caps = {"[WPA2-EAP-CCMP][ESS]"};
327        int[] levels = {mThresholdQualifiedRssi5G + 8};
328        int[] securities = {SECURITY_PSK};
329
330        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
331                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
332                    freqs, caps, levels, securities, mWifiConfigManager, mClock);
333        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
334
335        // connect to test1
336        mWifiNetworkSelector.selectNetwork(scanDetails, false, true, false);
337        when(mWifiInfo.getNetworkId()).thenReturn(0);
338        when(mWifiInfo.getBSSID()).thenReturn(bssids[0]);
339        when(mWifiInfo.is24GHz()).thenReturn(false);
340
341        when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
342                + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS + 2000);
343
344        levels[0] = mThresholdQualifiedRssi5G + 20;
345        scanDetailsAndConfigs =
346                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
347                    freqs, caps, levels, securities, mWifiConfigManager, mClock);
348        scanDetails = scanDetailsAndConfigs.getScanDetails();
349
350        WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
351                true, false, false);
352        assertEquals("Expect null configuration", null, candidate);
353    }
354
355
356    /**
357     * New network selection is performed if the currently connected network
358     * band is 2G.
359     *
360     * WifiStateMachine is connected to a 2G network.
361     * scanDetails contains a valid networks.
362     * Perform a network seletion after the first one.
363     *
364     * Expected behavior: the first network is recommended by Network Selector
365     */
366    @Test
367    public void band2GNetworkIsNotSufficient() {
368        String[] ssids = {"\"test1\""};
369        String[] bssids = {"6c:f3:7f:ae:8c:f3"};
370        int[] freqs = {2470};
371        String[] caps = {"[WPA2-EAP-CCMP][ESS]"};
372        int[] levels = {mThresholdQualifiedRssi2G + 8};
373        int[] securities = {SECURITY_PSK};
374
375        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
376                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
377                    freqs, caps, levels, securities, mWifiConfigManager, mClock);
378        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
379        WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
380
381        // connect to test1
382        mWifiNetworkSelector.selectNetwork(scanDetails, false, true, false);
383        when(mWifiInfo.getNetworkId()).thenReturn(0);
384        when(mWifiInfo.getBSSID()).thenReturn(bssids[0]);
385        when(mWifiInfo.is24GHz()).thenReturn(true);
386
387        when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
388                + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS + 2000);
389
390        // Do another network selection.
391        WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
392                true, false, false);
393
394        ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
395        WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
396        WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
397                chosenScanResult, candidate);
398    }
399
400
401    /**
402     * New network selection is performed if the currently connected network
403     * is a open one.
404     *
405     * WifiStateMachine is connected to a open network.
406     * scanDetails contains a valid networks.
407     * Perform a network seletion after the first one.
408     *
409     * Expected behavior: the first network is recommended by Network Selector
410     */
411    @Test
412    public void openNetworkIsNotSufficient() {
413        String[] ssids = {"\"test1\""};
414        String[] bssids = {"6c:f3:7f:ae:8c:f3"};
415        int[] freqs = {5180};
416        String[] caps = {"[ESS]"};
417        int[] levels = {mThresholdQualifiedRssi5G + 8};
418        int[] securities = {SECURITY_NONE};
419
420        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
421                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
422                    freqs, caps, levels, securities, mWifiConfigManager, mClock);
423        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
424        WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
425
426        // connect to test1
427        mWifiNetworkSelector.selectNetwork(scanDetails, false, true, false);
428        when(mWifiInfo.getNetworkId()).thenReturn(0);
429        when(mWifiInfo.getBSSID()).thenReturn(bssids[0]);
430        when(mWifiInfo.is24GHz()).thenReturn(false);
431        when(mWifiInfo.is5GHz()).thenReturn(true);
432
433        when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
434                + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS + 2000);
435
436        // Do another network selection.
437        WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
438                true, false, false);
439
440        ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
441        WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
442        WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
443                chosenScanResult, candidate);
444    }
445
446    /**
447     * New network selection is performed if the currently connected network
448     * has low RSSI value.
449     *
450     * WifiStateMachine is connected to a low RSSI 5GHz network.
451     * scanDetails contains a valid networks.
452     * Perform a network seletion after the first one.
453     *
454     * Expected behavior: the first network is recommended by Network Selector
455     */
456    @Test
457    public void lowRssi5GNetworkIsNotSufficient() {
458        String[] ssids = {"\"test1\""};
459        String[] bssids = {"6c:f3:7f:ae:8c:f3"};
460        int[] freqs = {5180};
461        String[] caps = {"[WPA2-EAP-CCMP][ESS]"};
462        int[] levels = {mThresholdQualifiedRssi5G - 2};
463        int[] securities = {SECURITY_PSK};
464
465        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
466                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
467                    freqs, caps, levels, securities, mWifiConfigManager, mClock);
468        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
469        WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
470
471        // connect to test1
472        mWifiNetworkSelector.selectNetwork(scanDetails, false, true, false);
473        when(mWifiInfo.getNetworkId()).thenReturn(0);
474        when(mWifiInfo.getBSSID()).thenReturn(bssids[0]);
475        when(mWifiInfo.is24GHz()).thenReturn(false);
476        when(mWifiInfo.is5GHz()).thenReturn(true);
477        when(mWifiInfo.getRssi()).thenReturn(levels[0]);
478
479        when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime()
480                + WifiNetworkSelector.MINIMUM_NETWORK_SELECTION_INTERVAL_MS + 2000);
481
482        // Do another network selection.
483        WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(scanDetails,
484                true, false, false);
485
486        ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
487        WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
488        WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
489                chosenScanResult, candidate);
490    }
491}
492