BaseWifiScannerImplTest.java revision 362fad8eddd674d7cf19ffcc1fec38d2d2ee2f53
1/*
2 * Copyright (C) 2015 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;
21import static com.android.server.wifi.ScanTestUtil.createFreqSet;
22
23import static org.junit.Assert.*;
24import static org.mockito.Mockito.*;
25
26import android.content.Context;
27import android.net.wifi.ScanResult;
28import android.net.wifi.WifiScanner;
29import android.net.wifi.WifiScanner.ScanData;
30import android.net.wifi.WifiSsid;
31import android.os.SystemClock;
32
33import com.android.server.wifi.MockAlarmManager;
34import com.android.server.wifi.MockLooper;
35import com.android.server.wifi.MockResources;
36import com.android.server.wifi.MockWifiMonitor;
37import com.android.server.wifi.ScanDetail;
38import com.android.server.wifi.ScanResults;
39import com.android.server.wifi.WifiMonitor;
40import com.android.server.wifi.WifiNative;
41import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection;
42
43import org.junit.Before;
44import org.junit.Test;
45import org.mockito.InOrder;
46import org.mockito.Mock;
47import org.mockito.MockitoAnnotations;
48
49import java.util.ArrayList;
50import java.util.Arrays;
51import java.util.Collections;
52import java.util.HashSet;
53import java.util.Set;
54
55/**
56 * Base unit tests that should pass for all implementations of
57 * {@link com.android.server.wifi.scanner.WifiScannerImpl}.
58 */
59public abstract class BaseWifiScannerImplTest {
60    @Mock Context mContext;
61    MockAlarmManager mAlarmManager;
62    MockWifiMonitor mWifiMonitor;
63    MockLooper mLooper;
64    @Mock WifiNative mWifiNative;
65    MockResources mResources;
66
67    /**
68     * mScanner implementation should be filled in by derived test class
69     */
70    WifiScannerImpl mScanner;
71
72    @Before
73    public void setUpBase() throws Exception {
74        MockitoAnnotations.initMocks(this);
75
76        mLooper = new MockLooper();
77        mAlarmManager = new MockAlarmManager();
78        mWifiMonitor = new MockWifiMonitor();
79        mResources = new MockResources();
80
81        when(mWifiNative.getInterfaceName()).thenReturn("a_test_interface_name");
82
83        when(mContext.getSystemService(Context.ALARM_SERVICE))
84                .thenReturn(mAlarmManager.getAlarmManager());
85
86        when(mContext.getResources()).thenReturn(mResources);
87    }
88
89    protected Set<Integer> expectedBandScanFreqs(int band) {
90        ChannelCollection collection = mScanner.getChannelHelper().createChannelCollection();
91        collection.addBand(band);
92        return collection.getSupplicantScanFreqs();
93    }
94
95    protected Set<Integer> expectedBandAndChannelScanFreqs(int band, int... channels) {
96        ChannelCollection collection = mScanner.getChannelHelper().createChannelCollection();
97        collection.addBand(band);
98        for (int channel : channels) {
99            collection.addChannel(channel);
100        }
101        return collection.getSupplicantScanFreqs();
102    }
103
104    @Test
105    public void singleScanSuccess() {
106        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
107                .withBasePeriod(10000) // ms
108                .withMaxApPerScan(10)
109                .addBucketWithBand(10000 /* ms */, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
110                        WifiScanner.WIFI_BAND_24_GHZ)
111                .build();
112
113        doSuccessfulSingleScanTest(settings, expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ),
114                new HashSet<Integer>(),
115                ScanResults.create(0, 2400, 2450, 2450, 2400, 2450, 2450, 2400, 2450, 2450), false);
116    }
117
118    @Test
119    public void singleScanSuccessWithChannels() {
120        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
121                .withBasePeriod(10000)
122                .withMaxApPerScan(10)
123                .addBucketWithChannels(20000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, 5650)
124                .build();
125
126        doSuccessfulSingleScanTest(settings, createFreqSet(5650),
127                new HashSet<Integer>(),
128                ScanResults.create(0, 5650, 5650, 5650, 5650, 5650, 5650, 5650, 5650), false);
129    }
130
131    @Test
132    public void singleScanSuccessWithFullResults() {
133        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
134                .withBasePeriod(10000)
135                .withMaxApPerScan(10)
136                .addBucketWithBand(10000,
137                        WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
138                        | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT,
139                        WifiScanner.WIFI_BAND_24_GHZ)
140                .build();
141
142        doSuccessfulSingleScanTest(settings, expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ),
143                new HashSet<Integer>(),
144                ScanResults.create(0, 2400, 2450, 2450, 2400, 2450, 2450, 2400, 2450, 2450), true);
145    }
146
147    /**
148     * Tests whether the provided hidden networkId's in scan settings is correctly passed along
149     * when invoking native scan.
150     */
151    @Test
152    public void singleScanSuccessWithHiddenNetworkIds() {
153        int[] hiddenNetworkIds = {0, 5};
154        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
155                .withBasePeriod(10000)
156                .withMaxApPerScan(10)
157                .withHiddenNetworkIds(hiddenNetworkIds)
158                .addBucketWithChannels(20000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, 5650)
159                .build();
160
161        Set<Integer> hiddenNetworkIdSet = new HashSet<Integer>();
162        for (int i = 0; i < hiddenNetworkIds.length; i++) {
163            hiddenNetworkIdSet.add(hiddenNetworkIds[i]);
164        }
165        doSuccessfulSingleScanTest(settings, createFreqSet(5650),
166                hiddenNetworkIdSet,
167                ScanResults.create(0, 5650, 5650, 5650, 5650, 5650, 5650, 5650, 5650), false);
168    }
169
170    /**
171     * Tests whether the provided hidden networkId's in scan settings is truncated to max size
172     * supported by wpa_supplicant when invoking native scan.
173     */
174    @Test
175    public void singleScanSuccessWithTruncatedHiddenNetworkIds() {
176        int[] hiddenNetworkIds = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
177        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
178                .withBasePeriod(10000)
179                .withMaxApPerScan(10)
180                .withHiddenNetworkIds(hiddenNetworkIds)
181                .addBucketWithChannels(20000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, 5650)
182                .build();
183
184        Set<Integer> hiddenNetworkIdSet = new HashSet<Integer>();
185        for (int i = 0; i < SupplicantWifiScannerImpl.MAX_HIDDEN_NETWORK_IDS_PER_SCAN; i++) {
186            hiddenNetworkIdSet.add(hiddenNetworkIds[i]);
187        }
188        doSuccessfulSingleScanTest(settings, createFreqSet(5650),
189                hiddenNetworkIdSet,
190                ScanResults.create(0, 5650, 5650, 5650, 5650, 5650, 5650, 5650, 5650), false);
191    }
192
193    @Test
194    public void overlappingSingleScanFails() {
195        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
196                .withBasePeriod(10000) // ms
197                .withMaxApPerScan(10)
198                .addBucketWithBand(10000 /* ms */, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
199                        WifiScanner.WIFI_BAND_24_GHZ)
200                .build();
201        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
202
203        WifiNative.ScanSettings settings2 = new NativeScanSettingsBuilder()
204                .withBasePeriod(10000) // ms
205                .withMaxApPerScan(10)
206                .addBucketWithBand(10000 /* ms */, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
207                        WifiScanner.WIFI_BAND_5_GHZ)
208                .build();
209        WifiNative.ScanEventHandler eventHandler2 = mock(WifiNative.ScanEventHandler.class);
210
211        // scan start succeeds
212        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(true);
213
214        assertTrue(mScanner.startSingleScan(settings, eventHandler));
215        assertFalse("second scan while first scan running should fail immediately",
216                mScanner.startSingleScan(settings2, eventHandler2));
217    }
218
219    @Test
220    public void singleScanFailOnExecute() {
221        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
222                .withBasePeriod(10000)
223                .withMaxApPerScan(10)
224                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
225                        WifiScanner.WIFI_BAND_24_GHZ)
226                .build();
227
228        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
229
230        ScanResults results = ScanResults.create(0, 2400, 2450, 2450);
231
232        InOrder order = inOrder(eventHandler, mWifiNative);
233
234        // scan fails
235        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(false);
236
237        // start scan
238        assertTrue(mScanner.startSingleScan(settings, eventHandler));
239
240        mLooper.dispatchAll();
241        order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_FAILED);
242
243        verifyNoMoreInteractions(eventHandler);
244    }
245
246    /**
247     * Test that a scan failure is reported if a scan times out
248     */
249    @Test
250    public void singleScanFailOnTimeout() {
251        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
252                .withBasePeriod(10000)
253                .withMaxApPerScan(10)
254                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
255                        WifiScanner.WIFI_BAND_24_GHZ)
256                .build();
257
258        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
259
260        ScanResults results = ScanResults.create(0, 2400, 2450, 2450);
261
262        InOrder order = inOrder(eventHandler, mWifiNative);
263
264        // scan succeeds
265        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(true);
266
267        // start scan
268        assertTrue(mScanner.startSingleScan(settings, eventHandler));
269        mLooper.dispatchAll();
270
271        // Fire timeout
272        mAlarmManager.dispatch(SupplicantWifiScannerImpl.TIMEOUT_ALARM_TAG);
273        mLooper.dispatchAll();
274
275        order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_FAILED);
276
277        verifyNoMoreInteractions(eventHandler);
278    }
279
280    /**
281     * Test that a scan failure is reported if supplicant sends a scan failed event
282     */
283    @Test
284    public void singleScanFailOnFailedEvent() {
285        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
286                .withBasePeriod(10000)
287                .withMaxApPerScan(10)
288                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
289                        WifiScanner.WIFI_BAND_24_GHZ)
290                .build();
291
292        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
293
294        ScanResults results = ScanResults.create(0, 2400, 2450, 2450);
295
296        InOrder order = inOrder(eventHandler, mWifiNative);
297
298        // scan succeeds
299        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(true);
300
301        // start scan
302        assertTrue(mScanner.startSingleScan(settings, eventHandler));
303        mLooper.dispatchAll();
304
305        // Fire failed event
306        mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_FAILED_EVENT);
307        mLooper.dispatchAll();
308
309        order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_FAILED);
310
311        verifyNoMoreInteractions(eventHandler);
312    }
313
314    @Test
315    public void singleScanNullEventHandler() {
316        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
317                .withBasePeriod(10000)
318                .withMaxApPerScan(10)
319                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
320                        WifiScanner.WIFI_BAND_24_GHZ)
321                .build();
322        assertFalse(mScanner.startSingleScan(settings, null));
323    }
324
325    @Test
326    public void singleScanNullSettings() {
327        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
328
329        assertFalse(mScanner.startSingleScan(null, eventHandler));
330
331        verifyNoMoreInteractions(eventHandler);
332    }
333
334    @Test
335    public void multipleSingleScanSuccess() {
336        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
337                .withBasePeriod(10000)
338                .withMaxApPerScan(10)
339                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
340                        WifiScanner.WIFI_BAND_24_GHZ)
341                .build();
342        WifiNative.ScanSettings settings2 = new NativeScanSettingsBuilder()
343                .withBasePeriod(10000)
344                .withMaxApPerScan(10)
345                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
346                        WifiScanner.WIFI_BAND_5_GHZ)
347                .build();
348
349        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
350        InOrder order = inOrder(eventHandler, mWifiNative);
351
352        // scans succeed
353        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(true);
354
355        // start first scan
356        assertTrue(mScanner.startSingleScan(settings, eventHandler));
357
358        expectSuccessfulSingleScan(order, eventHandler,
359                expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ),
360                new HashSet<Integer>(),
361                ScanResults.create(0, 2400, 2450, 2450), false);
362
363        // start second scan
364        assertTrue(mScanner.startSingleScan(settings2, eventHandler));
365
366        expectSuccessfulSingleScan(order, eventHandler,
367                expectedBandScanFreqs(WifiScanner.WIFI_BAND_5_GHZ),
368                new HashSet<Integer>(),
369                ScanResults.create(0, 5150, 5175), false);
370
371        verifyNoMoreInteractions(eventHandler);
372    }
373
374    /**
375     * Validate that scan results that are returned from supplicant, which are timestamped prior to
376     * the start of the scan, are ignored.
377     */
378    @Test
379    public void singleScanWhereSupplicantReturnsSomeOldResults() {
380        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
381                .withBasePeriod(10000)
382                .withMaxApPerScan(2)
383                .addBucketWithBand(10000,
384                        WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
385                        | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT,
386                        WifiScanner.WIFI_BAND_24_GHZ)
387                .build();
388
389        long approxScanStartUs = SystemClock.elapsedRealtime() * 1000;
390        ArrayList<ScanDetail> rawResults = new ArrayList<>(Arrays.asList(
391                        new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 1"),
392                                "00:00:00:00:00:00", "", -70, 2450,
393                                approxScanStartUs + 2000 * 1000, 0),
394                        new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 2"),
395                                "AA:BB:CC:DD:EE:FF", "", -66, 2400,
396                                approxScanStartUs + 2500 * 1000, 0),
397                        new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 3"),
398                                "00:00:00:00:00:00", "", -80, 2450,
399                                approxScanStartUs - 2000 * 1000, 0), // old result will be filtered
400                        new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 4"),
401                                "AA:BB:CC:11:22:33", "", -65, 2450,
402                                approxScanStartUs + 4000 * 1000, 0)));
403
404        ArrayList<ScanResult> fullResults = new ArrayList<>();
405        for (ScanDetail detail : rawResults) {
406            if (detail.getScanResult().timestamp > approxScanStartUs) {
407                fullResults.add(detail.getScanResult());
408            }
409        }
410        ArrayList<ScanResult> scanDataResults = new ArrayList<>(fullResults);
411        Collections.sort(scanDataResults, ScanResults.SCAN_RESULT_RSSI_COMPARATOR);
412        ScanData scanData = new ScanData(0, 0,
413                scanDataResults.toArray(new ScanResult[scanDataResults.size()]));
414        Set<Integer> expectedScan = expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ);
415
416        // Actual test
417
418        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
419
420        InOrder order = inOrder(eventHandler, mWifiNative);
421
422        // scan succeeds
423        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(true);
424
425        // start scan
426        assertTrue(mScanner.startSingleScan(settings, eventHandler));
427
428        order.verify(mWifiNative).scan(eq(expectedScan), any(Set.class));
429
430        when(mWifiNative.getScanResults()).thenReturn(rawResults);
431
432        // Notify scan has finished
433        mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
434
435        mLooper.dispatchAll();
436
437        for (ScanResult result : fullResults) {
438            order.verify(eventHandler).onFullScanResult(eq(result), eq(0));
439        }
440
441        order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
442        assertScanDataEquals(scanData, mScanner.getLatestSingleScanResults());
443
444        verifyNoMoreInteractions(eventHandler);
445    }
446
447    @Test
448    public void backgroundScanNullEventHandler() {
449        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
450                .withBasePeriod(10000)
451                .withMaxApPerScan(10)
452                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
453                        WifiScanner.WIFI_BAND_24_GHZ)
454                .build();
455        assertFalse(mScanner.startBatchedScan(settings, null));
456    }
457
458    @Test
459    public void backgroundScanNullSettings() {
460        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
461
462        assertFalse(mScanner.startBatchedScan(null, eventHandler));
463
464        verifyNoMoreInteractions(eventHandler);
465    }
466
467    protected void doSuccessfulSingleScanTest(WifiNative.ScanSettings settings,
468            Set<Integer> expectedScan, Set<Integer> expectedHiddenNetIds, ScanResults results,
469            boolean expectFullResults) {
470        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
471
472        InOrder order = inOrder(eventHandler, mWifiNative);
473
474        // scan succeeds
475        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(true);
476
477        // start scan
478        assertTrue(mScanner.startSingleScan(settings, eventHandler));
479
480        expectSuccessfulSingleScan(order, eventHandler, expectedScan, expectedHiddenNetIds,
481                results, expectFullResults);
482
483        verifyNoMoreInteractions(eventHandler);
484    }
485
486    protected void expectSuccessfulSingleScan(InOrder order,
487            WifiNative.ScanEventHandler eventHandler, Set<Integer> expectedScan,
488            Set<Integer> expectedHiddenNetIds, ScanResults results, boolean expectFullResults) {
489        order.verify(mWifiNative).scan(eq(expectedScan), eq(expectedHiddenNetIds));
490
491        when(mWifiNative.getScanResults()).thenReturn(results.getScanDetailArrayList());
492
493        // Notify scan has finished
494        mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
495
496        mLooper.dispatchAll();
497
498        if (expectFullResults) {
499            for (ScanResult result : results.getRawScanResults()) {
500                order.verify(eventHandler).onFullScanResult(eq(result), eq(0));
501            }
502        }
503
504        order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
505        assertScanDataEquals(results.getScanData(), mScanner.getLatestSingleScanResults());
506    }
507}
508