SupplicantPnoScannerTest.java revision a8367288377cbaed6371256ca837b7aa22280706
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.scanner;
18
19import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder;
20import static com.android.server.wifi.ScanTestUtil.assertScanDataEquals;
21
22import static org.junit.Assert.*;
23import static org.mockito.Mockito.*;
24
25import android.content.Context;
26import android.net.wifi.WifiConfiguration;
27import android.net.wifi.WifiScanner;
28import android.test.suitebuilder.annotation.SmallTest;
29
30import com.android.internal.R;
31import com.android.server.wifi.MockAlarmManager;
32import com.android.server.wifi.MockLooper;
33import com.android.server.wifi.MockResources;
34import com.android.server.wifi.MockWifiMonitor;
35import com.android.server.wifi.ScanResults;
36import com.android.server.wifi.WifiMonitor;
37import com.android.server.wifi.WifiNative;
38import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection;
39
40import org.junit.Before;
41import org.junit.Test;
42import org.mockito.InOrder;
43import org.mockito.Mock;
44import org.mockito.MockitoAnnotations;
45
46import java.util.HashSet;
47import java.util.Set;
48
49
50/**
51 * Unit tests for {@link com.android.server.wifi.scanner.SupplicantWifiScannerImpl.setPnoList}.
52 */
53@SmallTest
54public class SupplicantPnoScannerTest {
55
56    @Mock Context mContext;
57    MockAlarmManager mAlarmManager;
58    MockWifiMonitor mWifiMonitor;
59    MockLooper mLooper;
60    @Mock WifiNative mWifiNative;
61    MockResources mResources;
62    SupplicantWifiScannerImpl mScanner;
63
64    @Before
65    public void setup() throws Exception {
66        MockitoAnnotations.initMocks(this);
67
68        mLooper = new MockLooper();
69        mAlarmManager = new MockAlarmManager();
70        mWifiMonitor = new MockWifiMonitor();
71        mResources = new MockResources();
72
73        when(mWifiNative.getInterfaceName()).thenReturn("a_test_interface_name");
74        when(mContext.getSystemService(Context.ALARM_SERVICE))
75                .thenReturn(mAlarmManager.getAlarmManager());
76        when(mContext.getResources()).thenReturn(mResources);
77    }
78
79    /**
80     * Verify that the HW disconnected PNO scan triggers a supplicant PNO scan and invokes the
81     * OnPnoNetworkFound callback when the scan results are received.
82     */
83    @Test
84    public void startHwDisconnectedPnoScan() {
85        createScannerWithHwPnoScanSupport();
86
87        WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
88        WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
89        ScanResults scanResults = createDummyScanResults();
90
91        InOrder order = inOrder(pnoEventHandler, mWifiNative);
92        // Start PNO scan
93        startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
94        expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults);
95        verifyNoMoreInteractions(pnoEventHandler);
96    }
97
98    /**
99     * Verify that we pause & resume HW PNO scan when a single scan is scheduled and invokes the
100     * OnPnoNetworkFound callback when the scan results are received.
101     */
102    @Test
103    public void pauseResumeHwDisconnectedPnoScanForSingleScan() {
104        createScannerWithHwPnoScanSupport();
105
106        WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
107        WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
108        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
109        WifiNative.ScanSettings settings = createDummyScanSettings();
110        ScanResults scanResults = createDummyScanResults();
111
112        InOrder order = inOrder(eventHandler, mWifiNative);
113        // Start PNO scan
114        startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
115        // Start single scan
116        assertTrue(mScanner.startSingleScan(settings, eventHandler));
117        // Verify that the PNO scan was paused and single scan runs successfully
118        expectSuccessfulSingleScanWithHwPnoEnabled(order, eventHandler,
119                expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ), new HashSet<Integer>(),
120                scanResults);
121        verifyNoMoreInteractions(eventHandler);
122
123        order = inOrder(pnoEventHandler, mWifiNative);
124        // Resume PNO scan after the single scan results are received and PNO monitor debounce
125        // alarm fires.
126        assertTrue("dispatch pno monitor alarm",
127                mAlarmManager.dispatch(
128                        SupplicantWifiScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
129        assertEquals("dispatch message after alarm", 1, mLooper.dispatchAll());
130        // Now verify that PNO scan is resumed successfully
131        expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults);
132        verifyNoMoreInteractions(pnoEventHandler);
133    }
134
135    /**
136     * Verify that the SW disconnected PNO scan triggers a background scan and invokes the
137     * background scan callbacks when scan results are received.
138     */
139    @Test
140    public void startSwDisconnectedPnoScan() {
141        createScannerWithSwPnoScanSupport();
142        doSuccessfulSwPnoScanTest(false);
143    }
144
145    /**
146     * Verify that the HW connected PNO scan triggers a background scan and invokes the
147     * background scan callbacks when scan results are received.
148     */
149    @Test
150    public void startHwConnectedPnoScan() {
151        createScannerWithHwPnoScanSupport();
152        doSuccessfulSwPnoScanTest(true);
153    }
154
155    /**
156     * Verify that the SW connected PNO scan triggers a background scan and invokes the
157     * background scan callbacks when scan results are received.
158     */
159    @Test
160    public void startSwConnectedPnoScan() {
161        createScannerWithSwPnoScanSupport();
162        doSuccessfulSwPnoScanTest(true);
163    }
164
165    /**
166     * Verify that the HW PNO delayed failure cleans up the scan settings cleanly.
167     * 1. Start Hw PNO.
168     * 2. Start Single Scan which should pause PNO scan.
169     * 3. Fail the PNO scan resume and verify that the OnPnoScanFailed callback is invoked.
170     * 4. Now restart a new PNO scan to ensure that the failure was cleanly handled.
171     */
172    @Test
173    public void delayedHwDisconnectedPnoScanFailure() {
174        createScannerWithHwPnoScanSupport();
175
176        WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
177        WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
178        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
179        WifiNative.ScanSettings settings = createDummyScanSettings();
180        ScanResults scanResults = createDummyScanResults();
181
182        InOrder order = inOrder(eventHandler, mWifiNative);
183        // Start PNO scan
184        startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
185        // Start single scan
186        assertTrue(mScanner.startSingleScan(settings, eventHandler));
187        // Verify that the PNO scan was paused and single scan runs successfully
188        expectSuccessfulSingleScanWithHwPnoEnabled(order, eventHandler,
189                expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ), new HashSet<Integer>(),
190                scanResults);
191        verifyNoMoreInteractions(eventHandler);
192
193        // Fail the PNO resume and check that the OnPnoScanFailed callback is invoked.
194        order = inOrder(pnoEventHandler, mWifiNative);
195        when(mWifiNative.setPnoScan(true)).thenReturn(false);
196        assertTrue("dispatch pno monitor alarm",
197                mAlarmManager.dispatch(
198                        SupplicantWifiScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
199        assertEquals("dispatch message after alarm", 1, mLooper.dispatchAll());
200        order.verify(pnoEventHandler).onPnoScanFailed();
201        verifyNoMoreInteractions(pnoEventHandler);
202
203        // Add a new PNO scan request
204        startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
205        assertTrue("dispatch pno monitor alarm",
206                mAlarmManager.dispatch(
207                        SupplicantWifiScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
208        assertEquals("dispatch message after alarm", 1, mLooper.dispatchAll());
209        expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults);
210        verifyNoMoreInteractions(pnoEventHandler);
211    }
212
213    private void doSuccessfulSwPnoScanTest(boolean isConnectedPno) {
214        WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
215        WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(isConnectedPno);
216        WifiNative.ScanEventHandler scanEventHandler = mock(WifiNative.ScanEventHandler.class);
217        WifiNative.ScanSettings scanSettings = createDummyScanSettings();
218        ScanResults scanResults = createDummyScanResults();
219
220        InOrder order = inOrder(scanEventHandler, mWifiNative);
221
222        // Start PNO scan
223        startSuccessfulPnoScan(scanSettings, pnoSettings, scanEventHandler, pnoEventHandler);
224
225        expectSuccessfulSwPnoScan(order, scanEventHandler, scanResults);
226
227        verifyNoMoreInteractions(pnoEventHandler);
228    }
229
230    private void createScannerWithHwPnoScanSupport() {
231        mResources.setBoolean(R.bool.config_wifi_background_scan_support, true);
232        mScanner = new SupplicantWifiScannerImpl(mContext, mWifiNative, mLooper.getLooper());
233    }
234
235    private void createScannerWithSwPnoScanSupport() {
236        mResources.setBoolean(R.bool.config_wifi_background_scan_support, false);
237        mScanner = new SupplicantWifiScannerImpl(mContext, mWifiNative, mLooper.getLooper());
238    }
239
240    private WifiNative.PnoSettings createDummyPnoSettings(boolean isConnected) {
241        WifiNative.PnoSettings pnoSettings = new WifiNative.PnoSettings();
242        pnoSettings.isConnected = isConnected;
243        pnoSettings.networkList = new WifiNative.PnoNetwork[2];
244        pnoSettings.networkList[0] = new WifiNative.PnoNetwork();
245        pnoSettings.networkList[0].ssid = "ssid_pno_1";
246        pnoSettings.networkList[0].networkId = 1;
247        pnoSettings.networkList[0].priority = 1;
248        pnoSettings.networkList[1] = new WifiNative.PnoNetwork();
249        pnoSettings.networkList[1].ssid = "ssid_pno_2";
250        pnoSettings.networkList[1].networkId = 2;
251        pnoSettings.networkList[1].priority = 2;
252        return pnoSettings;
253    }
254
255    private WifiNative.ScanSettings createDummyScanSettings() {
256        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
257                .withBasePeriod(10000)
258                .withMaxApPerScan(10)
259                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
260                        WifiScanner.WIFI_BAND_24_GHZ)
261                .build();
262        return settings;
263    }
264
265    private ScanResults createDummyScanResults() {
266        return ScanResults.create(0, 2400, 2450, 2450, 2400, 2450, 2450, 2400, 2450, 2450);
267    }
268
269    private void startSuccessfulPnoScan(WifiNative.ScanSettings scanSettings,
270            WifiNative.PnoSettings pnoSettings, WifiNative.ScanEventHandler scanEventHandler,
271            WifiNative.PnoEventHandler pnoEventHandler) {
272        when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString())).thenReturn(true);
273        when(mWifiNative.enableNetworkWithoutConnect(anyInt())).thenReturn(true);
274        // Scans succeed
275        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(true);
276        when(mWifiNative.setPnoScan(anyBoolean())).thenReturn(true);
277
278        if (mScanner.isHwPnoSupported(pnoSettings.isConnected)) {
279            // This should happen only for HW PNO scan
280            assertTrue(mScanner.setHwPnoList(pnoSettings, pnoEventHandler));
281        } else {
282            // This should happen only for SW PNO scan
283            assertTrue(mScanner.startBatchedScan(scanSettings, scanEventHandler));
284
285        }
286    }
287
288    private Set<Integer> expectedBandScanFreqs(int band) {
289        ChannelCollection collection = mScanner.getChannelHelper().createChannelCollection();
290        collection.addBand(band);
291        return collection.getSupplicantScanFreqs();
292    }
293
294    /**
295     * Verify that the PNO scan was successfully started.
296     */
297    private void expectSuccessfulHwDisconnectedPnoScan(InOrder order,
298            WifiNative.PnoSettings pnoSettings, WifiNative.PnoEventHandler eventHandler,
299            ScanResults scanResults) {
300        for (int i = 0; i < pnoSettings.networkList.length; i++) {
301            WifiNative.PnoNetwork network = pnoSettings.networkList[i];
302            order.verify(mWifiNative).setNetworkVariable(network.networkId,
303                    WifiConfiguration.priorityVarName, Integer.toString(network.priority));
304            order.verify(mWifiNative).enableNetworkWithoutConnect(network.networkId);
305        }
306        // Verify  HW PNO scan started
307        order.verify(mWifiNative).setPnoScan(true);
308
309        // Setup scan results
310        when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList());
311
312        // Notify scan has finished
313        mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
314        assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());
315
316        order.verify(eventHandler).onPnoNetworkFound(scanResults.getRawScanResults());
317    }
318
319    /**
320     * Verify that the single scan results were delivered and that the PNO scan was paused and
321     * resumed either side of it.
322     */
323    private void expectSuccessfulSingleScanWithHwPnoEnabled(InOrder order,
324            WifiNative.ScanEventHandler eventHandler, Set<Integer> expectedScanFreqs,
325            Set<Integer> expectedHiddenNetIds, ScanResults scanResults) {
326        // Pause PNO scan first
327        order.verify(mWifiNative).setPnoScan(false);
328
329        order.verify(mWifiNative).scan(eq(expectedScanFreqs), eq(expectedHiddenNetIds));
330
331        when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList());
332
333        // Notify scan has finished
334        mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
335        assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());
336
337        order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
338        assertScanDataEquals(scanResults.getScanData(), mScanner.getLatestSingleScanResults());
339    }
340
341    /**
342     * Verify that the SW PNO scan was successfully started. This could either be disconnected
343     * or connected PNO.
344     * This is basically ensuring that the background scan runs successfully and returns the
345     * expected result.
346     */
347    private void expectSuccessfulSwPnoScan(InOrder order,
348            WifiNative.ScanEventHandler eventHandler, ScanResults scanResults) {
349
350        // Verify scan started
351        order.verify(mWifiNative).scan(any(Set.class), any(Set.class));
352
353        // Make sure that HW PNO scan was not started
354        verify(mWifiNative, never()).setPnoScan(anyBoolean());
355
356        // Setup scan results
357        when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList());
358
359        // Notify scan has finished
360        mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
361        assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());
362
363        // Verify background scan results delivered
364        order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
365        WifiScanner.ScanData[] scanData = mScanner.getLatestBatchedScanResults(true);
366        WifiScanner.ScanData lastScanData = scanData[scanData.length -1];
367        assertScanDataEquals(scanResults.getScanData(), lastScanData);
368    }
369}
370