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