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