SavedNetworkEvaluatorTest.java revision 17c2a7b30e5680b11fc0073ce322ee7bc14ef2c5
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.ContentResolver;
26import android.content.Context;
27import android.content.res.Resources;
28import android.database.ContentObserver;
29import android.net.Uri;
30import android.net.wifi.ScanResult;
31import android.net.wifi.WifiConfiguration;
32import android.os.Looper;
33import android.os.SystemClock;
34import android.provider.Settings;
35import android.test.suitebuilder.annotation.SmallTest;
36import android.util.LocalLog;
37
38import com.android.internal.R;
39import com.android.server.wifi.WifiNetworkSelectorTestUtil.ScanDetailsAndWifiConfigs;
40
41import org.junit.After;
42import org.junit.Before;
43import org.junit.Test;
44import org.mockito.ArgumentCaptor;
45import org.mockito.Mock;
46import org.mockito.MockitoAnnotations;
47
48import java.util.List;
49
50/**
51 * Unit tests for {@link com.android.server.wifi.SavedNetworkEvaluator}.
52 */
53@SmallTest
54public class SavedNetworkEvaluatorTest {
55
56    /** Sets up test. */
57    @Before
58    public void setUp() throws Exception {
59        MockitoAnnotations.initMocks(this);
60        setupContext();
61        setupResource();
62        setupWifiConfigManager();
63        mLocalLog = new LocalLog(512);
64
65        when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime());
66        when(mFrameworkFacade.getIntegerSetting(mContext,
67                Settings.Global.CURATE_SAVED_OPEN_NETWORKS, 0)).thenReturn(0);
68        when(mFrameworkFacade.getIntegerSetting(mContext,
69                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0)).thenReturn(0);
70
71        mThresholdMinimumRssi2G = mResource.getInteger(
72                R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
73        mThresholdMinimumRssi5G = mResource.getInteger(
74                R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
75        mThresholdQualifiedRssi2G = mResource.getInteger(
76                R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
77        mThresholdQualifiedRssi5G = mResource.getInteger(
78                R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz);
79        mThresholdSaturatedRssi2G = mResource.getInteger(
80                R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz);
81        mThresholdSaturatedRssi5G = mResource.getInteger(
82                R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz);
83
84        ArgumentCaptor<ContentObserver> observerCaptor =
85                ArgumentCaptor.forClass(ContentObserver.class);
86
87        mSavedNetworkEvaluator = new SavedNetworkEvaluator(mContext, mWifiConfigManager,
88                mClock, mLocalLog, Looper.getMainLooper(), mFrameworkFacade);
89        verify(mFrameworkFacade, times(2)).registerContentObserver(eq(mContext), any(Uri.class),
90                eq(false), observerCaptor.capture());
91        // SavedNetworkEvaluator uses a single ContentObserver for two registrations, we only need
92        // to get this object once.
93        mContentObserver = observerCaptor.getValue();
94    }
95
96    /** Cleans up test. */
97    @After
98    public void cleanup() {
99        validateMockitoUsage();
100    }
101
102    private SavedNetworkEvaluator mSavedNetworkEvaluator;
103    @Mock private WifiConfigManager mWifiConfigManager;
104    @Mock private Context mContext;
105    @Mock private ContentResolver mContentResolver;
106    @Mock private FrameworkFacade mFrameworkFacade;
107    @Mock private Resources mResource;
108    @Mock private Clock mClock;
109    private LocalLog mLocalLog;
110    private int mThresholdMinimumRssi2G;
111    private int mThresholdMinimumRssi5G;
112    private int mThresholdQualifiedRssi2G;
113    private int mThresholdQualifiedRssi5G;
114    private int mThresholdSaturatedRssi2G;
115    private int mThresholdSaturatedRssi5G;
116    private ContentObserver mContentObserver;
117    private static final String TAG = "Saved Network Evaluator Unit Test";
118
119    private void setupContext() {
120        when(mContext.getResources()).thenReturn(mResource);
121        when(mContext.getContentResolver()).thenReturn(mContentResolver);
122    }
123
124    private void setupResource() {
125        when(mResource.getInteger(
126                R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_5GHz))
127                .thenReturn(-70);
128        when(mResource.getInteger(
129                R.integer.config_wifi_framework_wifi_score_good_rssi_threshold_24GHz))
130                .thenReturn(-73);
131        when(mResource.getInteger(
132                R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_5GHz))
133                .thenReturn(-70);
134        when(mResource.getInteger(
135                R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz))
136                .thenReturn(-73);
137        when(mResource.getInteger(
138                R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz))
139                .thenReturn(-82);
140        when(mResource.getInteger(
141                R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz))
142                .thenReturn(-85);
143        when(mResource.getInteger(
144                R.integer.config_wifi_framework_RSSI_SCORE_SLOPE))
145                .thenReturn(4);
146        when(mResource.getInteger(
147                R.integer.config_wifi_framework_RSSI_SCORE_OFFSET))
148                .thenReturn(85);
149        when(mResource.getInteger(
150                R.integer.config_wifi_framework_SAME_BSSID_AWARD))
151                .thenReturn(24);
152        when(mResource.getInteger(
153                R.integer.config_wifi_framework_SECURITY_AWARD))
154                .thenReturn(80);
155        when(mResource.getInteger(
156                R.integer.config_wifi_framework_5GHz_preference_boost_factor))
157                .thenReturn(16);
158        when(mResource.getInteger(
159                R.integer.config_wifi_framework_current_network_boost))
160                .thenReturn(16);
161    }
162
163    private void setupWifiConfigManager() {
164        when(mWifiConfigManager.getLastSelectedNetwork())
165                .thenReturn(WifiConfiguration.INVALID_NETWORK_ID);
166    }
167
168    /**
169     * Do not evaluate networks that {@link WifiConfiguration#useExternalScores}.
170     */
171    @Test
172    public void ignoreNetworksIfUseExternalScores() {
173        String[] ssids = {"\"test1\"", "\"test2\""};
174        String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
175        int[] freqs = {2470, 2437};
176        String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
177        int[] levels = {mThresholdQualifiedRssi2G + 8, mThresholdQualifiedRssi2G + 10};
178        int[] securities = {SECURITY_PSK, SECURITY_PSK};
179
180        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
181                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
182                        freqs, caps, levels, securities, mWifiConfigManager, mClock);
183        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
184        WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
185        for (WifiConfiguration wifiConfiguration : savedConfigs) {
186            wifiConfiguration.useExternalScores = true;
187        }
188
189        WifiConfiguration candidate = mSavedNetworkEvaluator.evaluateNetworks(scanDetails,
190                null, null, true, false, null);
191
192        assertNull(candidate);
193    }
194
195    /**
196     * Do not evaluate open networks when {@link Settings.Global.CURATE_SAVED_OPEN_NETWORKS} and
197     * {@link Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED} are enabled.
198     */
199    @Test
200    public void ignoreOpensNetworksIfCurateSavedNetworksEnabled() {
201        String[] ssids = {"\"test1\"", "\"test2\""};
202        String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
203        int[] freqs = {5200, 5240};
204        String[] caps = {"[ESS]", "[ESS]"};
205        int[] levels = {mThresholdQualifiedRssi5G, mThresholdQualifiedRssi5G};
206        int[] securities = {SECURITY_NONE, SECURITY_NONE};
207
208        when(mFrameworkFacade.getIntegerSetting(mContext,
209                Settings.Global.CURATE_SAVED_OPEN_NETWORKS, 0)).thenReturn(1);
210        when(mFrameworkFacade.getIntegerSetting(mContext,
211                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0)).thenReturn(1);
212        mContentObserver.onChange(false);
213
214        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
215                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
216                        freqs, caps, levels, securities, mWifiConfigManager, mClock);
217        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
218
219        WifiConfiguration candidate = mSavedNetworkEvaluator.evaluateNetworks(scanDetails,
220                null, null, true, false, null);
221
222        assertNull(candidate);
223    }
224
225    /**
226     * Set the candidate {@link ScanResult} for all {@link WifiConfiguration}s even if they have
227     * useExternalScores set or are open networks with
228     * {@link Settings.Global.CURATE_SAVED_OPEN_NETWORKS} and
229     * {@link Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED} enabled.
230     */
231    @Test
232    public void setCandidateScanResultsForAllSavedNetworks() {
233        String[] ssids = {"\"test1\"", "\"test2\""};
234        String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
235        int[] freqs = {5200, 5240};
236        String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[ESS]"};
237        int[] levels = {mThresholdQualifiedRssi5G, mThresholdQualifiedRssi5G};
238        int[] securities = {SECURITY_PSK, SECURITY_NONE};
239
240        when(mFrameworkFacade.getIntegerSetting(mContext,
241                Settings.Global.CURATE_SAVED_OPEN_NETWORKS, 0)).thenReturn(1);
242        when(mFrameworkFacade.getIntegerSetting(mContext,
243                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0)).thenReturn(1);
244        mContentObserver.onChange(false);
245
246        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
247                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
248                        freqs, caps, levels, securities, mWifiConfigManager, mClock);
249        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
250        WifiConfiguration useExternalScoresConfig = scanDetailsAndConfigs.getWifiConfigs()[0];
251        useExternalScoresConfig.useExternalScores = true;
252        WifiConfiguration openNetworkConfig = scanDetailsAndConfigs.getWifiConfigs()[1];
253
254        WifiConfiguration candidate = mSavedNetworkEvaluator.evaluateNetworks(scanDetails,
255                null, null, true, false, null);
256
257        assertNull(candidate);
258
259        verify(mWifiConfigManager).setNetworkCandidateScanResult(
260                eq(useExternalScoresConfig.networkId),
261                eq(scanDetails.get(0).getScanResult()),
262                anyInt());
263        verify(mWifiConfigManager).setNetworkCandidateScanResult(
264                eq(openNetworkConfig.networkId),
265                eq(scanDetails.get(1).getScanResult()),
266                anyInt());
267    }
268
269    /**
270     * Between two 2G networks, choose the one with stronger RSSI value if other conditions
271     * are the same and the RSSI values are not satuarted.
272     */
273    @Test
274    public void chooseStrongerRssi2GNetwork() {
275        String[] ssids = {"\"test1\"", "\"test2\""};
276        String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
277        int[] freqs = {2470, 2437};
278        String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
279        int[] levels = {mThresholdQualifiedRssi2G + 8, mThresholdQualifiedRssi2G + 10};
280        int[] securities = {SECURITY_PSK, SECURITY_PSK};
281
282        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
283                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
284                    freqs, caps, levels, securities, mWifiConfigManager, mClock);
285        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
286        WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
287
288        WifiConfiguration candidate = mSavedNetworkEvaluator.evaluateNetworks(scanDetails,
289                null, null, true, false, null);
290
291        ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
292        WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate);
293        WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
294                chosenScanResult, candidate);
295    }
296
297    /**
298     * Between two 5G networks, choose the one with stronger RSSI value if other conditions
299     * are the same and the RSSI values are not saturated.
300     * {@link Settings.Global.CURATE_SAVED_OPEN_NETWORKS} and
301     * {@link Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED} will no affect on the outcome
302     * because both networks are secure.
303     */
304    @Test
305    public void chooseStrongerRssi5GNetwork() {
306        String[] ssids = {"\"test1\"", "\"test2\""};
307        String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
308        int[] freqs = {5200, 5240};
309        String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
310        int[] levels = {mThresholdQualifiedRssi5G + 8, mThresholdQualifiedRssi5G + 10};
311        int[] securities = {SECURITY_PSK, SECURITY_PSK};
312
313        when(mFrameworkFacade.getIntegerSetting(mContext,
314                Settings.Global.CURATE_SAVED_OPEN_NETWORKS, 0)).thenReturn(1);
315        when(mFrameworkFacade.getIntegerSetting(mContext,
316                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0)).thenReturn(1);
317        mContentObserver.onChange(false);
318
319        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
320                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
321                    freqs, caps, levels, securities, mWifiConfigManager, mClock);
322        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
323        WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
324
325        WifiConfiguration candidate = mSavedNetworkEvaluator.evaluateNetworks(scanDetails,
326                null, null, true, false, null);
327
328        ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
329        WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate);
330        WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
331                chosenScanResult, candidate);
332    }
333
334    /**
335     * Choose secure network over open network if other conditions are the same.
336     */
337    @Test
338    public void chooseSecureNetworkOverOpenNetwork() {
339        String[] ssids = {"\"test1\"", "\"test2\""};
340        String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
341        int[] freqs = {5200, 5240};
342        String[] caps = {"[ESS]", "[WPA2-EAP-CCMP][ESS]"};
343        int[] levels = {mThresholdQualifiedRssi5G, mThresholdQualifiedRssi5G};
344        int[] securities = {SECURITY_NONE, SECURITY_PSK};
345
346        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
347                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
348                    freqs, caps, levels, securities, mWifiConfigManager, mClock);
349        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
350        WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
351
352        WifiConfiguration candidate = mSavedNetworkEvaluator.evaluateNetworks(scanDetails,
353                null, null, true, false, null);
354
355        ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
356        WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate);
357        WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
358                chosenScanResult, candidate);
359    }
360
361    /**
362     * Choose 5G network over 2G network if other conditions are the same.
363     */
364    @Test
365    public void choose5GNetworkOver2GNetwork() {
366        String[] ssids = {"\"test1\"", "\"test2\""};
367        String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
368        int[] freqs = {2437, 5240};
369        String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
370        int[] levels = {mThresholdQualifiedRssi2G, mThresholdQualifiedRssi5G};
371        int[] securities = {SECURITY_PSK, SECURITY_PSK};
372
373        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
374                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
375                    freqs, caps, levels, securities, mWifiConfigManager, mClock);
376        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
377        WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
378
379        WifiConfiguration candidate = mSavedNetworkEvaluator.evaluateNetworks(scanDetails,
380                null, null, true, false, null);
381
382        ScanResult chosenScanResult = scanDetails.get(1).getScanResult();
383        WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[1], candidate);
384        WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
385                chosenScanResult, candidate);
386    }
387
388    /**
389     * Verify that we stick to the currently connected network if the other one is
390     * just slightly better scored.
391     */
392    @Test
393    public void stickToCurrentNetwork() {
394        String[] ssids = {"\"test1\"", "\"test2\""};
395        String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
396        int[] freqs = {5200, 5240};
397        String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
398        // test2 has slightly stronger RSSI value than test1
399        int[] levels = {mThresholdMinimumRssi5G + 2, mThresholdMinimumRssi5G + 4};
400        int[] securities = {SECURITY_PSK, SECURITY_PSK};
401
402        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
403                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
404                    freqs, caps, levels, securities, mWifiConfigManager, mClock);
405        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
406        WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
407
408        // Simuluate we are connected to SSID test1 already.
409        WifiConfiguration candidate = mSavedNetworkEvaluator.evaluateNetworks(scanDetails,
410                savedConfigs[0], null, true, false, null);
411
412        // Even though test2 has higher RSSI value, test1 is chosen because of the
413        // currently connected network bonus.
414        ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
415        WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
416        WifiNetworkSelectorTestUtil.verifySelectedScanResult(mWifiConfigManager,
417                chosenScanResult, candidate);
418    }
419
420    /**
421     * Verify that we stick to the currently connected BSSID if the other one is
422     * just slightly better scored.
423     */
424    @Test
425    public void stickToCurrentBSSID() {
426        // Same SSID
427        String[] ssids = {"\"test1\"", "\"test1\""};
428        String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4"};
429        int[] freqs = {5200, 5240};
430        String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
431        // test2 has slightly stronger RSSI value than test1
432        int[] levels = {mThresholdMinimumRssi5G + 2, mThresholdMinimumRssi5G + 6};
433        int[] securities = {SECURITY_PSK, SECURITY_PSK};
434
435        ScanDetailsAndWifiConfigs scanDetailsAndConfigs =
436                WifiNetworkSelectorTestUtil.setupScanDetailsAndConfigStore(ssids, bssids,
437                    freqs, caps, levels, securities, mWifiConfigManager, mClock);
438        List<ScanDetail> scanDetails = scanDetailsAndConfigs.getScanDetails();
439        WifiConfiguration[] savedConfigs = scanDetailsAndConfigs.getWifiConfigs();
440
441        // Simuluate we are connected to BSSID "6c:f3:7f:ae:8c:f3" already
442        WifiConfiguration candidate = mSavedNetworkEvaluator.evaluateNetworks(scanDetails,
443                null, bssids[0], true, false, null);
444
445        // Even though test2 has higher RSSI value, test1 is chosen because of the
446        // currently connected BSSID bonus.
447        ScanResult chosenScanResult = scanDetails.get(0).getScanResult();
448        WifiConfigurationTestUtil.assertConfigurationEqual(savedConfigs[0], candidate);
449    }
450}
451