WakeupControllerTest.java revision dca47232ea69a4501318b4dfb69db69e1216694f
1/*
2 * Copyright 2017 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.junit.Assert.assertFalse;
20import static org.junit.Assert.assertTrue;
21import static org.mockito.ArgumentMatchers.any;
22import static org.mockito.ArgumentMatchers.anyBoolean;
23import static org.mockito.ArgumentMatchers.anyInt;
24import static org.mockito.ArgumentMatchers.eq;
25import static org.mockito.Mockito.never;
26import static org.mockito.Mockito.verify;
27import static org.mockito.Mockito.when;
28
29import android.content.Context;
30import android.database.ContentObserver;
31import android.net.wifi.ScanResult;
32import android.net.wifi.WifiConfiguration;
33import android.net.wifi.WifiScanner;
34import android.os.test.TestLooper;
35import android.provider.Settings;
36
37import com.android.server.wifi.util.ScanResultUtil;
38
39import org.junit.Before;
40import org.junit.Test;
41import org.mockito.ArgumentCaptor;
42import org.mockito.InOrder;
43import org.mockito.Mock;
44import org.mockito.Mockito;
45import org.mockito.MockitoAnnotations;
46import org.xmlpull.v1.XmlPullParserException;
47
48import java.io.ByteArrayOutputStream;
49import java.io.IOException;
50import java.io.PrintWriter;
51import java.util.Arrays;
52import java.util.Collections;
53import java.util.Set;
54
55/**
56 * Unit tests for {@link WakeupController}.
57 */
58public class WakeupControllerTest {
59
60    private static final int DFS_CHANNEL = 5540;
61
62    @Mock private Context mContext;
63    @Mock private WakeupLock mWakeupLock;
64    @Mock private WakeupEvaluator mWakeupEvaluator;
65    @Mock private WakeupOnboarding mWakeupOnboarding;
66    @Mock private WifiConfigStore mWifiConfigStore;
67    @Mock private WifiInjector mWifiInjector;
68    @Mock private WifiScanner mWifiScanner;
69    @Mock private WifiConfigManager mWifiConfigManager;
70    @Mock private FrameworkFacade mFrameworkFacade;
71    @Mock private WifiSettingsStore mWifiSettingsStore;
72    @Mock private WifiWakeMetrics mWifiWakeMetrics;
73    @Mock private WifiController mWifiController;
74    @Mock private WifiNative mWifiNative;
75
76    private TestLooper mLooper;
77    private WakeupController mWakeupController;
78    private WakeupConfigStoreData mWakeupConfigStoreData;
79    private WifiScanner.ScanData[] mTestScanDatas;
80    private ScanResult mTestScanResult;
81
82    /** Initialize objects before each test run. */
83    @Before
84    public void setUp() {
85        MockitoAnnotations.initMocks(this);
86
87        when(mWifiInjector.getWifiScanner()).thenReturn(mWifiScanner);
88        when(mWifiInjector.getWifiSettingsStore()).thenReturn(mWifiSettingsStore);
89        when(mWifiInjector.getWifiController()).thenReturn(mWifiController);
90        when(mWifiInjector.getWifiNative()).thenReturn(mWifiNative);
91        when(mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY))
92                .thenReturn(new int[]{DFS_CHANNEL});
93
94        when(mWifiSettingsStore.handleWifiToggled(anyBoolean())).thenReturn(true);
95
96        mLooper = new TestLooper();
97
98        // scanlistener input
99        mTestScanResult = new ScanResult();
100        mTestScanResult.SSID = "open ssid 1";
101        mTestScanResult.capabilities = "";
102        mTestScanResult.frequency = 2412;
103        ScanResult[] scanResults = new ScanResult[1];
104        scanResults[0] = mTestScanResult;
105        mTestScanDatas = new WifiScanner.ScanData[1];
106        mTestScanDatas[0] = new WifiScanner.ScanData(0 /* id */, 0 /* flags */,
107                0 /* bucketsScanned */, true /* allChannelsScanned */, scanResults);
108    }
109
110    /** Initializes the wakeupcontroller in the given {@code enabled} state. */
111    private void initializeWakeupController(boolean enabled) {
112        initializeWakeupController(enabled, true /* isRead */);
113    }
114
115    private void initializeWakeupController(boolean enabled, boolean isRead) {
116        int settingsValue = enabled ? 1 : 0;
117        when(mFrameworkFacade.getIntegerSetting(mContext,
118                Settings.Global.WIFI_WAKEUP_ENABLED, 0)).thenReturn(settingsValue);
119        when(mWakeupOnboarding.isOnboarded()).thenReturn(true);
120        mWakeupController = new WakeupController(mContext,
121                mLooper.getLooper(),
122                mWakeupLock,
123                mWakeupEvaluator,
124                mWakeupOnboarding,
125                mWifiConfigManager,
126                mWifiConfigStore,
127                mWifiWakeMetrics,
128                mWifiInjector,
129                mFrameworkFacade);
130
131        ArgumentCaptor<WakeupConfigStoreData> captor =
132                ArgumentCaptor.forClass(WakeupConfigStoreData.class);
133        verify(mWifiConfigStore).registerStoreData(captor.capture());
134        mWakeupConfigStoreData = captor.getValue();
135        if (isRead) {
136            readUserStore();
137        }
138    }
139
140    private void readUserStore() {
141        try {
142            mWakeupConfigStoreData.deserializeData(null, 0, false);
143        } catch (XmlPullParserException | IOException e) {
144            // unreachable
145        }
146    }
147
148    private ScanResult createOpenScanResult(String ssid) {
149        ScanResult scanResult = new ScanResult();
150        scanResult.SSID = ssid;
151        scanResult.capabilities = "";
152        return scanResult;
153    }
154
155    private void verifyDoesNotEnableWifi() {
156        verify(mWifiSettingsStore, never()).handleWifiToggled(true /* wifiEnabled */);
157    }
158
159    /**
160     * Verify WakeupController is enabled when the settings toggle is true.
161     */
162    @Test
163    public void verifyEnabledWhenToggledOn() {
164        initializeWakeupController(true /* enabled */);
165
166        assertTrue(mWakeupController.isEnabled());
167    }
168
169    /**
170     * Verify WakeupController is disabled when the settings toggle is false.
171     */
172    @Test
173    public void verifyDisabledWhenToggledOff() {
174        initializeWakeupController(false /* enabled */);
175
176        assertFalse(mWakeupController.isEnabled());
177    }
178
179    /**
180     * Verify WakeupController registers its store data with the WifiConfigStore on construction.
181     */
182    @Test
183    public void registersWakeupConfigStoreData() {
184        initializeWakeupController(true /* enabled */);
185        verify(mWifiConfigStore).registerStoreData(any(WakeupConfigStoreData.class));
186    }
187
188    /**
189     * Verify that dump calls also dump the state of the WakeupLock.
190     */
191    @Test
192    public void dumpIncludesWakeupLock() {
193        initializeWakeupController(true /* enabled */);
194        ByteArrayOutputStream stream = new ByteArrayOutputStream();
195        PrintWriter writer = new PrintWriter(stream);
196        mWakeupController.dump(null, writer, null);
197
198        verify(mWakeupLock).dump(null, writer, null);
199    }
200
201    /**
202     * Verify that start sets the wakeup lock.
203     */
204    @Test
205    public void startSetsWakeupLock() {
206        initializeWakeupController(true /* enabled */);
207        mWakeupController.start();
208        verify(mWakeupLock).setLock(any());
209        verify(mWifiWakeMetrics).recordStartEvent(anyInt());
210    }
211
212    /**
213     * Verify that start does not record an ignored start call if the controller is not yet active.
214     */
215    @Test
216    public void startDoesNotRecordIgnoredStart() {
217        initializeWakeupController(true /* enabled */);
218        mWakeupController.start();
219        verify(mWifiWakeMetrics, never()).recordIgnoredStart();
220    }
221
222    /**
223     * Verify that start does not set the wakeup lock when feature is disabled.
224     */
225    @Test
226    public void startDoesNotSetWakeupLockWhenDisabled() {
227        initializeWakeupController(false /* enabled */);
228        mWakeupController.start();
229        verify(mWakeupLock, never()).setLock(any());
230        verify(mWifiWakeMetrics, never()).recordStartEvent(anyInt());
231    }
232
233    /**
234     * If the controller is already active, verify that start() is ignored and no setup is done.
235     */
236    @Test
237    public void startIsIgnoredIfAlreadyActive() {
238        initializeWakeupController(true /* enabled */);
239        InOrder lockInOrder = Mockito.inOrder(mWakeupLock);
240        InOrder metricsInOrder = Mockito.inOrder(mWifiWakeMetrics);
241
242        mWakeupController.start();
243        lockInOrder.verify(mWakeupLock).setLock(any());
244        metricsInOrder.verify(mWifiWakeMetrics).recordStartEvent(anyInt());
245
246        mWakeupController.stop();
247        mWakeupController.start();
248        metricsInOrder.verify(mWifiWakeMetrics).recordIgnoredStart();
249        metricsInOrder.verify(mWifiWakeMetrics, never()).recordStartEvent(anyInt());
250        lockInOrder.verify(mWakeupLock, never()).setLock(any());
251    }
252
253    /**
254     * Verify that start registers the scan listener on the wifi scanner.
255     */
256    @Test
257    public void startRegistersScanListener() {
258        initializeWakeupController(true /* enabled */);
259        mWakeupController.start();
260        verify(mWifiScanner).registerScanListener(any());
261    }
262
263    /**
264     * Verify that stop deregisters the scan listener from the wifi scanner.
265     */
266    @Test
267    public void stopDeresgistersScanListener() {
268        initializeWakeupController(true /* enabled */);
269        mWakeupController.start();
270        mWakeupController.stop();
271        verify(mWifiScanner).deregisterScanListener(any());
272    }
273
274    /**
275     * Verify that reset sets active to false.
276     *
277     * <p>This is accomplished by initiating another call to start and verifying that the wakeup
278     * lock is re-set.
279     */
280    @Test
281    public void resetSetsActiveToFalse() {
282        initializeWakeupController(true /* enabled */);
283        InOrder lockInOrder = Mockito.inOrder(mWakeupLock);
284        InOrder metricsInOrder = Mockito.inOrder(mWifiWakeMetrics);
285
286        mWakeupController.start();
287        lockInOrder.verify(mWakeupLock).setLock(any());
288        metricsInOrder.verify(mWifiWakeMetrics).recordStartEvent(anyInt());
289
290        mWakeupController.stop();
291        mWakeupController.reset();
292        metricsInOrder.verify(mWifiWakeMetrics).recordResetEvent(0 /* numScans */);
293
294        mWakeupController.start();
295        lockInOrder.verify(mWakeupLock).setLock(any());
296        metricsInOrder.verify(mWifiWakeMetrics).recordStartEvent(anyInt());
297    }
298
299    /**
300     * Verify that the wakeup lock is initialized with the intersection of ScanResults and saved
301     * networks.
302     */
303    @Test
304    public void startInitializesWakeupLockWithSavedScanResults() {
305        String ssid1 = "ssid 1";
306        String ssid2 = "ssid 2";
307        String quotedSsid = ScanResultUtil.createQuotedSSID(ssid1);
308
309        // saved configs
310        WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(quotedSsid);
311        openNetwork.getNetworkSelectionStatus().setHasEverConnected(true);
312        WifiConfiguration wepNetwork = WifiConfigurationTestUtil.createWepNetwork();
313        wepNetwork.getNetworkSelectionStatus().setHasEverConnected(true);
314        when(mWifiConfigManager.getSavedNetworks())
315                .thenReturn(Arrays.asList(openNetwork, wepNetwork));
316
317        // scan results from most recent scan
318        ScanResult savedScanResult = createOpenScanResult(ssid1);
319        savedScanResult.frequency = 2412;
320        ScanResult unsavedScanResult = createOpenScanResult(ssid2);
321        savedScanResult.frequency = 2412;
322
323        when(mWifiScanner.getSingleScanResults())
324                .thenReturn(Arrays.asList(savedScanResult, unsavedScanResult));
325
326        // intersection of most recent scan + saved configs
327        Set<ScanResultMatchInfo> expectedMatchInfos =
328                Collections.singleton(ScanResultMatchInfo.fromScanResult(savedScanResult));
329
330        initializeWakeupController(true /* enabled */);
331        mWakeupController.start();
332        verify(mWakeupLock).setLock(eq(expectedMatchInfos));
333        verify(mWifiWakeMetrics).recordStartEvent(expectedMatchInfos.size());
334    }
335
336    /**
337     * Verify that start filters out DFS channels.
338     */
339    @Test
340    public void startFiltersOutDfsScanResults() {
341        String ssid = "test_ssid";
342        String quotedSsid = ScanResultUtil.createQuotedSSID(ssid);
343
344        // saved config
345        WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(quotedSsid);
346        openNetwork.getNetworkSelectionStatus().setHasEverConnected(true);
347        when(mWifiConfigManager.getSavedNetworks())
348                .thenReturn(Collections.singletonList(openNetwork));
349
350        // scan result from most recent scan
351        ScanResult scanResult = createOpenScanResult(ssid);
352        scanResult.frequency = DFS_CHANNEL;
353
354        when(mWifiScanner.getSingleScanResults()).thenReturn(Collections.singletonList(scanResult));
355
356        // intersection of most recent scan + saved configs
357        Set<ScanResultMatchInfo> expectedMatchInfos = Collections.emptySet();
358
359        initializeWakeupController(true /* enabled */);
360        mWakeupController.start();
361        verify(mWakeupLock).setLock(eq(expectedMatchInfos));
362        verify(mWifiWakeMetrics).recordStartEvent(expectedMatchInfos.size());
363    }
364
365    /**
366     * Verify that onResults updates the WakeupLock.
367     */
368    @Test
369    public void onResultsUpdatesWakeupLock() {
370        initializeWakeupController(true /* enabled */);
371        mWakeupController.start();
372
373        ArgumentCaptor<WifiScanner.ScanListener> scanListenerArgumentCaptor =
374                ArgumentCaptor.forClass(WifiScanner.ScanListener.class);
375
376        verify(mWifiScanner).registerScanListener(scanListenerArgumentCaptor.capture());
377        WifiScanner.ScanListener scanListener = scanListenerArgumentCaptor.getValue();
378
379        // incoming scan results
380        scanListener.onResults(mTestScanDatas);
381
382        ScanResultMatchInfo expectedMatchInfo = ScanResultMatchInfo.fromScanResult(mTestScanResult);
383        verify(mWakeupLock).update(eq(Collections.singleton(expectedMatchInfo)));
384    }
385
386    /**
387     * Verify that onResults filters out DFS channels.
388     */
389    @Test
390    public void onResultsFiltersOutDfsScanResults() {
391        initializeWakeupController(true /* enabled */);
392        mWakeupController.start();
393
394        ArgumentCaptor<WifiScanner.ScanListener> scanListenerArgumentCaptor =
395                ArgumentCaptor.forClass(WifiScanner.ScanListener.class);
396
397        verify(mWifiScanner).registerScanListener(scanListenerArgumentCaptor.capture());
398        WifiScanner.ScanListener scanListener = scanListenerArgumentCaptor.getValue();
399
400        // incoming scan results
401        mTestScanResult.frequency = DFS_CHANNEL;
402        scanListener.onResults(mTestScanDatas);
403
404        verify(mWakeupLock).update(eq(Collections.emptySet()));
405    }
406
407    /**
408     * Verify that the controller searches for viable networks during onResults when WakeupLock is
409     * unlocked.
410     */
411    @Test
412    public void onResultsSearchesForViableNetworkWhenWakeupLockIsUnlocked() {
413        // unlock wakeup lock
414        when(mWakeupLock.isUnlocked()).thenReturn(true);
415        // do not find viable network
416        when(mWakeupEvaluator.findViableNetwork(any(), any())).thenReturn(null);
417
418        initializeWakeupController(true /* enabled */);
419        mWakeupController.start();
420
421        ArgumentCaptor<WifiScanner.ScanListener> scanListenerArgumentCaptor =
422                ArgumentCaptor.forClass(WifiScanner.ScanListener.class);
423
424        verify(mWifiScanner).registerScanListener(scanListenerArgumentCaptor.capture());
425        WifiScanner.ScanListener scanListener = scanListenerArgumentCaptor.getValue();
426
427        // incoming scan results
428        scanListener.onResults(mTestScanDatas);
429
430        verify(mWakeupEvaluator).findViableNetwork(any(), any());
431        verifyDoesNotEnableWifi();
432    }
433
434    /**
435     * Verify that the controller updates the WakeupLock even if the user is not onboarded.
436     */
437    @Test
438    public void onResultsUpdatesIfNotOnboarded() {
439        initializeWakeupController(true /* enabled */);
440        when(mWakeupOnboarding.isOnboarded()).thenReturn(false);
441        when(mWakeupLock.isUnlocked()).thenReturn(false);
442        mWakeupController.start();
443
444        ArgumentCaptor<WifiScanner.ScanListener> scanListenerArgumentCaptor =
445                ArgumentCaptor.forClass(WifiScanner.ScanListener.class);
446
447        verify(mWifiScanner).registerScanListener(scanListenerArgumentCaptor.capture());
448        WifiScanner.ScanListener scanListener = scanListenerArgumentCaptor.getValue();
449
450        // incoming scan results
451        scanListener.onResults(mTestScanDatas);
452
453        verify(mWakeupLock).update(any());
454        verify(mWakeupLock).isUnlocked();
455        verifyDoesNotEnableWifi();
456    }
457
458    /**
459     * Verify that the controller enables wifi and notifies user when all criteria are met.
460     */
461    @Test
462    public void onResultsEnablesWifi() {
463        // unlock wakeup lock
464        when(mWakeupLock.isUnlocked()).thenReturn(true);
465        // find viable network
466        when(mWakeupEvaluator.findViableNetwork(any(), any())).thenReturn(mTestScanResult);
467
468        initializeWakeupController(true /* enabled */);
469        mWakeupController.start();
470
471        ArgumentCaptor<WifiScanner.ScanListener> scanListenerArgumentCaptor =
472                ArgumentCaptor.forClass(WifiScanner.ScanListener.class);
473
474        verify(mWifiScanner).registerScanListener(scanListenerArgumentCaptor.capture());
475        WifiScanner.ScanListener scanListener = scanListenerArgumentCaptor.getValue();
476
477        // incoming scan results
478        scanListener.onResults(mTestScanDatas);
479
480        verify(mWakeupEvaluator).findViableNetwork(any(), any());
481        verify(mWifiSettingsStore).handleWifiToggled(true /* wifiEnabled */);
482        verify(mWifiWakeMetrics).recordWakeupEvent(1 /* numScans */);
483    }
484
485    /**
486     * Verify that the controller will not do any work if the user store has not been read.
487     */
488    @Test
489    public void controllerDoesNoWorkIfUserStoreIsNotRead() {
490        initializeWakeupController(true /* enabled */, false /* isRead */);
491        mWakeupController.start();
492
493        ArgumentCaptor<WifiScanner.ScanListener> scanListenerArgumentCaptor =
494                ArgumentCaptor.forClass(WifiScanner.ScanListener.class);
495
496        verify(mWifiScanner).registerScanListener(scanListenerArgumentCaptor.capture());
497        WifiScanner.ScanListener scanListener = scanListenerArgumentCaptor.getValue();
498
499        // incoming scan results
500        scanListener.onResults(mTestScanDatas);
501
502        verify(mWakeupLock, never()).setLock(any());
503        verify(mWakeupLock, never()).update(any());
504        verify(mWakeupLock, never()).isUnlocked();
505        verify(mWakeupOnboarding, never()).maybeShowNotification();
506        verify(mWakeupEvaluator, never()).findViableNetwork(any(), any());
507    }
508
509    @Test
510    public void userIsNotOnboardedByInitialization() {
511        initializeWakeupController(true /* enabled */);
512        verify(mWakeupOnboarding, never()).setOnboarded();
513    }
514
515    @Test
516    public void userIsOnboardedBySettingChange() {
517        initializeWakeupController(true /* enabled */);
518        ArgumentCaptor<ContentObserver> argumentCaptor =
519                ArgumentCaptor.forClass(ContentObserver.class);
520        verify(mFrameworkFacade).registerContentObserver(any(), any(), eq(true),
521                argumentCaptor.capture());
522        ContentObserver contentObserver = argumentCaptor.getValue();
523        contentObserver.onChange(false /* selfChange */);
524        verify(mWakeupOnboarding).setOnboarded();
525    }
526}
527