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.*;
20
21import static org.junit.Assert.*;
22import static org.mockito.Matchers.*;
23import static org.mockito.Mockito.*;
24
25import android.content.BroadcastReceiver;
26import android.content.Context;
27import android.content.IntentFilter;
28import android.net.wifi.ScanResult;
29import android.net.wifi.WifiManager;
30import android.net.wifi.WifiScanner;
31import android.os.Binder;
32import android.os.Bundle;
33import android.os.Handler;
34import android.os.Looper;
35import android.os.Message;
36import android.os.RemoteException;
37import android.os.WorkSource;
38import android.test.suitebuilder.annotation.SmallTest;
39import android.util.Pair;
40
41import com.android.internal.app.IBatteryStats;
42import com.android.internal.util.AsyncChannel;
43import com.android.internal.util.Protocol;
44import com.android.server.wifi.BidirectionalAsyncChannel;
45import com.android.server.wifi.Clock;
46import com.android.server.wifi.MockAlarmManager;
47import com.android.server.wifi.MockAnswerUtil.AnswerWithArguments;
48import com.android.server.wifi.MockLooper;
49import com.android.server.wifi.ScanResults;
50import com.android.server.wifi.TestUtil;
51import com.android.server.wifi.WifiInjector;
52import com.android.server.wifi.WifiMetrics;
53import com.android.server.wifi.WifiMetricsProto;
54import com.android.server.wifi.WifiNative;
55
56import org.junit.After;
57import org.junit.Before;
58import org.junit.Test;
59import org.mockito.ArgumentCaptor;
60import org.mockito.InOrder;
61import org.mockito.Mock;
62import org.mockito.MockitoAnnotations;
63import org.mockito.internal.matchers.CapturingMatcher;
64
65import java.io.FileDescriptor;
66import java.io.PrintWriter;
67import java.io.StringWriter;
68import java.util.ArrayList;
69import java.util.Arrays;
70import java.util.Collections;
71import java.util.regex.Pattern;
72
73/**
74 * Unit tests for {@link com.android.server.wifi.scanner.WifiScanningServiceImpl}.
75 */
76@SmallTest
77public class WifiScanningServiceTest {
78    public static final String TAG = "WifiScanningServiceTest";
79
80    @Mock Context mContext;
81    MockAlarmManager mAlarmManager;
82    @Mock WifiScannerImpl mWifiScannerImpl;
83    @Mock WifiScannerImpl.WifiScannerImplFactory mWifiScannerImplFactory;
84    @Mock IBatteryStats mBatteryStats;
85    @Mock WifiInjector mWifiInjector;
86    @Mock Clock mClock;
87    WifiMetrics mWifiMetrics;
88    MockLooper mLooper;
89    WifiScanningServiceImpl mWifiScanningServiceImpl;
90
91
92    @Before
93    public void setUp() throws Exception {
94        MockitoAnnotations.initMocks(this);
95
96        mAlarmManager = new MockAlarmManager();
97        when(mContext.getSystemService(Context.ALARM_SERVICE))
98                .thenReturn(mAlarmManager.getAlarmManager());
99        mWifiMetrics = new WifiMetrics(mClock);
100
101        ChannelHelper channelHelper = new PresetKnownBandsChannelHelper(
102                new int[]{2400, 2450},
103                new int[]{5150, 5175},
104                new int[]{5600, 5650, 5660});
105
106        mLooper = new MockLooper();
107        when(mWifiScannerImplFactory
108                .create(any(Context.class), any(Looper.class), any(Clock.class)))
109                .thenReturn(mWifiScannerImpl);
110        when(mWifiScannerImpl.getChannelHelper()).thenReturn(channelHelper);
111        when(mWifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics);
112        mWifiScanningServiceImpl = new WifiScanningServiceImpl(mContext, mLooper.getLooper(),
113                mWifiScannerImplFactory, mBatteryStats, mWifiInjector);
114    }
115
116    @After
117    public void cleanup() {
118        validateMockitoUsage();
119    }
120
121    /**
122     * Internal BroadcastReceiver that WifiScanningServiceImpl uses to listen for broadcasts
123     * this is initialized by calling startServiceAndLoadDriver
124     */
125    BroadcastReceiver mBroadcastReceiver;
126
127    private WifiScanner.ScanSettings generateValidScanSettings() {
128        return createRequest(WifiScanner.WIFI_BAND_BOTH, 30000, 0, 20,
129                WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
130    }
131
132    private BidirectionalAsyncChannel connectChannel(Handler handler) {
133        BidirectionalAsyncChannel controlChannel = new BidirectionalAsyncChannel();
134        controlChannel.connect(mLooper.getLooper(), mWifiScanningServiceImpl.getMessenger(),
135                handler);
136        mLooper.dispatchAll();
137        controlChannel.assertConnected();
138        return controlChannel;
139    }
140
141    private static Message verifyHandleMessageAndGetMessage(InOrder order, Handler handler) {
142        ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
143        order.verify(handler).handleMessage(messageCaptor.capture());
144        return messageCaptor.getValue();
145    }
146
147    private static Message verifyHandleMessageAndGetMessage(InOrder order, Handler handler,
148            final int what) {
149        CapturingMatcher<Message> messageMatcher = new CapturingMatcher<Message>() {
150            public boolean matches(Object argument) {
151                Message message = (Message) argument;
152                return message.what == what;
153            }
154        };
155        order.verify(handler).handleMessage(argThat(messageMatcher));
156        return messageMatcher.getLastValue();
157    }
158
159    private static void verifyScanResultsRecieved(InOrder order, Handler handler, int listenerId,
160            WifiScanner.ScanData... expected) {
161        Message scanResultMessage = verifyHandleMessageAndGetMessage(order, handler,
162                WifiScanner.CMD_SCAN_RESULT);
163        assertScanResultsMessage(listenerId, expected, scanResultMessage);
164    }
165
166    private static void assertScanResultsMessage(int listenerId, WifiScanner.ScanData[] expected,
167            Message scanResultMessage) {
168        assertEquals("what", WifiScanner.CMD_SCAN_RESULT, scanResultMessage.what);
169        assertEquals("listenerId", listenerId, scanResultMessage.arg2);
170        assertScanDatasEquals(expected,
171                ((WifiScanner.ParcelableScanData) scanResultMessage.obj).getResults());
172    }
173
174    private static void verifySingleScanCompletedRecieved(InOrder order, Handler handler,
175            int listenerId) {
176        Message completedMessage = verifyHandleMessageAndGetMessage(order, handler,
177                WifiScanner.CMD_SINGLE_SCAN_COMPLETED);
178        assertSingleScanCompletedMessage(listenerId, completedMessage);
179    }
180
181    private static void assertSingleScanCompletedMessage(int listenerId, Message completedMessage) {
182        assertEquals("what", WifiScanner.CMD_SINGLE_SCAN_COMPLETED, completedMessage.what);
183        assertEquals("listenerId", listenerId, completedMessage.arg2);
184    }
185
186    private static void sendBackgroundScanRequest(BidirectionalAsyncChannel controlChannel,
187            int scanRequestId, WifiScanner.ScanSettings settings, WorkSource workSource) {
188        Bundle scanParams = new Bundle();
189        scanParams.putParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
190        scanParams.putParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
191        controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_START_BACKGROUND_SCAN, 0,
192                        scanRequestId, scanParams));
193    }
194
195    private static void sendSingleScanRequest(BidirectionalAsyncChannel controlChannel,
196            int scanRequestId, WifiScanner.ScanSettings settings, WorkSource workSource) {
197        Bundle scanParams = new Bundle();
198        scanParams.putParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
199        scanParams.putParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
200        controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_START_SINGLE_SCAN, 0,
201                        scanRequestId, scanParams));
202    }
203
204    private static void registerScanListener(BidirectionalAsyncChannel controlChannel,
205            int listenerRequestId) {
206        controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_REGISTER_SCAN_LISTENER, 0,
207                        listenerRequestId, null));
208    }
209
210    private static void deregisterScanListener(BidirectionalAsyncChannel controlChannel,
211            int listenerRequestId) {
212        controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_DEREGISTER_SCAN_LISTENER, 0,
213                        listenerRequestId, null));
214    }
215
216    private static void verifySuccessfulResponse(InOrder order, Handler handler, int arg2) {
217        Message response = verifyHandleMessageAndGetMessage(order, handler);
218        assertSuccessfulResponse(arg2, response);
219    }
220
221    private static void assertSuccessfulResponse(int arg2, Message response) {
222        if (response.what == WifiScanner.CMD_OP_FAILED) {
223            WifiScanner.OperationResult result = (WifiScanner.OperationResult) response.obj;
224            fail("response indicates failure, reason=" + result.reason
225                    + ", description=" + result.description);
226        } else {
227            assertEquals("response.what", WifiScanner.CMD_OP_SUCCEEDED, response.what);
228            assertEquals("response.arg2", arg2, response.arg2);
229        }
230    }
231
232    /**
233     * If multiple results are expected for a single hardware scan then the order that they are
234     * dispatched is dependant on the order which they are iterated through internally. This
235     * function validates that the order is either one way or the other. A scan listener can
236     * optionally be provided as well and will be checked after the after the single scan requests.
237     */
238    private static void verifyMultipleSingleScanResults(InOrder handlerOrder, Handler handler,
239            int requestId1, ScanResults results1, int requestId2, ScanResults results2,
240            int listenerRequestId, ScanResults listenerResults) {
241        ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
242        handlerOrder.verify(handler, times(listenerResults == null ? 4 : 5))
243                .handleMessage(messageCaptor.capture());
244        int firstListenerId = messageCaptor.getAllValues().get(0).arg2;
245        assertTrue(firstListenerId + " was neither " + requestId2 + " nor " + requestId1,
246                firstListenerId == requestId2 || firstListenerId == requestId1);
247        if (firstListenerId == requestId2) {
248            assertScanResultsMessage(requestId2,
249                    new WifiScanner.ScanData[] {results2.getScanData()},
250                    messageCaptor.getAllValues().get(0));
251            assertSingleScanCompletedMessage(requestId2, messageCaptor.getAllValues().get(1));
252            assertScanResultsMessage(requestId1,
253                    new WifiScanner.ScanData[] {results1.getScanData()},
254                    messageCaptor.getAllValues().get(2));
255            assertSingleScanCompletedMessage(requestId1, messageCaptor.getAllValues().get(3));
256            if (listenerResults != null) {
257                assertScanResultsMessage(listenerRequestId,
258                        new WifiScanner.ScanData[] {listenerResults.getScanData()},
259                        messageCaptor.getAllValues().get(4));
260            }
261        } else {
262            assertScanResultsMessage(requestId1,
263                    new WifiScanner.ScanData[] {results1.getScanData()},
264                    messageCaptor.getAllValues().get(0));
265            assertSingleScanCompletedMessage(requestId1, messageCaptor.getAllValues().get(1));
266            assertScanResultsMessage(requestId2,
267                    new WifiScanner.ScanData[] {results2.getScanData()},
268                    messageCaptor.getAllValues().get(2));
269            assertSingleScanCompletedMessage(requestId2, messageCaptor.getAllValues().get(3));
270            if (listenerResults != null) {
271                assertScanResultsMessage(listenerRequestId,
272                        new WifiScanner.ScanData[] {listenerResults.getScanData()},
273                        messageCaptor.getAllValues().get(4));
274            }
275        }
276    }
277
278    private static void verifyMultipleSingleScanResults(InOrder handlerOrder, Handler handler,
279            int requestId1, ScanResults results1, int requestId2, ScanResults results2) {
280        verifyMultipleSingleScanResults(handlerOrder, handler, requestId1, results1, requestId2,
281                results2, -1, null);
282    }
283
284    private static void verifyFailedResponse(InOrder order, Handler handler, int arg2,
285            int expectedErrorReason, String expectedErrorDescription) {
286        Message response = verifyHandleMessageAndGetMessage(order, handler);
287        assertFailedResponse(arg2, expectedErrorReason, expectedErrorDescription, response);
288    }
289
290    private static void assertFailedResponse(int arg2, int expectedErrorReason,
291            String expectedErrorDescription, Message response) {
292        if (response.what == WifiScanner.CMD_OP_SUCCEEDED) {
293            fail("response indicates success");
294        } else {
295            assertEquals("response.what", WifiScanner.CMD_OP_FAILED, response.what);
296            assertEquals("response.arg2", arg2, response.arg2);
297            WifiScanner.OperationResult result = (WifiScanner.OperationResult) response.obj;
298            assertEquals("response.obj.reason",
299                    expectedErrorReason, result.reason);
300            assertEquals("response.obj.description",
301                    expectedErrorDescription, result.description);
302        }
303    }
304
305    private WifiNative.ScanEventHandler verifyStartSingleScan(InOrder order,
306            WifiNative.ScanSettings expected) {
307        ArgumentCaptor<WifiNative.ScanSettings> scanSettingsCaptor =
308                ArgumentCaptor.forClass(WifiNative.ScanSettings.class);
309        ArgumentCaptor<WifiNative.ScanEventHandler> scanEventHandlerCaptor =
310                ArgumentCaptor.forClass(WifiNative.ScanEventHandler.class);
311        order.verify(mWifiScannerImpl).startSingleScan(scanSettingsCaptor.capture(),
312                scanEventHandlerCaptor.capture());
313        assertNativeScanSettingsEquals(expected, scanSettingsCaptor.getValue());
314        return scanEventHandlerCaptor.getValue();
315    }
316
317    private WifiNative.ScanEventHandler verifyStartBackgroundScan(InOrder order,
318            WifiNative.ScanSettings expected) {
319        ArgumentCaptor<WifiNative.ScanSettings> scanSettingsCaptor =
320                ArgumentCaptor.forClass(WifiNative.ScanSettings.class);
321        ArgumentCaptor<WifiNative.ScanEventHandler> scanEventHandlerCaptor =
322                ArgumentCaptor.forClass(WifiNative.ScanEventHandler.class);
323        order.verify(mWifiScannerImpl).startBatchedScan(scanSettingsCaptor.capture(),
324                scanEventHandlerCaptor.capture());
325        assertNativeScanSettingsEquals(expected, scanSettingsCaptor.getValue());
326        return scanEventHandlerCaptor.getValue();
327    }
328
329    private static final int MAX_AP_PER_SCAN = 16;
330    private void startServiceAndLoadDriver() {
331        mWifiScanningServiceImpl.startService();
332        setupAndLoadDriver();
333    }
334
335    private void setupAndLoadDriver() {
336        when(mWifiScannerImpl.getScanCapabilities(any(WifiNative.ScanCapabilities.class)))
337                .thenAnswer(new AnswerWithArguments() {
338                        public boolean answer(WifiNative.ScanCapabilities capabilities) {
339                            capabilities.max_scan_cache_size = Integer.MAX_VALUE;
340                            capabilities.max_scan_buckets = 8;
341                            capabilities.max_ap_cache_per_scan = MAX_AP_PER_SCAN;
342                            capabilities.max_rssi_sample_size = 8;
343                            capabilities.max_scan_reporting_threshold = 10;
344                            capabilities.max_hotlist_bssids = 0;
345                            capabilities.max_significant_wifi_change_aps = 0;
346                            return true;
347                        }
348                    });
349        ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
350                ArgumentCaptor.forClass(BroadcastReceiver.class);
351        verify(mContext)
352                .registerReceiver(broadcastReceiverCaptor.capture(), any(IntentFilter.class));
353        mBroadcastReceiver = broadcastReceiverCaptor.getValue();
354        TestUtil.sendWifiScanAvailable(broadcastReceiverCaptor.getValue(), mContext,
355                WifiManager.WIFI_STATE_ENABLED);
356        mLooper.dispatchAll();
357    }
358
359    private String dumpService() {
360        StringWriter stringWriter = new StringWriter();
361        mWifiScanningServiceImpl.dump(new FileDescriptor(), new PrintWriter(stringWriter),
362                new String[0]);
363        return stringWriter.toString();
364    }
365
366    private void assertDumpContainsRequestLog(String type, int id) {
367        String serviceDump = dumpService();
368        Pattern logLineRegex = Pattern.compile("^.+" + type
369                + ": ClientInfo\\[uid=\\d+,android\\.os\\.Messenger@[a-f0-9]+\\],Id=" + id
370                + ".*$", Pattern.MULTILINE);
371        assertTrue("dump did not contain log with type=" + type + ", id=" + id +
372                ": " + serviceDump + "\n",
373                logLineRegex.matcher(serviceDump).find());
374    }
375
376    private void assertDumpContainsCallbackLog(String callback, int id, String extra) {
377        String serviceDump = dumpService();
378        String extraPattern = extra == null ? "" : "," + extra;
379        Pattern logLineRegex = Pattern.compile("^.+" + callback
380                + ": ClientInfo\\[uid=\\d+,android\\.os\\.Messenger@[a-f0-9]+\\],Id=" + id
381                + extraPattern + "$", Pattern.MULTILINE);
382        assertTrue("dump did not contain callback log with callback=" + callback + ", id=" + id +
383                ", extra=" + extra + ": " + serviceDump + "\n",
384                logLineRegex.matcher(serviceDump).find());
385    }
386
387    @Test
388    public void construct() throws Exception {
389        verifyNoMoreInteractions(mWifiScannerImpl, mWifiScannerImpl,
390                mWifiScannerImplFactory, mBatteryStats);
391        dumpService(); // make sure this succeeds
392    }
393
394    @Test
395    public void startService() throws Exception {
396        mWifiScanningServiceImpl.startService();
397        verifyNoMoreInteractions(mWifiScannerImplFactory);
398
399        Handler handler = mock(Handler.class);
400        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
401        InOrder order = inOrder(handler);
402        sendBackgroundScanRequest(controlChannel, 122, generateValidScanSettings(), null);
403        mLooper.dispatchAll();
404        verifyFailedResponse(order, handler, 122, WifiScanner.REASON_UNSPECIFIED, "not available");
405    }
406
407    @Test
408    public void disconnectClientBeforeWifiEnabled() throws Exception {
409        mWifiScanningServiceImpl.startService();
410
411        BidirectionalAsyncChannel controlChannel = connectChannel(mock(Handler.class));
412        mLooper.dispatchAll();
413
414        controlChannel.disconnect();
415        mLooper.dispatchAll();
416    }
417
418    @Test
419    public void loadDriver() throws Exception {
420        startServiceAndLoadDriver();
421        verify(mWifiScannerImplFactory, times(1))
422                .create(any(Context.class), any(Looper.class), any(Clock.class));
423
424        Handler handler = mock(Handler.class);
425        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
426        InOrder order = inOrder(handler);
427        when(mWifiScannerImpl.startBatchedScan(any(WifiNative.ScanSettings.class),
428                        any(WifiNative.ScanEventHandler.class))).thenReturn(true);
429        sendBackgroundScanRequest(controlChannel, 192, generateValidScanSettings(), null);
430        mLooper.dispatchAll();
431        verifySuccessfulResponse(order, handler, 192);
432        assertDumpContainsRequestLog("addBackgroundScanRequest", 192);
433    }
434
435    @Test
436    public void disconnectClientAfterStartingWifi() throws Exception {
437        mWifiScanningServiceImpl.startService();
438
439        BidirectionalAsyncChannel controlChannel = connectChannel(mock(Handler.class));
440        mLooper.dispatchAll();
441
442        setupAndLoadDriver();
443
444        controlChannel.disconnect();
445        mLooper.dispatchAll();
446    }
447
448    @Test
449    public void connectAndDisconnectClientAfterStartingWifi() throws Exception {
450        startServiceAndLoadDriver();
451
452        BidirectionalAsyncChannel controlChannel = connectChannel(mock(Handler.class));
453        mLooper.dispatchAll();
454        controlChannel.disconnect();
455        mLooper.dispatchAll();
456    }
457
458    @Test
459    public void sendInvalidCommand() throws Exception {
460        startServiceAndLoadDriver();
461
462        Handler handler = mock(Handler.class);
463        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
464        InOrder order = inOrder(handler, mWifiScannerImpl);
465        controlChannel.sendMessage(Message.obtain(null, Protocol.BASE_WIFI_MANAGER));
466        mLooper.dispatchAll();
467        verifyFailedResponse(order, handler, 0, WifiScanner.REASON_INVALID_REQUEST,
468                "Invalid request");
469    }
470
471    private void doSuccessfulSingleScan(WifiScanner.ScanSettings requestSettings,
472            WifiNative.ScanSettings nativeSettings, ScanResults results) throws RemoteException {
473        int requestId = 12;
474        WorkSource workSource = new WorkSource(2292);
475        startServiceAndLoadDriver();
476
477        Handler handler = mock(Handler.class);
478        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
479        InOrder order = inOrder(handler, mWifiScannerImpl);
480
481        when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
482                        any(WifiNative.ScanEventHandler.class))).thenReturn(true);
483
484        sendSingleScanRequest(controlChannel, requestId, requestSettings, workSource);
485
486        mLooper.dispatchAll();
487        WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(order, nativeSettings);
488        verifySuccessfulResponse(order, handler, requestId);
489        verify(mBatteryStats).noteWifiScanStartedFromSource(eq(workSource));
490
491        when(mWifiScannerImpl.getLatestSingleScanResults())
492                .thenReturn(results.getRawScanData());
493        eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
494
495        mLooper.dispatchAll();
496        verifyScanResultsRecieved(order, handler, requestId, results.getScanData());
497        verifySingleScanCompletedRecieved(order, handler, requestId);
498        verifyNoMoreInteractions(handler);
499        verify(mBatteryStats).noteWifiScanStoppedFromSource(eq(workSource));
500        assertDumpContainsRequestLog("addSingleScanRequest", requestId);
501        assertDumpContainsCallbackLog("singleScanResults", requestId,
502                "results=" + results.getScanData().getResults().length);
503    }
504
505    /**
506     * Do a single scan for a band and verify that it is successful.
507     */
508    @Test
509    public void sendSingleScanBandRequest() throws Exception {
510        WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH_WITH_DFS,
511                0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
512        doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings),
513                ScanResults.create(0, true, 2400, 5150, 5175));
514    }
515
516    /**
517     * Do a single scan for a list of channels and verify that it is successful.
518     */
519    @Test
520    public void sendSingleScanChannelsRequest() throws Exception {
521        WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(2400, 5150, 5175),
522                0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
523        doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings),
524                ScanResults.create(0, 2400, 5150, 5175));
525    }
526
527    /**
528     * Do a single scan for a list of all channels and verify that it is successful.
529     */
530    @Test
531    public void sendSingleScanAllChannelsRequest() throws Exception {
532        WifiScanner.ScanSettings requestSettings = createRequest(
533                channelsToSpec(2400, 2450, 5150, 5175, 5600, 5650, 5660),
534                0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
535        doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings),
536                ScanResults.create(0, true, 2400, 5150, 5175));
537    }
538
539    /**
540     * Do a single scan with no results and verify that it is successful.
541     */
542    @Test
543    public void sendSingleScanRequestWithNoResults() throws Exception {
544        WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
545                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
546        doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings),
547                ScanResults.create(0, new int[0]));
548    }
549
550    /**
551     * Do a single scan with results that do not match the requested scan and verify that it is
552     * still successful (and returns no results).
553     */
554    @Test
555    public void sendSingleScanRequestWithBadRawResults() throws Exception {
556        WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_24_GHZ, 0,
557                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
558        // Create a set of scan results that has results not matching the request settings, but is
559        // limited to zero results for the expected results.
560        ScanResults results = ScanResults.createOverflowing(0, 0,
561                ScanResults.generateNativeResults(0, 5150, 5171));
562        doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings),
563                results);
564    }
565
566    /**
567     * Do a single scan, which the hardware fails to start, and verify that a failure response is
568     * delivered.
569     */
570    @Test
571    public void sendSingleScanRequestWhichFailsToStart() throws Exception {
572        WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
573                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
574        int requestId = 33;
575
576        startServiceAndLoadDriver();
577
578        Handler handler = mock(Handler.class);
579        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
580        InOrder order = inOrder(handler, mWifiScannerImpl);
581
582        // scan fails
583        when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
584                        any(WifiNative.ScanEventHandler.class))).thenReturn(false);
585
586        sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
587
588        mLooper.dispatchAll();
589        // Scan is successfully queue, but then fails to execute
590        ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
591        order.verify(handler, times(2)).handleMessage(messageCaptor.capture());
592        assertSuccessfulResponse(requestId, messageCaptor.getAllValues().get(0));
593        assertFailedResponse(requestId, WifiScanner.REASON_UNSPECIFIED,
594                "Failed to start single scan", messageCaptor.getAllValues().get(1));
595        verifyNoMoreInteractions(mBatteryStats);
596
597        assertEquals(mWifiMetrics.getOneshotScanCount(), 1);
598        assertEquals(mWifiMetrics.getScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_UNKNOWN), 1);
599        assertDumpContainsRequestLog("addSingleScanRequest", requestId);
600    }
601
602    /**
603     * Do a single scan, which successfully starts, but fails partway through and verify that a
604     * failure response is delivered.
605     */
606    @Test
607    public void sendSingleScanRequestWhichFailsAfterStart() throws Exception {
608        WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
609                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
610        int requestId = 33;
611        WorkSource workSource = new WorkSource(Binder.getCallingUid()); // don't explicitly set
612
613        startServiceAndLoadDriver();
614
615        Handler handler = mock(Handler.class);
616        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
617        InOrder order = inOrder(handler, mWifiScannerImpl);
618
619        // successful start
620        when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
621                        any(WifiNative.ScanEventHandler.class))).thenReturn(true);
622
623        sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
624
625        // Scan is successfully queue
626        mLooper.dispatchAll();
627        WifiNative.ScanEventHandler eventHandler =
628                verifyStartSingleScan(order, computeSingleScanNativeSettings(requestSettings));
629        verifySuccessfulResponse(order, handler, requestId);
630        verify(mBatteryStats).noteWifiScanStartedFromSource(eq(workSource));
631
632        // but then fails to execute
633        eventHandler.onScanStatus(WifiNative.WIFI_SCAN_FAILED);
634        mLooper.dispatchAll();
635        verifyFailedResponse(order, handler, requestId,
636                WifiScanner.REASON_UNSPECIFIED, "Scan failed");
637        assertDumpContainsCallbackLog("singleScanFailed", requestId,
638                "reason=" + WifiScanner.REASON_UNSPECIFIED + ", Scan failed");
639        assertEquals(mWifiMetrics.getOneshotScanCount(), 1);
640        assertEquals(mWifiMetrics.getScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_UNKNOWN), 1);
641        verify(mBatteryStats).noteWifiScanStoppedFromSource(eq(workSource));
642    }
643
644    /**
645     * Send a single scan request and then disable Wi-Fi before it completes
646     */
647    @Test
648    public void sendSingleScanRequestThenDisableWifi() {
649        WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(2400), 0,
650                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
651        int requestId = 2293;
652
653        startServiceAndLoadDriver();
654
655        when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
656                        any(WifiNative.ScanEventHandler.class))).thenReturn(true);
657
658        Handler handler = mock(Handler.class);
659        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
660        InOrder order = inOrder(handler, mWifiScannerImpl);
661
662        // Run scan 1
663        sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
664        mLooper.dispatchAll();
665        verifySuccessfulResponse(order, handler, requestId);
666
667        // disable wifi
668        TestUtil.sendWifiScanAvailable(mBroadcastReceiver, mContext,
669                WifiManager.WIFI_STATE_DISABLED);
670
671        // validate failed response
672        mLooper.dispatchAll();
673        verifyFailedResponse(order, handler, requestId, WifiScanner.REASON_UNSPECIFIED,
674                "Scan was interrupted");
675        verifyNoMoreInteractions(handler);
676    }
677
678    /**
679     * Send a single scan request, schedule a second pending scan and disable Wi-Fi before the first
680     * scan completes.
681     */
682    @Test
683    public void sendSingleScanAndPendingScanAndListenerThenDisableWifi() {
684        WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2400), 0,
685                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
686        int requestId1 = 2293;
687
688        WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450), 0,
689                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
690        int requestId2 = 2294;
691
692        int listenerRequestId = 2295;
693
694        startServiceAndLoadDriver();
695
696        when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
697                        any(WifiNative.ScanEventHandler.class))).thenReturn(true);
698
699        Handler handler = mock(Handler.class);
700        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
701        InOrder order = inOrder(handler, mWifiScannerImpl);
702
703        // Request scan 1
704        sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null);
705        mLooper.dispatchAll();
706        verifySuccessfulResponse(order, handler, requestId1);
707
708        // Request scan 2
709        sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null);
710        mLooper.dispatchAll();
711        verifySuccessfulResponse(order, handler, requestId2);
712
713        // Setup scan listener
714        registerScanListener(controlChannel, listenerRequestId);
715        mLooper.dispatchAll();
716        verifySuccessfulResponse(order, handler, listenerRequestId);
717
718        // disable wifi
719        TestUtil.sendWifiScanAvailable(mBroadcastReceiver, mContext,
720                WifiManager.WIFI_STATE_DISABLED);
721
722        // validate failed response
723        mLooper.dispatchAll();
724        ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
725        order.verify(handler, times(2)).handleMessage(messageCaptor.capture());
726        assertFailedResponse(requestId1, WifiScanner.REASON_UNSPECIFIED,
727                "Scan was interrupted", messageCaptor.getAllValues().get(0));
728        assertFailedResponse(requestId2, WifiScanner.REASON_UNSPECIFIED,
729                "Scan was interrupted", messageCaptor.getAllValues().get(1));
730        // No additional callbacks for scan listener
731        verifyNoMoreInteractions(handler);
732    }
733
734    /**
735     * Send a single scan request and then a second one after the first completes.
736     */
737    @Test
738    public void sendSingleScanRequestAfterPreviousCompletes() {
739        WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2400), 0,
740                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
741        int requestId1 = 12;
742        ScanResults results1 = ScanResults.create(0, 2400);
743
744
745        WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0,
746                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
747        int requestId2 = 13;
748        ScanResults results2 = ScanResults.create(0, 2450);
749
750
751        startServiceAndLoadDriver();
752
753        when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
754                        any(WifiNative.ScanEventHandler.class))).thenReturn(true);
755
756        Handler handler = mock(Handler.class);
757        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
758        InOrder order = inOrder(handler, mWifiScannerImpl);
759
760        // Run scan 1
761        sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null);
762
763        mLooper.dispatchAll();
764        WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(order,
765                computeSingleScanNativeSettings(requestSettings1));
766        verifySuccessfulResponse(order, handler, requestId1);
767
768        // dispatch scan 1 results
769        when(mWifiScannerImpl.getLatestSingleScanResults())
770                .thenReturn(results1.getScanData());
771        eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
772
773        mLooper.dispatchAll();
774        verifyScanResultsRecieved(order, handler, requestId1, results1.getScanData());
775        verifySingleScanCompletedRecieved(order, handler, requestId1);
776
777        // Run scan 2
778        sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null);
779
780        mLooper.dispatchAll();
781        WifiNative.ScanEventHandler eventHandler2 = verifyStartSingleScan(order,
782                computeSingleScanNativeSettings(requestSettings2));
783        verifySuccessfulResponse(order, handler, requestId2);
784
785        // dispatch scan 2 results
786        when(mWifiScannerImpl.getLatestSingleScanResults())
787                .thenReturn(results2.getScanData());
788        eventHandler2.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
789
790        mLooper.dispatchAll();
791        verifyScanResultsRecieved(order, handler, requestId2, results2.getScanData());
792        verifySingleScanCompletedRecieved(order, handler, requestId2);
793    }
794
795    /**
796     * Send a single scan request and then a second one not satisfied by the first before the first
797     * completes. Verify that both are scheduled and succeed.
798     */
799    @Test
800    public void sendSingleScanRequestWhilePreviousScanRunning() {
801        WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2400), 0,
802                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
803        int requestId1 = 12;
804        ScanResults results1 = ScanResults.create(0, 2400);
805
806        WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0,
807                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
808        int requestId2 = 13;
809        ScanResults results2 = ScanResults.create(0, 2450);
810
811
812        startServiceAndLoadDriver();
813
814        when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
815                        any(WifiNative.ScanEventHandler.class))).thenReturn(true);
816
817        Handler handler = mock(Handler.class);
818        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
819        InOrder handlerOrder = inOrder(handler);
820        InOrder nativeOrder = inOrder(mWifiScannerImpl);
821
822        // Run scan 1
823        sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null);
824
825        mLooper.dispatchAll();
826        WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(nativeOrder,
827                computeSingleScanNativeSettings(requestSettings1));
828        verifySuccessfulResponse(handlerOrder, handler, requestId1);
829
830        // Queue scan 2 (will not run because previous is in progress)
831        sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null);
832        mLooper.dispatchAll();
833        verifySuccessfulResponse(handlerOrder, handler, requestId2);
834
835        // dispatch scan 1 results
836        when(mWifiScannerImpl.getLatestSingleScanResults())
837                .thenReturn(results1.getScanData());
838        eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
839
840        mLooper.dispatchAll();
841        verifyScanResultsRecieved(handlerOrder, handler, requestId1, results1.getScanData());
842        verifySingleScanCompletedRecieved(handlerOrder, handler, requestId1);
843
844        // now that the first scan completed we expect the second one to start
845        WifiNative.ScanEventHandler eventHandler2 = verifyStartSingleScan(nativeOrder,
846                computeSingleScanNativeSettings(requestSettings2));
847
848        // dispatch scan 2 results
849        when(mWifiScannerImpl.getLatestSingleScanResults())
850                .thenReturn(results2.getScanData());
851        eventHandler2.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
852
853        mLooper.dispatchAll();
854        verifyScanResultsRecieved(handlerOrder, handler, requestId2, results2.getScanData());
855        verifySingleScanCompletedRecieved(handlerOrder, handler, requestId2);
856        assertEquals(mWifiMetrics.getOneshotScanCount(), 2);
857        assertEquals(mWifiMetrics.getScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_SUCCESS), 2);
858    }
859
860
861    /**
862     * Send a single scan request and then two more before the first completes. Neither are
863     * satisfied by the first scan. Verify that the first completes and the second two are merged.
864     */
865    @Test
866    public void sendMultipleSingleScanRequestWhilePreviousScanRunning() throws RemoteException {
867        WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2400), 0,
868                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
869        int requestId1 = 12;
870        WorkSource workSource1 = new WorkSource(1121);
871        ScanResults results1 = ScanResults.create(0, 2400);
872
873        WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0,
874                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
875        int requestId2 = 13;
876        WorkSource workSource2 = new WorkSource(Binder.getCallingUid()); // don't explicitly set
877        ScanResults results2 = ScanResults.create(0, 2450, 5175, 2450);
878
879        WifiScanner.ScanSettings requestSettings3 = createRequest(channelsToSpec(5150), 0,
880                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
881        int requestId3 = 15;
882        WorkSource workSource3 = new WorkSource(2292);
883        ScanResults results3 = ScanResults.create(0, 5150, 5150, 5150, 5150);
884
885        WifiNative.ScanSettings nativeSettings2and3 = createSingleScanNativeSettingsForChannels(
886                WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, channelsToSpec(2450, 5175, 5150));
887        ScanResults results2and3 = ScanResults.merge(results2, results3);
888        WorkSource workSource2and3 = new WorkSource();
889        workSource2and3.add(workSource2);
890        workSource2and3.add(workSource3);
891
892
893        startServiceAndLoadDriver();
894
895        when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
896                        any(WifiNative.ScanEventHandler.class))).thenReturn(true);
897
898        Handler handler = mock(Handler.class);
899        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
900        InOrder handlerOrder = inOrder(handler);
901        InOrder nativeOrder = inOrder(mWifiScannerImpl);
902
903        // Run scan 1
904        sendSingleScanRequest(controlChannel, requestId1, requestSettings1, workSource1);
905
906        mLooper.dispatchAll();
907        WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(nativeOrder,
908                computeSingleScanNativeSettings(requestSettings1));
909        verifySuccessfulResponse(handlerOrder, handler, requestId1);
910        verify(mBatteryStats).noteWifiScanStartedFromSource(eq(workSource1));
911
912
913        // Queue scan 2 (will not run because previous is in progress)
914        // uses uid of calling process
915        sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null);
916        mLooper.dispatchAll();
917        verifySuccessfulResponse(handlerOrder, handler, requestId2);
918
919        // Queue scan 3 (will not run because previous is in progress)
920        sendSingleScanRequest(controlChannel, requestId3, requestSettings3, workSource3);
921        mLooper.dispatchAll();
922        verifySuccessfulResponse(handlerOrder, handler, requestId3);
923
924        // dispatch scan 1 results
925        when(mWifiScannerImpl.getLatestSingleScanResults())
926                .thenReturn(results1.getScanData());
927        eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
928
929        mLooper.dispatchAll();
930        verifyScanResultsRecieved(handlerOrder, handler, requestId1, results1.getScanData());
931        verifySingleScanCompletedRecieved(handlerOrder, handler, requestId1);
932        verify(mBatteryStats).noteWifiScanStoppedFromSource(eq(workSource1));
933        verify(mBatteryStats).noteWifiScanStartedFromSource(eq(workSource2and3));
934
935        // now that the first scan completed we expect the second and third ones to start
936        WifiNative.ScanEventHandler eventHandler2and3 = verifyStartSingleScan(nativeOrder,
937                nativeSettings2and3);
938
939        // dispatch scan 2 and 3 results
940        when(mWifiScannerImpl.getLatestSingleScanResults())
941                .thenReturn(results2and3.getScanData());
942        eventHandler2and3.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
943
944        mLooper.dispatchAll();
945
946        verifyMultipleSingleScanResults(handlerOrder, handler, requestId2, results2, requestId3,
947                results3);
948        assertEquals(mWifiMetrics.getOneshotScanCount(), 3);
949        assertEquals(mWifiMetrics.getScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_SUCCESS), 3);
950
951        verify(mBatteryStats).noteWifiScanStoppedFromSource(eq(workSource2and3));
952
953        assertDumpContainsRequestLog("addSingleScanRequest", requestId1);
954        assertDumpContainsRequestLog("addSingleScanRequest", requestId2);
955        assertDumpContainsRequestLog("addSingleScanRequest", requestId3);
956        assertDumpContainsCallbackLog("singleScanResults", requestId1,
957                "results=" + results1.getRawScanResults().length);
958        assertDumpContainsCallbackLog("singleScanResults", requestId2,
959                "results=" + results2.getRawScanResults().length);
960        assertDumpContainsCallbackLog("singleScanResults", requestId3,
961                "results=" + results3.getRawScanResults().length);
962    }
963
964
965    /**
966     * Send a single scan request and then a second one satisfied by the first before the first
967     * completes. Verify that only one scan is scheduled.
968     */
969    @Test
970    public void sendSingleScanRequestWhilePreviousScanRunningAndMergeIntoFirstScan() {
971        // Split by frequency to make it easier to determine which results each request is expecting
972        ScanResults results24GHz = ScanResults.create(0, 2400, 2400, 2400, 2450);
973        ScanResults results5GHz = ScanResults.create(0, 5150, 5150, 5175);
974        ScanResults resultsBoth = ScanResults.merge(results24GHz, results5GHz);
975
976        WifiScanner.ScanSettings requestSettings1 = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
977                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
978        int requestId1 = 12;
979        ScanResults results1 = resultsBoth;
980
981        WifiScanner.ScanSettings requestSettings2 = createRequest(WifiScanner.WIFI_BAND_24_GHZ, 0,
982                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
983        int requestId2 = 13;
984        ScanResults results2 = results24GHz;
985
986
987        startServiceAndLoadDriver();
988
989        when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
990                        any(WifiNative.ScanEventHandler.class))).thenReturn(true);
991
992        Handler handler = mock(Handler.class);
993        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
994        InOrder handlerOrder = inOrder(handler);
995        InOrder nativeOrder = inOrder(mWifiScannerImpl);
996
997        // Run scan 1
998        sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null);
999
1000        mLooper.dispatchAll();
1001        WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(nativeOrder,
1002                computeSingleScanNativeSettings(requestSettings1));
1003        verifySuccessfulResponse(handlerOrder, handler, requestId1);
1004
1005        // Queue scan 2 (will be folded into ongoing scan)
1006        sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null);
1007        mLooper.dispatchAll();
1008        verifySuccessfulResponse(handlerOrder, handler, requestId2);
1009
1010        // dispatch scan 1 results
1011        when(mWifiScannerImpl.getLatestSingleScanResults())
1012                .thenReturn(resultsBoth.getScanData());
1013        eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
1014
1015        mLooper.dispatchAll();
1016        verifyMultipleSingleScanResults(handlerOrder, handler, requestId1, results1, requestId2,
1017                results2);
1018
1019        assertEquals(mWifiMetrics.getOneshotScanCount(), 2);
1020        assertEquals(mWifiMetrics.getScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_SUCCESS), 2);
1021    }
1022
1023    /**
1024     * Send a single scan request and then two more before the first completes, one of which is
1025     * satisfied by the first scan. Verify that the first two complete together the second scan is
1026     * just for the other scan.
1027     */
1028    @Test
1029    public void sendMultipleSingleScanRequestWhilePreviousScanRunningAndMergeOneIntoFirstScan()
1030          throws RemoteException {
1031        // Split by frequency to make it easier to determine which results each request is expecting
1032        ScanResults results2400 = ScanResults.create(0, 2400, 2400, 2400);
1033        ScanResults results2450 = ScanResults.create(0, 2450);
1034        ScanResults results1and3 = ScanResults.merge(results2400, results2450);
1035
1036        WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2400, 2450), 0,
1037                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
1038        int requestId1 = 12;
1039        WorkSource workSource1 = new WorkSource(1121);
1040        ScanResults results1 = results1and3;
1041
1042        WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0,
1043                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
1044        int requestId2 = 13;
1045        WorkSource workSource2 = new WorkSource(Binder.getCallingUid()); // don't explicitly set
1046        ScanResults results2 = ScanResults.create(0, 2450, 5175, 2450);
1047
1048        WifiScanner.ScanSettings requestSettings3 = createRequest(channelsToSpec(2400), 0,
1049                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
1050        int requestId3 = 15;
1051        WorkSource workSource3 = new WorkSource(2292);
1052        ScanResults results3 = results2400;
1053
1054        startServiceAndLoadDriver();
1055
1056        when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
1057                        any(WifiNative.ScanEventHandler.class))).thenReturn(true);
1058
1059        Handler handler = mock(Handler.class);
1060        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
1061        InOrder handlerOrder = inOrder(handler);
1062        InOrder nativeOrder = inOrder(mWifiScannerImpl);
1063
1064        // Run scan 1
1065        sendSingleScanRequest(controlChannel, requestId1, requestSettings1, workSource1);
1066
1067        mLooper.dispatchAll();
1068        WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(nativeOrder,
1069                computeSingleScanNativeSettings(requestSettings1));
1070        verifySuccessfulResponse(handlerOrder, handler, requestId1);
1071        verify(mBatteryStats).noteWifiScanStartedFromSource(eq(workSource1));
1072
1073
1074        // Queue scan 2 (will not run because previous is in progress)
1075        // uses uid of calling process
1076        sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null);
1077        mLooper.dispatchAll();
1078        verifySuccessfulResponse(handlerOrder, handler, requestId2);
1079
1080        // Queue scan 3 (will be merged into the active scan)
1081        sendSingleScanRequest(controlChannel, requestId3, requestSettings3, workSource3);
1082        mLooper.dispatchAll();
1083        verifySuccessfulResponse(handlerOrder, handler, requestId3);
1084
1085        // dispatch scan 1 results
1086        when(mWifiScannerImpl.getLatestSingleScanResults())
1087                .thenReturn(results1and3.getScanData());
1088        eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
1089
1090        mLooper.dispatchAll();
1091        verifyMultipleSingleScanResults(handlerOrder, handler, requestId1, results1, requestId3,
1092                results3);
1093        // only the requests know at the beginning of the scan get blamed
1094        verify(mBatteryStats).noteWifiScanStoppedFromSource(eq(workSource1));
1095        verify(mBatteryStats).noteWifiScanStartedFromSource(eq(workSource2));
1096
1097        // now that the first scan completed we expect the second and third ones to start
1098        WifiNative.ScanEventHandler eventHandler2 = verifyStartSingleScan(nativeOrder,
1099                computeSingleScanNativeSettings(requestSettings2));
1100
1101        // dispatch scan 2 and 3 results
1102        when(mWifiScannerImpl.getLatestSingleScanResults())
1103                .thenReturn(results2.getScanData());
1104        eventHandler2.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
1105
1106        mLooper.dispatchAll();
1107
1108        verifyScanResultsRecieved(handlerOrder, handler, requestId2, results2.getScanData());
1109        verifySingleScanCompletedRecieved(handlerOrder, handler, requestId2);
1110        assertEquals(mWifiMetrics.getOneshotScanCount(), 3);
1111        assertEquals(mWifiMetrics.getScanReturnEntry(WifiMetricsProto.WifiLog.SCAN_SUCCESS), 3);
1112
1113        verify(mBatteryStats).noteWifiScanStoppedFromSource(eq(workSource2));
1114
1115        assertDumpContainsRequestLog("addSingleScanRequest", requestId1);
1116        assertDumpContainsRequestLog("addSingleScanRequest", requestId2);
1117        assertDumpContainsRequestLog("addSingleScanRequest", requestId3);
1118        assertDumpContainsCallbackLog("singleScanResults", requestId1,
1119                "results=" + results1.getRawScanResults().length);
1120        assertDumpContainsCallbackLog("singleScanResults", requestId2,
1121                "results=" + results2.getRawScanResults().length);
1122        assertDumpContainsCallbackLog("singleScanResults", requestId3,
1123                "results=" + results3.getRawScanResults().length);
1124    }
1125
1126    /**
1127     * Register a single scan listener and do a single scan
1128     */
1129    @Test
1130    public void registerScanListener() throws Exception {
1131        WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
1132                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
1133        WifiNative.ScanSettings nativeSettings = computeSingleScanNativeSettings(requestSettings);
1134        ScanResults results = ScanResults.create(0, 2400, 5150, 5175);
1135
1136        int requestId = 12;
1137        int listenerRequestId = 13;
1138
1139        startServiceAndLoadDriver();
1140
1141        Handler handler = mock(Handler.class);
1142        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
1143        InOrder order = inOrder(handler, mWifiScannerImpl);
1144
1145        when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
1146                        any(WifiNative.ScanEventHandler.class))).thenReturn(true);
1147
1148        registerScanListener(controlChannel, listenerRequestId);
1149        mLooper.dispatchAll();
1150        verifySuccessfulResponse(order, handler, listenerRequestId);
1151
1152        sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
1153
1154        mLooper.dispatchAll();
1155        WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(order, nativeSettings);
1156        verifySuccessfulResponse(order, handler, requestId);
1157
1158        when(mWifiScannerImpl.getLatestSingleScanResults())
1159                .thenReturn(results.getRawScanData());
1160        eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
1161
1162        mLooper.dispatchAll();
1163        verifyScanResultsRecieved(order, handler, requestId, results.getScanData());
1164        verifySingleScanCompletedRecieved(order, handler, requestId);
1165        verifyScanResultsRecieved(order, handler, listenerRequestId, results.getScanData());
1166        verifyNoMoreInteractions(handler);
1167
1168        assertDumpContainsRequestLog("registerScanListener", listenerRequestId);
1169        assertDumpContainsCallbackLog("singleScanResults", listenerRequestId,
1170                "results=" + results.getScanData().getResults().length);
1171    }
1172
1173    /**
1174     * Register a single scan listener and do a single scan
1175     */
1176    @Test
1177    public void deregisterScanListener() throws Exception {
1178        WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
1179                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
1180        WifiNative.ScanSettings nativeSettings = computeSingleScanNativeSettings(requestSettings);
1181        ScanResults results = ScanResults.create(0, 2400, 5150, 5175);
1182
1183        int requestId = 12;
1184        int listenerRequestId = 13;
1185
1186        startServiceAndLoadDriver();
1187
1188        Handler handler = mock(Handler.class);
1189        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
1190        InOrder order = inOrder(handler, mWifiScannerImpl);
1191
1192        when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
1193                        any(WifiNative.ScanEventHandler.class))).thenReturn(true);
1194
1195        registerScanListener(controlChannel, listenerRequestId);
1196        mLooper.dispatchAll();
1197        verifySuccessfulResponse(order, handler, listenerRequestId);
1198
1199        sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
1200
1201        mLooper.dispatchAll();
1202        WifiNative.ScanEventHandler eventHandler = verifyStartSingleScan(order, nativeSettings);
1203        verifySuccessfulResponse(order, handler, requestId);
1204
1205        deregisterScanListener(controlChannel, listenerRequestId);
1206        mLooper.dispatchAll();
1207
1208        when(mWifiScannerImpl.getLatestSingleScanResults())
1209                .thenReturn(results.getRawScanData());
1210        eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
1211
1212        mLooper.dispatchAll();
1213        verifyScanResultsRecieved(order, handler, requestId, results.getScanData());
1214        verifySingleScanCompletedRecieved(order, handler, requestId);
1215        verifyNoMoreInteractions(handler);
1216
1217        assertDumpContainsRequestLog("registerScanListener", listenerRequestId);
1218        assertDumpContainsRequestLog("deregisterScanListener", listenerRequestId);
1219    }
1220
1221    /**
1222     * Send a single scan request and then two more before the first completes. Neither are
1223     * satisfied by the first scan. Verify that the first completes and the second two are merged.
1224     */
1225    @Test
1226    public void scanListenerRecievesAllResults() throws RemoteException {
1227        WifiScanner.ScanSettings requestSettings1 = createRequest(channelsToSpec(2400), 0,
1228                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
1229        int requestId1 = 12;
1230        ScanResults results1 = ScanResults.create(0, 2400);
1231
1232        WifiScanner.ScanSettings requestSettings2 = createRequest(channelsToSpec(2450, 5175), 0,
1233                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
1234        int requestId2 = 13;
1235        ScanResults results2 = ScanResults.create(0, 2450, 5175, 2450);
1236
1237        WifiScanner.ScanSettings requestSettings3 = createRequest(channelsToSpec(5150), 0,
1238                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
1239        int requestId3 = 15;
1240        ScanResults results3 = ScanResults.create(0, 5150, 5150, 5150, 5150);
1241
1242        WifiNative.ScanSettings nativeSettings2and3 = createSingleScanNativeSettingsForChannels(
1243                WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, channelsToSpec(2450, 5175, 5150));
1244        ScanResults results2and3 = ScanResults.merge(results2, results3);
1245
1246        int listenerRequestId = 13;
1247
1248
1249        startServiceAndLoadDriver();
1250
1251        when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
1252                        any(WifiNative.ScanEventHandler.class))).thenReturn(true);
1253
1254        Handler handler = mock(Handler.class);
1255        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
1256        InOrder handlerOrder = inOrder(handler);
1257        InOrder nativeOrder = inOrder(mWifiScannerImpl);
1258
1259        // Run scan 1
1260        sendSingleScanRequest(controlChannel, requestId1, requestSettings1, null);
1261
1262        mLooper.dispatchAll();
1263        WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(nativeOrder,
1264                computeSingleScanNativeSettings(requestSettings1));
1265        verifySuccessfulResponse(handlerOrder, handler, requestId1);
1266
1267
1268        // Queue scan 2 (will not run because previous is in progress)
1269        sendSingleScanRequest(controlChannel, requestId2, requestSettings2, null);
1270        mLooper.dispatchAll();
1271        verifySuccessfulResponse(handlerOrder, handler, requestId2);
1272
1273        // Queue scan 3 (will not run because previous is in progress)
1274        sendSingleScanRequest(controlChannel, requestId3, requestSettings3, null);
1275        mLooper.dispatchAll();
1276        verifySuccessfulResponse(handlerOrder, handler, requestId3);
1277
1278        // Register scan listener
1279        registerScanListener(controlChannel, listenerRequestId);
1280        mLooper.dispatchAll();
1281        verifySuccessfulResponse(handlerOrder, handler, listenerRequestId);
1282
1283        // dispatch scan 1 results
1284        when(mWifiScannerImpl.getLatestSingleScanResults())
1285                .thenReturn(results1.getScanData());
1286        eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
1287
1288        mLooper.dispatchAll();
1289        verifyScanResultsRecieved(handlerOrder, handler, requestId1, results1.getScanData());
1290        verifySingleScanCompletedRecieved(handlerOrder, handler, requestId1);
1291        verifyScanResultsRecieved(handlerOrder, handler, listenerRequestId, results1.getScanData());
1292
1293        // now that the first scan completed we expect the second and third ones to start
1294        WifiNative.ScanEventHandler eventHandler2and3 = verifyStartSingleScan(nativeOrder,
1295                nativeSettings2and3);
1296
1297        // dispatch scan 2 and 3 results
1298        when(mWifiScannerImpl.getLatestSingleScanResults())
1299                .thenReturn(results2and3.getScanData());
1300        eventHandler2and3.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
1301
1302        mLooper.dispatchAll();
1303
1304        verifyMultipleSingleScanResults(handlerOrder, handler, requestId2, results2, requestId3,
1305                results3, listenerRequestId, results2and3);
1306
1307        assertDumpContainsRequestLog("registerScanListener", listenerRequestId);
1308        assertDumpContainsCallbackLog("singleScanResults", listenerRequestId,
1309                "results=" + results1.getRawScanResults().length);
1310        assertDumpContainsCallbackLog("singleScanResults", listenerRequestId,
1311                "results=" + results2and3.getRawScanResults().length);
1312    }
1313
1314
1315    private void doSuccessfulBackgroundScan(WifiScanner.ScanSettings requestSettings,
1316            WifiNative.ScanSettings nativeSettings) {
1317        startServiceAndLoadDriver();
1318
1319        Handler handler = mock(Handler.class);
1320        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
1321        InOrder order = inOrder(handler, mWifiScannerImpl);
1322
1323        when(mWifiScannerImpl.startBatchedScan(any(WifiNative.ScanSettings.class),
1324                        any(WifiNative.ScanEventHandler.class))).thenReturn(true);
1325
1326        sendBackgroundScanRequest(controlChannel, 12, requestSettings, null);
1327        mLooper.dispatchAll();
1328        verifyStartBackgroundScan(order, nativeSettings);
1329        verifySuccessfulResponse(order, handler, 12);
1330        verifyNoMoreInteractions(handler);
1331        assertDumpContainsRequestLog("addBackgroundScanRequest", 12);
1332    }
1333
1334    /**
1335     * Do a background scan for a band and verify that it is successful.
1336     */
1337    @Test
1338    public void sendBackgroundScanBandRequest() throws Exception {
1339        WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 30000,
1340                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
1341        WifiNative.ScanSettings nativeSettings = new NativeScanSettingsBuilder()
1342                .withBasePeriod(30000)
1343                .withMaxApPerScan(MAX_AP_PER_SCAN)
1344                .withMaxScansToCache(BackgroundScanScheduler.DEFAULT_MAX_SCANS_TO_BATCH)
1345                .addBucketWithBand(30000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
1346                        WifiScanner.WIFI_BAND_BOTH)
1347                .build();
1348        doSuccessfulBackgroundScan(requestSettings, nativeSettings);
1349        assertEquals(mWifiMetrics.getBackgroundScanCount(), 1);
1350    }
1351
1352    /**
1353     * Do a background scan for a list of channels and verify that it is successful.
1354     */
1355    @Test
1356    public void sendBackgroundScanChannelsRequest() throws Exception {
1357        WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(5150), 30000,
1358                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
1359        WifiNative.ScanSettings nativeSettings = new NativeScanSettingsBuilder()
1360                .withBasePeriod(30000)
1361                .withMaxApPerScan(MAX_AP_PER_SCAN)
1362                .withMaxScansToCache(BackgroundScanScheduler.DEFAULT_MAX_SCANS_TO_BATCH)
1363                .addBucketWithChannels(30000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, 5150)
1364                .build();
1365        doSuccessfulBackgroundScan(requestSettings, nativeSettings);
1366    }
1367
1368    private Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> createScanSettingsForHwPno()
1369            throws Exception {
1370        WifiScanner.ScanSettings requestSettings = createRequest(
1371                channelsToSpec(0, 2400, 5150, 5175), 30000, 0, 20,
1372                WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
1373        WifiNative.ScanSettings nativeSettings = new NativeScanSettingsBuilder()
1374                .withBasePeriod(30000)
1375                .withMaxApPerScan(MAX_AP_PER_SCAN)
1376                .withMaxScansToCache(BackgroundScanScheduler.DEFAULT_MAX_SCANS_TO_BATCH)
1377                .addBucketWithChannels(30000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
1378                        0, 2400, 5150, 5175)
1379                .build();
1380        return Pair.create(requestSettings, nativeSettings);
1381    }
1382
1383    private Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> createScanSettingsForSwPno()
1384            throws Exception {
1385        Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> settingsPair =
1386                createScanSettingsForHwPno();
1387
1388        WifiScanner.ScanSettings requestSettings = settingsPair.first;
1389        WifiNative.ScanSettings nativeSettings = settingsPair.second;
1390        // reportEvents field is overridden for SW PNO
1391        for (int i = 0; i < nativeSettings.buckets.length; i++) {
1392            nativeSettings.buckets[i].report_events = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
1393                    | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
1394        }
1395        return Pair.create(requestSettings, nativeSettings);
1396    }
1397
1398    private Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> createPnoSettings(
1399            ScanResults results)
1400            throws Exception {
1401        WifiScanner.PnoSettings requestPnoSettings = new WifiScanner.PnoSettings();
1402        requestPnoSettings.networkList =
1403                new WifiScanner.PnoSettings.PnoNetwork[results.getRawScanResults().length];
1404        int i = 0;
1405        for (ScanResult scanResult : results.getRawScanResults()) {
1406            requestPnoSettings.networkList[i++] =
1407                    new WifiScanner.PnoSettings.PnoNetwork(scanResult.SSID);
1408        }
1409
1410        WifiNative.PnoSettings nativePnoSettings = new WifiNative.PnoSettings();
1411        nativePnoSettings.min5GHzRssi = requestPnoSettings.min5GHzRssi;
1412        nativePnoSettings.min24GHzRssi = requestPnoSettings.min24GHzRssi;
1413        nativePnoSettings.initialScoreMax = requestPnoSettings.initialScoreMax;
1414        nativePnoSettings.currentConnectionBonus = requestPnoSettings.currentConnectionBonus;
1415        nativePnoSettings.sameNetworkBonus = requestPnoSettings.sameNetworkBonus;
1416        nativePnoSettings.secureBonus = requestPnoSettings.secureBonus;
1417        nativePnoSettings.band5GHzBonus = requestPnoSettings.band5GHzBonus;
1418        nativePnoSettings.isConnected = requestPnoSettings.isConnected;
1419        nativePnoSettings.networkList =
1420                new WifiNative.PnoNetwork[requestPnoSettings.networkList.length];
1421        for (i = 0; i < requestPnoSettings.networkList.length; i++) {
1422            nativePnoSettings.networkList[i] = new WifiNative.PnoNetwork();
1423            nativePnoSettings.networkList[i].ssid = requestPnoSettings.networkList[i].ssid;
1424            nativePnoSettings.networkList[i].networkId =
1425                    requestPnoSettings.networkList[i].networkId;
1426            nativePnoSettings.networkList[i].priority = requestPnoSettings.networkList[i].priority;
1427            nativePnoSettings.networkList[i].flags = requestPnoSettings.networkList[i].flags;
1428            nativePnoSettings.networkList[i].auth_bit_field =
1429                    requestPnoSettings.networkList[i].authBitField;
1430        }
1431        return Pair.create(requestPnoSettings, nativePnoSettings);
1432    }
1433
1434    private ScanResults createScanResultsForPno() {
1435        return ScanResults.create(0, 2400, 5150, 5175);
1436    }
1437
1438    private ScanResults createScanResultsForPnoWithNoIE() {
1439        return ScanResults.createWithNoIE(0, 2400, 5150, 5175);
1440    }
1441
1442    private WifiNative.PnoEventHandler verifyHwPno(InOrder order,
1443            WifiNative.PnoSettings expected) {
1444        ArgumentCaptor<WifiNative.PnoSettings> pnoSettingsCaptor =
1445                ArgumentCaptor.forClass(WifiNative.PnoSettings.class);
1446        ArgumentCaptor<WifiNative.PnoEventHandler> pnoEventHandlerCaptor =
1447                ArgumentCaptor.forClass(WifiNative.PnoEventHandler.class);
1448        order.verify(mWifiScannerImpl).setHwPnoList(pnoSettingsCaptor.capture(),
1449                pnoEventHandlerCaptor.capture());
1450        assertNativePnoSettingsEquals(expected, pnoSettingsCaptor.getValue());
1451        return pnoEventHandlerCaptor.getValue();
1452    }
1453
1454    private void sendPnoScanRequest(BidirectionalAsyncChannel controlChannel,
1455            int scanRequestId, WifiScanner.ScanSettings scanSettings,
1456            WifiScanner.PnoSettings pnoSettings) {
1457        Bundle pnoParams = new Bundle();
1458        scanSettings.isPnoScan = true;
1459        pnoParams.putParcelable(WifiScanner.PNO_PARAMS_SCAN_SETTINGS_KEY, scanSettings);
1460        pnoParams.putParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY, pnoSettings);
1461        controlChannel.sendMessage(Message.obtain(null, WifiScanner.CMD_START_PNO_SCAN, 0,
1462                scanRequestId, pnoParams));
1463    }
1464
1465    private void assertPnoNetworkFoundMessage(int listenerId, ScanResult[] expected,
1466            Message networkFoundMessage) {
1467        assertEquals("what", WifiScanner.CMD_PNO_NETWORK_FOUND, networkFoundMessage.what);
1468        assertEquals("listenerId", listenerId, networkFoundMessage.arg2);
1469        assertScanResultsEquals(expected,
1470                ((WifiScanner.ParcelableScanResults) networkFoundMessage.obj).getResults());
1471    }
1472
1473    private void verifyPnoNetworkFoundRecieved(InOrder order, Handler handler, int listenerId,
1474            ScanResult[] expected) {
1475        Message scanResultMessage = verifyHandleMessageAndGetMessage(order, handler,
1476                WifiScanner.CMD_PNO_NETWORK_FOUND);
1477        assertPnoNetworkFoundMessage(listenerId, expected, scanResultMessage);
1478    }
1479
1480    private void expectSuccessfulBackgroundScan(InOrder order,
1481            WifiNative.ScanSettings nativeSettings, ScanResults results) {
1482        when(mWifiScannerImpl.startBatchedScan(any(WifiNative.ScanSettings.class),
1483                any(WifiNative.ScanEventHandler.class))).thenReturn(true);
1484        mLooper.dispatchAll();
1485        WifiNative.ScanEventHandler eventHandler = verifyStartBackgroundScan(order, nativeSettings);
1486        WifiScanner.ScanData[] scanDatas = new WifiScanner.ScanData[1];
1487        scanDatas[0] = results.getScanData();
1488        for (ScanResult fullScanResult : results.getRawScanResults()) {
1489            eventHandler.onFullScanResult(fullScanResult, 0);
1490        }
1491        when(mWifiScannerImpl.getLatestBatchedScanResults(anyBoolean())).thenReturn(scanDatas);
1492        eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
1493        mLooper.dispatchAll();
1494    }
1495
1496    private void expectHwPnoScanWithNoBackgroundScan(InOrder order, Handler handler, int requestId,
1497            WifiNative.PnoSettings nativeSettings, ScanResults results) {
1498        when(mWifiScannerImpl.isHwPnoSupported(anyBoolean())).thenReturn(true);
1499        when(mWifiScannerImpl.shouldScheduleBackgroundScanForHwPno()).thenReturn(false);
1500
1501        when(mWifiScannerImpl.setHwPnoList(any(WifiNative.PnoSettings.class),
1502                any(WifiNative.PnoEventHandler.class))).thenReturn(true);
1503        mLooper.dispatchAll();
1504        WifiNative.PnoEventHandler eventHandler = verifyHwPno(order, nativeSettings);
1505        verifySuccessfulResponse(order, handler, requestId);
1506        eventHandler.onPnoNetworkFound(results.getRawScanResults());
1507        mLooper.dispatchAll();
1508    }
1509
1510    private void expectHwPnoScanWithBackgroundScan(InOrder order, Handler handler, int requestId,
1511            WifiNative.ScanSettings nativeScanSettings,
1512            WifiNative.PnoSettings nativePnoSettings, ScanResults results) {
1513        when(mWifiScannerImpl.isHwPnoSupported(anyBoolean())).thenReturn(true);
1514        when(mWifiScannerImpl.shouldScheduleBackgroundScanForHwPno()).thenReturn(true);
1515
1516        when(mWifiScannerImpl.setHwPnoList(any(WifiNative.PnoSettings.class),
1517                any(WifiNative.PnoEventHandler.class))).thenReturn(true);
1518        when(mWifiScannerImpl.startBatchedScan(any(WifiNative.ScanSettings.class),
1519                any(WifiNative.ScanEventHandler.class))).thenReturn(true);
1520        mLooper.dispatchAll();
1521        WifiNative.PnoEventHandler eventHandler = verifyHwPno(order, nativePnoSettings);
1522        verifySuccessfulResponse(order, handler, requestId);
1523        verifyStartBackgroundScan(order, nativeScanSettings);
1524        eventHandler.onPnoNetworkFound(results.getRawScanResults());
1525        mLooper.dispatchAll();
1526    }
1527
1528    private void expectHwPnoScanWithBackgroundScanWithNoIE(InOrder order, Handler handler,
1529            int requestId, WifiNative.ScanSettings nativeBackgroundScanSettings,
1530            WifiNative.ScanSettings nativeSingleScanSettings,
1531            WifiNative.PnoSettings nativePnoSettings, ScanResults results) {
1532        when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
1533                any(WifiNative.ScanEventHandler.class))).thenReturn(true);
1534
1535        expectHwPnoScanWithBackgroundScan(order, handler, requestId, nativeBackgroundScanSettings,
1536                nativePnoSettings, results);
1537        WifiNative.ScanEventHandler eventHandler =
1538                verifyStartSingleScan(order, nativeSingleScanSettings);
1539        when(mWifiScannerImpl.getLatestSingleScanResults()).thenReturn(results.getScanData());
1540        eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
1541        mLooper.dispatchAll();
1542    }
1543    private void expectSwPnoScan(InOrder order, WifiNative.ScanSettings nativeScanSettings,
1544            ScanResults results) {
1545        when(mWifiScannerImpl.isHwPnoSupported(anyBoolean())).thenReturn(false);
1546        when(mWifiScannerImpl.shouldScheduleBackgroundScanForHwPno()).thenReturn(true);
1547
1548        expectSuccessfulBackgroundScan(order, nativeScanSettings, results);
1549    }
1550
1551    /**
1552     * Tests Supplicant PNO scan when the PNO scan results contain IE info. This ensures that the
1553     * PNO scan results are plumbed back to the client as a PNO network found event.
1554     */
1555    @Test
1556    public void testSuccessfulHwPnoScanWithNoBackgroundScan() throws Exception {
1557        startServiceAndLoadDriver();
1558        Handler handler = mock(Handler.class);
1559        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
1560        InOrder order = inOrder(handler, mWifiScannerImpl);
1561        int requestId = 12;
1562
1563        ScanResults scanResults = createScanResultsForPno();
1564        Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings =
1565                createScanSettingsForHwPno();
1566        Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings =
1567                createPnoSettings(scanResults);
1568
1569        sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first);
1570        expectHwPnoScanWithNoBackgroundScan(order, handler, requestId, pnoSettings.second,
1571                scanResults);
1572        verifyPnoNetworkFoundRecieved(order, handler, requestId, scanResults.getRawScanResults());
1573    }
1574
1575    /**
1576     * Tests Hal ePNO scan when the PNO scan results contain IE info. This ensures that the
1577     * PNO scan results are plumbed back to the client as a PNO network found event.
1578     */
1579    @Test
1580    public void testSuccessfulHwPnoScanWithBackgroundScan() throws Exception {
1581        startServiceAndLoadDriver();
1582        Handler handler = mock(Handler.class);
1583        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
1584        InOrder order = inOrder(handler, mWifiScannerImpl);
1585        int requestId = 12;
1586
1587        ScanResults scanResults = createScanResultsForPno();
1588        Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings =
1589                createScanSettingsForHwPno();
1590        Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings =
1591                createPnoSettings(scanResults);
1592
1593        sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first);
1594        expectHwPnoScanWithBackgroundScan(order, handler, requestId, scanSettings.second,
1595                pnoSettings.second, scanResults);
1596        verifyPnoNetworkFoundRecieved(order, handler, requestId, scanResults.getRawScanResults());
1597    }
1598
1599    /**
1600     * Tests Hal ePNO scan when the PNO scan results don't contain IE info. This ensures that the
1601     * single scan results are plumbed back to the client as a PNO network found event.
1602     */
1603    @Test
1604    public void testSuccessfulHwPnoScanWithBackgroundScanWithNoIE() throws Exception {
1605        startServiceAndLoadDriver();
1606        Handler handler = mock(Handler.class);
1607        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
1608        InOrder order = inOrder(handler, mWifiScannerImpl);
1609        int requestId = 12;
1610
1611        ScanResults scanResults = createScanResultsForPnoWithNoIE();
1612        Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings =
1613                createScanSettingsForHwPno();
1614        Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings =
1615                createPnoSettings(scanResults);
1616
1617        sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first);
1618        expectHwPnoScanWithBackgroundScanWithNoIE(order, handler, requestId, scanSettings.second,
1619                computeSingleScanNativeSettings(scanSettings.first), pnoSettings.second,
1620                scanResults);
1621
1622        ArrayList<ScanResult> sortScanList =
1623                new ArrayList<ScanResult>(Arrays.asList(scanResults.getRawScanResults()));
1624        Collections.sort(sortScanList, WifiScannerImpl.SCAN_RESULT_SORT_COMPARATOR);
1625        verifyPnoNetworkFoundRecieved(order, handler, requestId,
1626                sortScanList.toArray(new ScanResult[sortScanList.size()]));
1627    }
1628
1629    /**
1630     * Tests SW PNO scan. This ensures that the background scan results are plumbed back to the
1631     * client as a PNO network found event.
1632     */
1633    @Test
1634    public void testSuccessfulSwPnoScan() throws Exception {
1635        startServiceAndLoadDriver();
1636        Handler handler = mock(Handler.class);
1637        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
1638        InOrder order = inOrder(handler, mWifiScannerImpl);
1639        int requestId = 12;
1640
1641        ScanResults scanResults = createScanResultsForPno();
1642        Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings =
1643                createScanSettingsForSwPno();
1644        Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings =
1645                createPnoSettings(scanResults);
1646
1647        sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first);
1648        expectSwPnoScan(order, scanSettings.second, scanResults);
1649        verifyPnoNetworkFoundRecieved(order, handler, requestId, scanResults.getRawScanResults());
1650    }
1651
1652    /**
1653     * Tries to simulate the race scenario where a client is disconnected immediately after single
1654     * scan request is sent to |SingleScanStateMachine|.
1655     */
1656    @Test
1657    public void processSingleScanRequestAfterDisconnect() throws Exception {
1658        startServiceAndLoadDriver();
1659        BidirectionalAsyncChannel controlChannel = connectChannel(mock(Handler.class));
1660        mLooper.dispatchAll();
1661
1662        // Send the single scan request and then send the disconnect immediately after.
1663        WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
1664                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
1665        int requestId = 10;
1666
1667        sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
1668        // Can't call |disconnect| here because that sends |CMD_CHANNEL_DISCONNECT| followed by
1669        // |CMD_CHANNEL_DISCONNECTED|.
1670        controlChannel.sendMessage(Message.obtain(null, AsyncChannel.CMD_CHANNEL_DISCONNECTED,
1671                        AsyncChannel.STATUS_REMOTE_DISCONNECTION, 0, null));
1672
1673        // Now process the above 2 actions. This should result in first processing the single scan
1674        // request (which forwards the request to SingleScanStateMachine) and then processing the
1675        // disconnect after.
1676        mLooper.dispatchAll();
1677
1678        // Now check that we logged the invalid request.
1679        String serviceDump = dumpService();
1680        Pattern logLineRegex = Pattern.compile("^.+" + "singleScanInvalidRequest: "
1681                + "ClientInfo\\[unknown\\],Id=" + requestId + ",bad request$", Pattern.MULTILINE);
1682        assertTrue("dump did not contain log with ClientInfo[unknown]: " + serviceDump + "\n",
1683                logLineRegex.matcher(serviceDump).find());
1684    }
1685
1686    /**
1687     * Tries to simulate the race scenario where a client is disconnected immediately after single
1688     * scan request is sent to |SingleScanStateMachine|.
1689     */
1690    @Test
1691    public void sendScanRequestAfterUnsuccessfulSend() throws Exception {
1692        WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
1693                0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
1694        int requestId = 9;
1695
1696        startServiceAndLoadDriver();
1697        Handler handler = mock(Handler.class);
1698        BidirectionalAsyncChannel controlChannel = connectChannel(handler);
1699        mLooper.dispatchAll();
1700
1701        when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
1702                        any(WifiNative.ScanEventHandler.class))).thenReturn(true);
1703        ScanResults results = ScanResults.create(0, 2400);
1704        when(mWifiScannerImpl.getLatestSingleScanResults())
1705                .thenReturn(results.getRawScanData());
1706
1707        InOrder order = inOrder(mWifiScannerImpl, handler);
1708
1709        sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
1710        mLooper.dispatchAll();
1711        WifiNative.ScanEventHandler eventHandler1 = verifyStartSingleScan(order,
1712                computeSingleScanNativeSettings(requestSettings));
1713        verifySuccessfulResponse(order, handler, requestId);
1714
1715        eventHandler1.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
1716        mLooper.dispatchAll();
1717        verifyScanResultsRecieved(order, handler, requestId, results.getScanData());
1718        verifySingleScanCompletedRecieved(order, handler, requestId);
1719        verifyNoMoreInteractions(handler);
1720
1721        controlChannel.sendMessage(Message.obtain(null, AsyncChannel.CMD_CHANNEL_DISCONNECTED,
1722                        AsyncChannel.STATUS_SEND_UNSUCCESSFUL, 0, null));
1723        mLooper.dispatchAll();
1724
1725        sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
1726        mLooper.dispatchAll();
1727        WifiNative.ScanEventHandler eventHandler2 = verifyStartSingleScan(order,
1728                computeSingleScanNativeSettings(requestSettings));
1729        verifySuccessfulResponse(order, handler, requestId);
1730
1731        eventHandler2.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
1732        mLooper.dispatchAll();
1733        verifyScanResultsRecieved(order, handler, requestId, results.getScanData());
1734        verifySingleScanCompletedRecieved(order, handler, requestId);
1735        verifyNoMoreInteractions(handler);
1736    }
1737}
1738