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 
17 package android.net.wifi;
18 
19 import static org.junit.Assert.assertArrayEquals;
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertNotNull;
23 import static org.junit.Assert.assertNull;
24 import static org.junit.Assert.assertTrue;
25 import static org.mockito.ArgumentMatchers.eq;
26 import static org.mockito.Mockito.mock;
27 import static org.mockito.Mockito.spy;
28 import static org.mockito.Mockito.times;
29 import static org.mockito.Mockito.validateMockitoUsage;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.when;
32 
33 import android.content.Context;
34 import android.net.wifi.WifiScanner.PnoSettings;
35 import android.net.wifi.WifiScanner.PnoSettings.PnoNetwork;
36 import android.net.wifi.WifiScanner.ScanData;
37 import android.net.wifi.WifiScanner.ScanSettings;
38 import android.os.Bundle;
39 import android.os.Handler;
40 import android.os.Message;
41 import android.os.Messenger;
42 import android.os.Parcel;
43 import android.os.test.TestLooper;
44 
45 import androidx.test.filters.SmallTest;
46 
47 import com.android.internal.util.test.BidirectionalAsyncChannelServer;
48 
49 import org.junit.After;
50 import org.junit.Before;
51 import org.junit.Test;
52 import org.mockito.ArgumentCaptor;
53 import org.mockito.Mock;
54 import org.mockito.MockitoAnnotations;
55 
56 import java.util.Arrays;
57 
58 /**
59  * Unit tests for {@link android.net.wifi.WifiScanner}.
60  */
61 @SmallTest
62 public class WifiScannerTest {
63     @Mock
64     private Context mContext;
65     @Mock
66     private IWifiScanner mService;
67 
68     private static final boolean TEST_PNOSETTINGS_IS_CONNECTED = false;
69     private static final int TEST_PNOSETTINGS_MIN_5GHZ_RSSI = -60;
70     private static final int TEST_PNOSETTINGS_MIN_2GHZ_RSSI = -70;
71     private static final int TEST_PNOSETTINGS_INITIAL_SCORE_MAX = 50;
72     private static final int TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS = 10;
73     private static final int TEST_PNOSETTINGS_SAME_NETWORK_BONUS = 11;
74     private static final int TEST_PNOSETTINGS_SECURE_BONUS = 12;
75     private static final int TEST_PNOSETTINGS_BAND_5GHZ_BONUS = 13;
76     private static final String TEST_SSID_1 = "TEST1";
77     private static final String TEST_SSID_2 = "TEST2";
78     private static final int[] TEST_FREQUENCIES_1 = {};
79     private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
80 
81     private WifiScanner mWifiScanner;
82     private TestLooper mLooper;
83     private Handler mHandler;
84     private BidirectionalAsyncChannelServer mBidirectionalAsyncChannelServer;
85 
86     /**
87      * Setup before tests.
88      */
89     @Before
setUp()90     public void setUp() throws Exception {
91         MockitoAnnotations.initMocks(this);
92         mLooper = new TestLooper();
93         mHandler = spy(new Handler(mLooper.getLooper()));
94         mBidirectionalAsyncChannelServer = new BidirectionalAsyncChannelServer(
95                 mContext, mLooper.getLooper(), mHandler);
96         when(mService.getMessenger()).thenReturn(mBidirectionalAsyncChannelServer.getMessenger());
97         mWifiScanner = new WifiScanner(mContext, mService, mLooper.getLooper());
98         mLooper.dispatchAll();
99     }
100 
101     /**
102      * Clean up after tests.
103      */
104     @After
cleanup()105     public void cleanup() {
106         validateMockitoUsage();
107     }
108 
109     /**
110      * Verify parcel read/write for ScanSettings.
111      */
112     @Test
verifyScanSettingsParcelWithBand()113     public void verifyScanSettingsParcelWithBand() throws Exception {
114         ScanSettings writeSettings = new ScanSettings();
115         writeSettings.type = WifiScanner.TYPE_LOW_POWER;
116         writeSettings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
117 
118         ScanSettings readSettings = parcelWriteRead(writeSettings);
119         assertEquals(readSettings.type, writeSettings.type);
120         assertEquals(readSettings.band, writeSettings.band);
121         assertEquals(0, readSettings.channels.length);
122     }
123 
124     /**
125      * Verify parcel read/write for ScanSettings.
126      */
127     @Test
verifyScanSettingsParcelWithChannels()128     public void verifyScanSettingsParcelWithChannels() throws Exception {
129         ScanSettings writeSettings = new ScanSettings();
130         writeSettings.type = WifiScanner.TYPE_HIGH_ACCURACY;
131         writeSettings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
132         writeSettings.channels = new WifiScanner.ChannelSpec[] {
133                 new WifiScanner.ChannelSpec(5),
134                 new WifiScanner.ChannelSpec(7)
135         };
136 
137         ScanSettings readSettings = parcelWriteRead(writeSettings);
138         assertEquals(writeSettings.type, readSettings.type);
139         assertEquals(writeSettings.band, readSettings.band);
140         assertEquals(2, readSettings.channels.length);
141         assertEquals(5, readSettings.channels[0].frequency);
142         assertEquals(7, readSettings.channels[1].frequency);
143     }
144 
145     /**
146      * Write the provided {@link ScanSettings} to a parcel and deserialize it.
147      */
parcelWriteRead(ScanSettings writeSettings)148     private static ScanSettings parcelWriteRead(ScanSettings writeSettings) throws Exception {
149         Parcel parcel = Parcel.obtain();
150         writeSettings.writeToParcel(parcel, 0);
151         parcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
152         return ScanSettings.CREATOR.createFromParcel(parcel);
153     }
154 
155     /**
156      *  PnoSettings object can be serialized and deserialized, while keeping the
157      *  values unchanged.
158      */
159     @Test
canSerializeAndDeserializePnoSettings()160     public void canSerializeAndDeserializePnoSettings() throws Exception {
161 
162         PnoSettings pnoSettings = new PnoSettings();
163 
164         PnoNetwork pnoNetwork1 = new PnoNetwork(TEST_SSID_1);
165         PnoNetwork pnoNetwork2 = new PnoNetwork(TEST_SSID_2);
166         pnoNetwork1.frequencies = TEST_FREQUENCIES_1;
167         pnoNetwork2.frequencies = TEST_FREQUENCIES_2;
168 
169         pnoSettings.networkList = new PnoNetwork[]{pnoNetwork1, pnoNetwork2};
170         pnoSettings.isConnected = TEST_PNOSETTINGS_IS_CONNECTED;
171         pnoSettings.min5GHzRssi = TEST_PNOSETTINGS_MIN_5GHZ_RSSI;
172         pnoSettings.min24GHzRssi = TEST_PNOSETTINGS_MIN_2GHZ_RSSI;
173         pnoSettings.initialScoreMax = TEST_PNOSETTINGS_INITIAL_SCORE_MAX;
174         pnoSettings.currentConnectionBonus = TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS;
175         pnoSettings.sameNetworkBonus = TEST_PNOSETTINGS_SAME_NETWORK_BONUS;
176         pnoSettings.secureBonus = TEST_PNOSETTINGS_SECURE_BONUS;
177         pnoSettings.band5GHzBonus = TEST_PNOSETTINGS_BAND_5GHZ_BONUS;
178 
179         Parcel parcel = Parcel.obtain();
180         pnoSettings.writeToParcel(parcel, 0);
181         // Rewind the pointer to the head of the parcel.
182         parcel.setDataPosition(0);
183         PnoSettings pnoSettingsDeserialized =
184                 pnoSettings.CREATOR.createFromParcel(parcel);
185 
186         assertNotNull(pnoSettingsDeserialized);
187         assertEquals(TEST_PNOSETTINGS_IS_CONNECTED, pnoSettingsDeserialized.isConnected);
188         assertEquals(TEST_PNOSETTINGS_MIN_5GHZ_RSSI, pnoSettingsDeserialized.min5GHzRssi);
189         assertEquals(TEST_PNOSETTINGS_MIN_2GHZ_RSSI, pnoSettingsDeserialized.min24GHzRssi);
190         assertEquals(TEST_PNOSETTINGS_INITIAL_SCORE_MAX, pnoSettingsDeserialized.initialScoreMax);
191         assertEquals(TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS,
192                 pnoSettingsDeserialized.currentConnectionBonus);
193         assertEquals(TEST_PNOSETTINGS_SAME_NETWORK_BONUS,
194                 pnoSettingsDeserialized.sameNetworkBonus);
195         assertEquals(TEST_PNOSETTINGS_SECURE_BONUS, pnoSettingsDeserialized.secureBonus);
196         assertEquals(TEST_PNOSETTINGS_BAND_5GHZ_BONUS, pnoSettingsDeserialized.band5GHzBonus);
197 
198         // Test parsing of PnoNetwork
199         assertEquals(pnoSettings.networkList.length, pnoSettingsDeserialized.networkList.length);
200         for (int i = 0; i < pnoSettings.networkList.length; i++) {
201             PnoNetwork expected = pnoSettings.networkList[i];
202             PnoNetwork actual = pnoSettingsDeserialized.networkList[i];
203             assertEquals(expected.ssid, actual.ssid);
204             assertEquals(expected.flags, actual.flags);
205             assertEquals(expected.authBitField, actual.authBitField);
206             assertTrue(Arrays.equals(expected.frequencies, actual.frequencies));
207         }
208     }
209 
210     /**
211      *  Make sure that frequencies is not null by default.
212      */
213     @Test
pnoNetworkFrequencyIsNotNull()214     public void pnoNetworkFrequencyIsNotNull() throws Exception {
215         PnoNetwork pnoNetwork = new PnoNetwork(TEST_SSID_1);
216         assertNotNull(pnoNetwork.frequencies);
217     }
218 
219     /**
220      * Verify parcel read/write for ScanData.
221      */
222     @Test
verifyScanDataParcel()223     public void verifyScanDataParcel() throws Exception {
224         ScanData writeScanData = new ScanData(2, 0, 3,
225                 WifiScanner.WIFI_BAND_BOTH_WITH_DFS, new ScanResult[0]);
226 
227         ScanData readScanData = parcelWriteRead(writeScanData);
228         assertEquals(writeScanData.getId(), readScanData.getId());
229         assertEquals(writeScanData.getFlags(), readScanData.getFlags());
230         assertEquals(writeScanData.getBucketsScanned(), readScanData.getBucketsScanned());
231         assertEquals(writeScanData.getBandScanned(), readScanData.getBandScanned());
232         assertArrayEquals(writeScanData.getResults(), readScanData.getResults());
233     }
234 
235     /**
236      * Write the provided {@link ScanData} to a parcel and deserialize it.
237      */
parcelWriteRead(ScanData writeScanData)238     private static ScanData parcelWriteRead(ScanData writeScanData) throws Exception {
239         Parcel parcel = Parcel.obtain();
240         writeScanData.writeToParcel(parcel, 0);
241         parcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
242         return ScanData.CREATOR.createFromParcel(parcel);
243     }
244 
245 
246     /**
247      * Test behavior of {@link WifiScanner#startScan(ScanSettings, WifiScanner.ScanListener)}
248      * @throws Exception
249      */
250     @Test
testStartScan()251     public void testStartScan() throws Exception {
252         ScanSettings scanSettings = new ScanSettings();
253         WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
254 
255         mWifiScanner.startScan(scanSettings, scanListener);
256         mLooper.dispatchAll();
257 
258         ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
259         verify(mHandler).handleMessage(messageArgumentCaptor.capture());
260         Message message = messageArgumentCaptor.getValue();
261         assertNotNull(message);
262 
263         assertEquals(WifiScanner.CMD_START_SINGLE_SCAN, message.what);
264         assertTrue(message.obj instanceof Bundle);
265         Bundle messageBundle = (Bundle) message.obj;
266         assertEquals(scanSettings,
267                 messageBundle.getParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY));
268         assertNull(messageBundle.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY));
269         assertEquals(mContext.getOpPackageName(),
270                 messageBundle.getParcelable(WifiScanner.REQUEST_PACKAGE_NAME_KEY));
271 
272     }
273 
274     /**
275      * Test behavior of {@link WifiScanner#stopScan(WifiScanner.ScanListener)}
276      * @throws Exception
277      */
278     @Test
testStopScan()279     public void testStopScan() throws Exception {
280         ScanSettings scanSettings = new ScanSettings();
281         WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
282 
283         mWifiScanner.startScan(scanSettings, scanListener);
284         mLooper.dispatchAll();
285 
286         mWifiScanner.stopScan(scanListener);
287         mLooper.dispatchAll();
288 
289         ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
290         verify(mHandler, times(2)).handleMessage(messageArgumentCaptor.capture());
291         Message message = messageArgumentCaptor.getValue();
292         assertNotNull(message);
293 
294         assertEquals(WifiScanner.CMD_STOP_SINGLE_SCAN, message.what);
295         assertTrue(message.obj instanceof Bundle);
296         Bundle messageBundle = (Bundle) message.obj;
297         assertEquals(mContext.getOpPackageName(),
298                 messageBundle.getParcelable(WifiScanner.REQUEST_PACKAGE_NAME_KEY));
299 
300     }
301 
302     /**
303      * Test behavior of {@link WifiScanner#startScan(ScanSettings, WifiScanner.ScanListener)}
304      * @throws Exception
305      */
306     @Test
testStartScanListenerOnSuccess()307     public void testStartScanListenerOnSuccess() throws Exception {
308         ScanSettings scanSettings = new ScanSettings();
309         WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
310 
311         mWifiScanner.startScan(scanSettings, scanListener);
312         mLooper.dispatchAll();
313 
314         ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
315         verify(mHandler).handleMessage(messageArgumentCaptor.capture());
316         Message sentMessage = messageArgumentCaptor.getValue();
317         assertNotNull(sentMessage);
318 
319         assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
320         Messenger scannerMessenger =
321                 mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
322 
323         Message responseMessage = Message.obtain();
324         responseMessage.what = WifiScanner.CMD_OP_SUCCEEDED;
325         responseMessage.arg2 = sentMessage.arg2;
326         scannerMessenger.send(responseMessage);
327         mLooper.dispatchAll();
328 
329         verify(scanListener).onSuccess();
330     }
331 
332     /**
333      * Test behavior of {@link WifiScanner#startScan(ScanSettings, WifiScanner.ScanListener)}
334      * @throws Exception
335      */
336     @Test
testStartScanListenerOnResults()337     public void testStartScanListenerOnResults() throws Exception {
338         ScanSettings scanSettings = new ScanSettings();
339         WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
340 
341         mWifiScanner.startScan(scanSettings, scanListener);
342         mLooper.dispatchAll();
343 
344         ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
345         verify(mHandler).handleMessage(messageArgumentCaptor.capture());
346         Message sentMessage = messageArgumentCaptor.getValue();
347         assertNotNull(sentMessage);
348 
349         assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
350         Messenger scannerMessenger =
351                 mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
352 
353         ScanResult scanResult = new ScanResult();
354         ScanData scanDatas[] = new ScanData[]{new ScanData(0, 0 , new ScanResult[] {scanResult})};
355         Message responseMessage = Message.obtain();
356         responseMessage.what = WifiScanner.CMD_SCAN_RESULT;
357         responseMessage.arg2 = sentMessage.arg2;
358         responseMessage.obj = new WifiScanner.ParcelableScanData(scanDatas);
359         scannerMessenger.send(responseMessage);
360         mLooper.dispatchAll();
361 
362         verify(scanListener).onResults(scanDatas);
363     }
364 
365     /**
366      * Test behavior of {@link WifiScanner#startDisconnectedPnoScan(ScanSettings, PnoSettings,
367      * WifiScanner.PnoScanListener)}
368      * @throws Exception
369      */
370     @Test
testStartDisconnectedPnoScan()371     public void testStartDisconnectedPnoScan() throws Exception {
372         ScanSettings scanSettings = new ScanSettings();
373         PnoSettings pnoSettings = new PnoSettings();
374         WifiScanner.PnoScanListener pnoScanListener = mock(WifiScanner.PnoScanListener.class);
375 
376         mWifiScanner.startDisconnectedPnoScan(scanSettings, pnoSettings, pnoScanListener);
377         mLooper.dispatchAll();
378 
379         ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
380         verify(mHandler).handleMessage(messageArgumentCaptor.capture());
381         Message message = messageArgumentCaptor.getValue();
382         assertNotNull(message);
383 
384         assertEquals(WifiScanner.CMD_START_PNO_SCAN, message.what);
385         assertTrue(message.obj instanceof Bundle);
386         Bundle messageBundle = (Bundle) message.obj;
387         assertEquals(scanSettings,
388                 messageBundle.getParcelable(WifiScanner.PNO_PARAMS_SCAN_SETTINGS_KEY));
389         assertTrue(scanSettings.isPnoScan);
390         assertFalse(pnoSettings.isConnected);
391         assertEquals(pnoSettings,
392                 messageBundle.getParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY));
393     }
394 
395     /**
396      * Test behavior of {@link WifiScanner#startConnectedPnoScan(ScanSettings, PnoSettings,
397      * WifiScanner.PnoScanListener)}
398      * @throws Exception
399      */
400     @Test
testStartConnectedPnoScan()401     public void testStartConnectedPnoScan() throws Exception {
402         ScanSettings scanSettings = new ScanSettings();
403         PnoSettings pnoSettings = new PnoSettings();
404         WifiScanner.PnoScanListener pnoScanListener = mock(WifiScanner.PnoScanListener.class);
405 
406         mWifiScanner.startConnectedPnoScan(scanSettings, pnoSettings, pnoScanListener);
407         mLooper.dispatchAll();
408 
409         ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
410         verify(mHandler).handleMessage(messageArgumentCaptor.capture());
411         Message message = messageArgumentCaptor.getValue();
412         assertNotNull(message);
413 
414         assertEquals(WifiScanner.CMD_START_PNO_SCAN, message.what);
415         assertTrue(message.obj instanceof Bundle);
416         Bundle messageBundle = (Bundle) message.obj;
417         assertEquals(scanSettings,
418                 messageBundle.getParcelable(WifiScanner.PNO_PARAMS_SCAN_SETTINGS_KEY));
419         assertTrue(scanSettings.isPnoScan);
420         assertTrue(pnoSettings.isConnected);
421         assertEquals(pnoSettings,
422                 messageBundle.getParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY));
423     }
424 
425     /**
426      * Test behavior of {@link WifiScanner#stopPnoScan(WifiScanner.ScanListener)}
427      * WifiScanner.PnoScanListener)}
428      * @throws Exception
429      */
430     @Test
testStopPnoScan()431     public void testStopPnoScan() throws Exception {
432         ScanSettings scanSettings = new ScanSettings();
433         PnoSettings pnoSettings = new PnoSettings();
434         WifiScanner.PnoScanListener pnoScanListener = mock(WifiScanner.PnoScanListener.class);
435 
436         mWifiScanner.startDisconnectedPnoScan(scanSettings, pnoSettings, pnoScanListener);
437         mLooper.dispatchAll();
438         mWifiScanner.stopPnoScan(pnoScanListener);
439         mLooper.dispatchAll();
440 
441         ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
442         verify(mHandler, times(2)).handleMessage(messageArgumentCaptor.capture());
443         Message message = messageArgumentCaptor.getValue();
444         assertNotNull(message);
445 
446         assertEquals(WifiScanner.CMD_STOP_PNO_SCAN, message.what);
447     }
448 }
449