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 17 package com.android.server.wifi; 18 19 import static org.junit.Assert.*; 20 import static org.junit.Assume.*; 21 import static org.mockito.Mockito.*; 22 23 import android.net.wifi.ScanResult; 24 import android.net.wifi.WifiScanner; 25 import android.net.wifi.WifiScanner.ScanData; 26 import android.net.wifi.WifiSsid; 27 28 import org.hamcrest.Description; 29 import org.hamcrest.Matcher; 30 import org.hamcrest.TypeSafeDiagnosingMatcher; 31 32 import java.util.Arrays; 33 import java.util.HashSet; 34 import java.util.Set; 35 36 /** 37 * Utilities for testing Wifi Scanning 38 */ 39 public class ScanTestUtil { 40 41 public static void setupMockChannels(WifiNative wifiNative, int[] channels24, int[] channels5, 42 int[] channelsDfs) throws Exception { 43 when(wifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ)) 44 .thenReturn(channels24); 45 when(wifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ)) 46 .thenReturn(channels5); 47 when(wifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY)) 48 .thenReturn(channelsDfs); 49 } 50 51 public static WifiScanner.ScanSettings createRequest(WifiScanner.ChannelSpec[] channels, 52 int period, int batch, int bssidsPerScan, int reportEvents) { 53 WifiScanner.ScanSettings request = new WifiScanner.ScanSettings(); 54 request.band = WifiScanner.WIFI_BAND_UNSPECIFIED; 55 request.channels = channels; 56 request.periodInMs = period; 57 request.numBssidsPerScan = bssidsPerScan; 58 request.maxScansToCache = batch; 59 request.reportEvents = reportEvents; 60 return request; 61 } 62 63 public static WifiScanner.ScanSettings createRequest(int type, int band, int period, int batch, 64 int bssidsPerScan, int reportEvents) { 65 return createRequest(WifiScanner.TYPE_HIGH_ACCURACY, band, period, 0, 0, 66 batch, bssidsPerScan, reportEvents); 67 } 68 69 public static WifiScanner.ScanSettings createRequest(int band, int period, int batch, 70 int bssidsPerScan, int reportEvents) { 71 return createRequest(WifiScanner.TYPE_HIGH_ACCURACY, band, period, 0, 0, batch, 72 bssidsPerScan, reportEvents); 73 } 74 75 /** 76 * Create an exponential back off scan request if maxPeriod != period && maxPeriod != 0. 77 */ 78 public static WifiScanner.ScanSettings createRequest(int type, int band, int period, 79 int maxPeriod, int stepCount, int batch, int bssidsPerScan, int reportEvents) { 80 WifiScanner.ScanSettings request = new WifiScanner.ScanSettings(); 81 request.type = type; 82 request.band = band; 83 request.channels = null; 84 request.periodInMs = period; 85 request.maxPeriodInMs = maxPeriod; 86 request.stepCount = stepCount; 87 request.numBssidsPerScan = bssidsPerScan; 88 request.maxScansToCache = batch; 89 request.reportEvents = reportEvents; 90 return request; 91 } 92 93 /** 94 * Builder to create WifiNative.ScanSettings objects for testing 95 */ 96 public static class NativeScanSettingsBuilder { 97 private final WifiNative.ScanSettings mSettings = new WifiNative.ScanSettings(); 98 public NativeScanSettingsBuilder() { 99 mSettings.scanType = WifiNative.SCAN_TYPE_LOW_LATENCY; 100 mSettings.buckets = new WifiNative.BucketSettings[0]; 101 mSettings.num_buckets = 0; 102 mSettings.report_threshold_percent = 100; 103 } 104 105 public NativeScanSettingsBuilder withType(int type) { 106 mSettings.scanType = type; 107 return this; 108 } 109 public NativeScanSettingsBuilder withBasePeriod(int basePeriod) { 110 mSettings.base_period_ms = basePeriod; 111 return this; 112 } 113 public NativeScanSettingsBuilder withMaxApPerScan(int maxAp) { 114 mSettings.max_ap_per_scan = maxAp; 115 return this; 116 } 117 public NativeScanSettingsBuilder withMaxScansToCache(int maxScans) { 118 mSettings.report_threshold_num_scans = maxScans; 119 return this; 120 } 121 public NativeScanSettingsBuilder withMaxPercentToCache(int percent) { 122 mSettings.report_threshold_percent = percent; 123 return this; 124 } 125 126 /** 127 * Add the provided hidden network SSIDs to scan request. 128 * @param networkSSIDs List of hidden network SSIDs 129 * @return builder object 130 */ 131 public NativeScanSettingsBuilder withHiddenNetworkSSIDs(String[] networkSSIDs) { 132 mSettings.hiddenNetworks = new WifiNative.HiddenNetwork[networkSSIDs.length]; 133 for (int i = 0; i < networkSSIDs.length; i++) { 134 mSettings.hiddenNetworks[i] = new WifiNative.HiddenNetwork(); 135 mSettings.hiddenNetworks[i].ssid = networkSSIDs[i]; 136 } 137 return this; 138 } 139 140 public NativeScanSettingsBuilder addBucketWithBand( 141 int period, int reportEvents, int band) { 142 WifiNative.BucketSettings bucket = new WifiNative.BucketSettings(); 143 bucket.bucket = mSettings.num_buckets; 144 bucket.band = band; 145 bucket.period_ms = period; 146 bucket.report_events = reportEvents; 147 return addBucket(bucket); 148 } 149 150 public NativeScanSettingsBuilder addBucketWithChannels( 151 int period, int reportEvents, WifiScanner.ChannelSpec... channels) { 152 int[] channelFreqs = new int[channels.length]; 153 for (int i = 0; i < channels.length; ++i) { 154 channelFreqs[i] = channels[i].frequency; 155 } 156 return addBucketWithChannels(period, reportEvents, channelFreqs); 157 } 158 159 public NativeScanSettingsBuilder addBucketWithChannels( 160 int period, int reportEvents, int... channels) { 161 WifiNative.BucketSettings bucket = new WifiNative.BucketSettings(); 162 bucket.bucket = mSettings.num_buckets; 163 bucket.band = WifiScanner.WIFI_BAND_UNSPECIFIED; 164 bucket.num_channels = channels.length; 165 bucket.channels = channelsToNativeSettings(channels); 166 bucket.period_ms = period; 167 bucket.report_events = reportEvents; 168 return addBucket(bucket); 169 } 170 171 public NativeScanSettingsBuilder addBucket(WifiNative.BucketSettings bucket) { 172 mSettings.buckets = Arrays.copyOf(mSettings.buckets, mSettings.num_buckets + 1); 173 mSettings.buckets[mSettings.num_buckets] = bucket; 174 mSettings.num_buckets = mSettings.num_buckets + 1; 175 return this; 176 } 177 178 public WifiNative.ScanSettings build() { 179 return mSettings; 180 } 181 182 } 183 184 private static int getNativeScanType(int type) { 185 switch(type) { 186 case WifiScanner.TYPE_LOW_LATENCY: 187 return WifiNative.SCAN_TYPE_LOW_LATENCY; 188 case WifiScanner.TYPE_LOW_POWER: 189 return WifiNative.SCAN_TYPE_LOW_POWER; 190 case WifiScanner.TYPE_HIGH_ACCURACY: 191 return WifiNative.SCAN_TYPE_HIGH_ACCURACY; 192 default: 193 fail(); 194 return -1; 195 } 196 } 197 198 /** 199 * Compute the expected native scan settings that are expected for the given 200 * WifiScanner.ScanSettings. 201 */ 202 public static WifiNative.ScanSettings computeSingleScanNativeSettings( 203 WifiScanner.ScanSettings requestSettings) { 204 int reportEvents = requestSettings.reportEvents | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN; 205 NativeScanSettingsBuilder builder = new NativeScanSettingsBuilder() 206 .withBasePeriod(0) 207 .withMaxApPerScan(0) 208 .withMaxPercentToCache(0) 209 .withMaxScansToCache(0) 210 .withType(getNativeScanType(requestSettings.type)); 211 if (requestSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { 212 builder.addBucketWithChannels(0, reportEvents, requestSettings.channels); 213 } else { 214 builder.addBucketWithBand(0, reportEvents, requestSettings.band); 215 } 216 217 return builder.build(); 218 } 219 220 /** 221 * Compute the expected native scan settings that are expected for the given channels. 222 */ 223 public static WifiNative.ScanSettings createSingleScanNativeSettingsForChannels( 224 int reportEvents, WifiScanner.ChannelSpec... channels) { 225 return createSingleScanNativeSettingsForChannels( 226 WifiNative.SCAN_TYPE_LOW_LATENCY, reportEvents, channels); 227 } 228 229 /** 230 * Compute the expected native scan settings that are expected for the given channels & type. 231 */ 232 public static WifiNative.ScanSettings createSingleScanNativeSettingsForChannels( 233 int nativeScanType, int reportEvents, WifiScanner.ChannelSpec... channels) { 234 int actualReportEvents = reportEvents | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN; 235 return new NativeScanSettingsBuilder() 236 .withBasePeriod(0) 237 .withMaxApPerScan(0) 238 .withMaxPercentToCache(0) 239 .withMaxScansToCache(0) 240 .addBucketWithChannels(0, actualReportEvents, channels) 241 .withType(nativeScanType) 242 .build(); 243 } 244 245 public static Set<Integer> createFreqSet(int... elements) { 246 Set<Integer> set = new HashSet<>(); 247 for (int e : elements) { 248 set.add(e); 249 } 250 return set; 251 } 252 253 public static ScanResult createScanResult(int freq) { 254 return new ScanResult(WifiSsid.createFromAsciiEncoded("AN SSID"), "00:00:00:00:00:00", 0L, 255 -1, null, "", 0, freq, 0); 256 } 257 258 private static ScanData createScanData(int[] freqs, int bucketsScanned) { 259 ScanResult[] results = new ScanResult[freqs.length]; 260 for (int i = 0; i < freqs.length; ++i) { 261 results[i] = createScanResult(freqs[i]); 262 } 263 return new ScanData(0, 0, bucketsScanned, false, results); 264 } 265 266 public static ScanData[] createScanDatas(int[][] freqs, int[] bucketsScanned) { 267 assumeTrue(freqs.length == bucketsScanned.length); 268 ScanData[] data = new ScanData[freqs.length]; 269 for (int i = 0; i < freqs.length; ++i) { 270 data[i] = createScanData(freqs[i], bucketsScanned[i]); 271 } 272 return data; 273 } 274 275 public static ScanData[] createScanDatas(int[][] freqs) { 276 return createScanDatas(freqs, new int[freqs.length] /* defaults all 0 */); 277 } 278 279 private static void assertScanResultEquals( 280 String prefix, ScanResult expected, ScanResult actual) { 281 assertEquals(prefix + "SSID", expected.SSID, actual.SSID); 282 assertEquals(prefix + "wifiSsid", expected.wifiSsid.toString(), actual.wifiSsid.toString()); 283 assertEquals(prefix + "BSSID", expected.BSSID, actual.BSSID); 284 assertEquals(prefix + "capabilities", expected.capabilities, actual.capabilities); 285 assertEquals(prefix + "level", expected.level, actual.level); 286 assertEquals(prefix + "frequency", expected.frequency, actual.frequency); 287 assertEquals(prefix + "timestamp", expected.timestamp, actual.timestamp); 288 assertEquals(prefix + "seen", expected.seen, actual.seen); 289 } 290 291 private static void assertScanResultsEquals(String prefix, ScanResult[] expected, 292 ScanResult[] actual) { 293 assertNotNull(prefix + "expected ScanResults was null", expected); 294 assertNotNull(prefix + "actual ScanResults was null", actual); 295 assertEquals(prefix + "results.length", expected.length, actual.length); 296 for (int j = 0; j < expected.length; ++j) { 297 ScanResult expectedResult = expected[j]; 298 ScanResult actualResult = actual[j]; 299 assertScanResultEquals(prefix + "results[" + j + "]", actualResult, expectedResult); 300 } 301 } 302 303 /** 304 * Asserts if the provided scan results are the same. 305 */ 306 public static void assertScanResultEquals(ScanResult expected, ScanResult actual) { 307 assertScanResultEquals("", expected, actual); 308 } 309 310 /** 311 * Asserts if the provided scan result arrays are the same. 312 */ 313 public static void assertScanResultsEquals(ScanResult[] expected, ScanResult[] actual) { 314 assertScanResultsEquals("", expected, actual); 315 } 316 317 private static void assertScanDataEquals(String prefix, ScanData expected, ScanData actual) { 318 assertNotNull(prefix + "expected ScanData was null", expected); 319 assertNotNull(prefix + "actual ScanData was null", actual); 320 assertEquals(prefix + "id", expected.getId(), actual.getId()); 321 assertEquals(prefix + "flags", expected.getFlags(), actual.getFlags()); 322 assertEquals(prefix + "all channels", expected.isAllChannelsScanned(), 323 actual.isAllChannelsScanned()); 324 assertScanResultsEquals(prefix, expected.getResults(), actual.getResults()); 325 } 326 327 public static void assertScanDataEquals(ScanData expected, ScanData actual) { 328 assertScanDataEquals("", expected, actual); 329 } 330 331 public static void assertScanDatasEquals(String prefix, ScanData[] expected, ScanData[] actual) { 332 assertNotNull("expected " + prefix + "ScanData[] was null", expected); 333 assertNotNull("actaul " + prefix + "ScanData[] was null", actual); 334 assertEquals(prefix + "ScanData.length", expected.length, actual.length); 335 for (int i = 0; i < expected.length; ++i) { 336 assertScanDataEquals(prefix + "ScanData[" + i + "].", expected[i], actual[i]); 337 } 338 } 339 340 public static void assertScanDatasEquals(ScanData[] expected, ScanData[] actual) { 341 assertScanDatasEquals("", expected, actual); 342 } 343 344 public static WifiScanner.ChannelSpec[] channelsToSpec(int... channels) { 345 WifiScanner.ChannelSpec[] channelSpecs = new WifiScanner.ChannelSpec[channels.length]; 346 for (int i = 0; i < channels.length; ++i) { 347 channelSpecs[i] = new WifiScanner.ChannelSpec(channels[i]); 348 } 349 return channelSpecs; 350 } 351 352 public static void assertNativeScanSettingsEquals(WifiNative.ScanSettings expected, 353 WifiNative.ScanSettings actual) { 354 assertEquals("scan type", expected.scanType, actual.scanType); 355 assertEquals("bssids per scan", expected.max_ap_per_scan, actual.max_ap_per_scan); 356 assertEquals("scans to cache", expected.report_threshold_num_scans, 357 actual.report_threshold_num_scans); 358 assertEquals("percent to cache", expected.report_threshold_percent, 359 actual.report_threshold_percent); 360 assertEquals("base period", expected.base_period_ms, actual.base_period_ms); 361 362 assertEquals("number of buckets", expected.num_buckets, actual.num_buckets); 363 assertNotNull("buckets was null", actual.buckets); 364 for (int i = 0; i < expected.buckets.length; ++i) { 365 assertNotNull("buckets[" + i + "] was null", actual.buckets[i]); 366 assertEquals("buckets[" + i + "].period", 367 expected.buckets[i].period_ms, actual.buckets[i].period_ms); 368 assertEquals("buckets[" + i + "].reportEvents", 369 expected.buckets[i].report_events, actual.buckets[i].report_events); 370 371 assertEquals("buckets[" + i + "].band", 372 expected.buckets[i].band, actual.buckets[i].band); 373 if (expected.buckets[i].band == WifiScanner.WIFI_BAND_UNSPECIFIED) { 374 Set<Integer> expectedChannels = new HashSet<>(); 375 for (WifiNative.ChannelSettings channel : expected.buckets[i].channels) { 376 expectedChannels.add(channel.frequency); 377 } 378 Set<Integer> actualChannels = new HashSet<>(); 379 for (WifiNative.ChannelSettings channel : actual.buckets[i].channels) { 380 actualChannels.add(channel.frequency); 381 } 382 assertEquals("channels", expectedChannels, actualChannels); 383 } else { 384 // since num_channels and channels are ignored when band is not 385 // WifiScanner.WIFI_BAND_UNSPECIFIED just assert that there are no channels 386 // the band equality was already checked above 387 assertEquals("buckets[" + i + "].num_channels not 0", 0, 388 actual.buckets[i].num_channels); 389 assertTrue("buckets[" + i + "].channels not null or empty", 390 actual.buckets[i].channels == null 391 || actual.buckets[i].channels.length == 0); 392 } 393 } 394 } 395 396 /** 397 * Asserts if the provided pno settings are the same. 398 */ 399 public static void assertNativePnoSettingsEquals(WifiNative.PnoSettings expected, 400 WifiNative.PnoSettings actual) { 401 assertNotNull("expected was null", expected); 402 assertNotNull("actaul was null", actual); 403 assertEquals("min5GHzRssi", expected.min5GHzRssi, actual.min5GHzRssi); 404 assertEquals("min24GHzRssi", expected.min24GHzRssi, actual.min24GHzRssi); 405 assertEquals("initialScoreMax", expected.initialScoreMax, actual.initialScoreMax); 406 assertEquals("currentConnectionBonus", expected.currentConnectionBonus, 407 actual.currentConnectionBonus); 408 assertEquals("sameNetworkBonus", expected.sameNetworkBonus, actual.sameNetworkBonus); 409 assertEquals("secureBonus", expected.secureBonus, actual.secureBonus); 410 assertEquals("band5GHzBonus", expected.band5GHzBonus, actual.band5GHzBonus); 411 assertEquals("isConnected", expected.isConnected, actual.isConnected); 412 assertNotNull("expected networkList was null", expected.networkList); 413 assertNotNull("actual networkList was null", actual.networkList); 414 assertEquals("networkList.length", expected.networkList.length, actual.networkList.length); 415 for (int i = 0; i < expected.networkList.length; i++) { 416 assertEquals("networkList[" + i + "].ssid", 417 expected.networkList[i].ssid, actual.networkList[i].ssid); 418 assertEquals("networkList[" + i + "].flags", 419 expected.networkList[i].flags, actual.networkList[i].flags); 420 assertEquals("networkList[" + i + "].auth_bit_field", 421 expected.networkList[i].auth_bit_field, actual.networkList[i].auth_bit_field); 422 } 423 } 424 425 /** 426 * Convert a list of channel frequencies to an array of equivalent WifiNative.ChannelSettings 427 */ 428 public static WifiNative.ChannelSettings[] channelsToNativeSettings(int... channels) { 429 WifiNative.ChannelSettings[] channelSpecs = new WifiNative.ChannelSettings[channels.length]; 430 for (int i = 0; i < channels.length; ++i) { 431 channelSpecs[i] = new WifiNative.ChannelSettings(); 432 channelSpecs[i].frequency = channels[i]; 433 } 434 return channelSpecs; 435 } 436 437 /** 438 * Matcher to check that a BucketSettings has the given band 439 */ 440 public static Matcher<WifiNative.BucketSettings> bandIs(final int expectedBand) { 441 return new TypeSafeDiagnosingMatcher<WifiNative.BucketSettings>() { 442 @Override 443 public boolean matchesSafely(WifiNative.BucketSettings bucketSettings, 444 Description mismatchDescription) { 445 if (bucketSettings.band != expectedBand) { 446 mismatchDescription 447 .appendText("did not have expected band ").appendValue(expectedBand) 448 .appendText(", was ").appendValue(bucketSettings.band); 449 return false; 450 } else { 451 return true; 452 } 453 } 454 455 @Override 456 public void describeTo(final Description description) { 457 description.appendText("bucket band is ").appendValue(expectedBand); 458 } 459 }; 460 } 461 462 /** 463 * Matcher to check that a BucketSettings has exactly the given channels 464 */ 465 public static Matcher<WifiNative.BucketSettings> channelsAre(final int... expectedChannels) { 466 return new TypeSafeDiagnosingMatcher<WifiNative.BucketSettings>() { 467 @Override 468 public boolean matchesSafely(WifiNative.BucketSettings bucketSettings, 469 Description mismatchDescription) { 470 if (bucketSettings.band != WifiScanner.WIFI_BAND_UNSPECIFIED) { 471 mismatchDescription.appendText("did not have expected unspecified band, was ") 472 .appendValue(bucketSettings.band); 473 return false; 474 } else if (bucketSettings.num_channels != expectedChannels.length) { 475 mismatchDescription 476 .appendText("did not have expected num_channels ") 477 .appendValue(expectedChannels.length) 478 .appendText(", was ").appendValue(bucketSettings.num_channels); 479 return false; 480 } else if (bucketSettings.channels == null) { 481 mismatchDescription.appendText("had null channels array"); 482 return false; 483 } else if (bucketSettings.channels.length != expectedChannels.length) { 484 mismatchDescription 485 .appendText("did not have channels array length matching excepted ") 486 .appendValue(expectedChannels.length) 487 .appendText(", was ").appendValue(bucketSettings.channels.length); 488 return false; 489 } else { 490 Set<Integer> foundChannelsSet = new HashSet<>(); 491 for (int i = 0; i < bucketSettings.channels.length; ++i) { 492 foundChannelsSet.add(bucketSettings.channels[i].frequency); 493 } 494 Set<Integer> expectedChannelsSet = new HashSet<>(); 495 for (int i = 0; i < expectedChannels.length; ++i) { 496 expectedChannelsSet.add(expectedChannels[i]); 497 } 498 499 if (!foundChannelsSet.containsAll(expectedChannelsSet) 500 || foundChannelsSet.size() != expectedChannelsSet.size()) { 501 Set<Integer> extraChannelsSet = new HashSet<>(foundChannelsSet); 502 extraChannelsSet.removeAll(expectedChannelsSet); 503 expectedChannelsSet.removeAll(foundChannelsSet); 504 mismatchDescription 505 .appendText("does not contain expected channels ") 506 .appendValue(expectedChannelsSet); 507 if (extraChannelsSet.size() > 0) { 508 mismatchDescription 509 .appendText(", but contains extra channels ") 510 .appendValue(extraChannelsSet); 511 } 512 return false; 513 } else { 514 return true; 515 } 516 } 517 } 518 519 @Override 520 public void describeTo(final Description description) { 521 description.appendText("bucket channels are ").appendValue(expectedChannels); 522 } 523 }; 524 } 525 } 526