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.assertNativeScanSettingsEquals; 21import static com.android.server.wifi.ScanTestUtil.channelsToSpec; 22import static com.android.server.wifi.ScanTestUtil.createRequest; 23 24import static org.junit.Assert.assertEquals; 25import static org.junit.Assert.assertNotNull; 26import static org.junit.Assert.assertTrue; 27import static org.mockito.Mockito.validateMockitoUsage; 28 29import android.net.wifi.WifiScanner; 30import android.net.wifi.WifiScanner.ScanSettings; 31import android.test.suitebuilder.annotation.SmallTest; 32import android.util.ArraySet; 33 34import com.android.server.wifi.WifiNative; 35import com.android.server.wifi.WifiNative.BucketSettings; 36import com.android.server.wifi.scanner.KnownBandsChannelHelper.KnownBandsChannelCollection; 37 38import org.junit.After; 39import org.junit.Before; 40import org.junit.Test; 41 42import java.lang.reflect.Field; 43import java.util.ArrayList; 44import java.util.Collection; 45import java.util.Collections; 46import java.util.Set; 47 48/** 49 * Unit tests for {@link com.android.server.wifi.scanner.BackgroundScanScheduler}. 50 */ 51@SmallTest 52public class BackgroundScanSchedulerTest { 53 54 private static final int DEFAULT_MAX_BUCKETS = 9; 55 private static final int DEFAULT_MAX_CHANNELS_PER_BUCKET = 23; 56 private static final int DEFAULT_MAX_BATCH = 11; 57 private static final int DEFAULT_MAX_AP_PER_SCAN = 33; 58 59 private KnownBandsChannelHelper mChannelHelper; 60 private BackgroundScanScheduler mScheduler; 61 62 @Before 63 public void setUp() throws Exception { 64 mChannelHelper = new PresetKnownBandsChannelHelper( 65 new int[]{2400, 2450}, 66 new int[]{5150, 5175}, 67 new int[]{5600, 5650, 5660}); 68 mScheduler = new BackgroundScanScheduler(mChannelHelper); 69 mScheduler.setMaxBuckets(DEFAULT_MAX_BUCKETS); 70 mScheduler.setMaxChannelsPerBucket(DEFAULT_MAX_CHANNELS_PER_BUCKET); 71 mScheduler.setMaxBatch(DEFAULT_MAX_BATCH); 72 mScheduler.setMaxApPerScan(DEFAULT_MAX_AP_PER_SCAN); 73 } 74 75 @After 76 public void cleanup() { 77 validateMockitoUsage(); 78 } 79 80 @Test 81 public void noRequest() { 82 Collection<ScanSettings> requests = Collections.emptyList(); 83 84 mScheduler.updateSchedule(requests); 85 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 86 87 assertEquals(30000, schedule.base_period_ms); 88 assertBuckets(schedule, 0); 89 } 90 91 @Test 92 public void singleRequest() { 93 Collection<ScanSettings> requests = Collections.singleton(createRequest( 94 WifiScanner.WIFI_BAND_BOTH, 30000, 0, 20, 95 WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT 96 )); 97 98 mScheduler.updateSchedule(requests); 99 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 100 101 assertEquals(30000, schedule.base_period_ms); 102 assertBuckets(schedule, 1); 103 for (ScanSettings request : requests) { 104 assertSettingsSatisfied(schedule, request, false, true); 105 } 106 } 107 108 @Test 109 public void singleRequestWithoutPredefinedBucket() { 110 Collection<ScanSettings> requests = Collections.singleton(createRequest( 111 WifiScanner.WIFI_BAND_BOTH, 7500, 0, 20, 112 WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT 113 )); 114 115 mScheduler.updateSchedule(requests); 116 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 117 118 assertEquals("base_period_ms", 10000, schedule.base_period_ms); 119 assertBuckets(schedule, 1); 120 for (ScanSettings request : requests) { 121 assertSettingsSatisfied(schedule, request, false, true); 122 } 123 } 124 125 @Test 126 public void fewRequests() { 127 Collection<ScanSettings> requests = new ArrayList<>(); 128 requests.add(createRequest(WifiScanner.WIFI_BAND_BOTH, 30000, 0, 20, 129 WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); 130 requests.add(createRequest(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY, 14000, 0, 20, 131 WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); 132 133 mScheduler.updateSchedule(requests); 134 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 135 136 assertEquals("base_period_ms", 10000, schedule.base_period_ms); 137 assertBuckets(schedule, 2); 138 for (ScanSettings request : requests) { 139 assertSettingsSatisfied(schedule, request, false, true); 140 } 141 } 142 143 @Test 144 public void manyRequests() { 145 Collection<ScanSettings> requests = new ArrayList<>(); 146 requests.add(createRequest(WifiScanner.WIFI_BAND_BOTH, 30000, 0, 20, 147 WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); 148 requests.add(createRequest(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY, 15000, 0, 20, 149 WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); 150 requests.add(createRequest(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY, 10000, 0, 20, 151 WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); 152 153 mScheduler.updateSchedule(requests); 154 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 155 156 assertEquals("base_period_ms", 10000, schedule.base_period_ms); 157 assertBuckets(schedule, 2); 158 for (ScanSettings request : requests) { 159 assertSettingsSatisfied(schedule, request, false, false); 160 } 161 } 162 163 @Test 164 public void requestsWithNoPeriodCommonDenominator() { 165 ArrayList<ScanSettings> requests = new ArrayList<>(); 166 requests.add(createRequest(WifiScanner.WIFI_BAND_BOTH, 299999, 0, 20, 167 WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); 168 requests.add(createRequest(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY, 10500, 0, 20, 169 WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); 170 171 mScheduler.updateSchedule(requests); 172 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 173 174 assertEquals("base_period_ms", 10000, schedule.base_period_ms); 175 assertBuckets(schedule, 2); 176 for (ScanSettings request : requests) { 177 assertSettingsSatisfied(schedule, request, false, true); 178 } 179 } 180 181 @Test 182 public void manyRequestsDifferentReportScans() { 183 Collection<ScanSettings> requests = new ArrayList<>(); 184 requests.add(createRequest(channelsToSpec(5175), 60000, 0, 20, 185 WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL)); 186 requests.add(createRequest(channelsToSpec(2400), 60000, 0, 20, 187 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 188 requests.add(createRequest(channelsToSpec(2450), 60000, 0, 20, 189 WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); 190 requests.add(createRequest(channelsToSpec(5150), 60000, 0, 20, 191 WifiScanner.REPORT_EVENT_NO_BATCH)); 192 193 mScheduler.updateSchedule(requests); 194 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 195 196 assertEquals("base_period_ms", 60000, schedule.base_period_ms); 197 assertBuckets(schedule, 1); 198 for (ScanSettings request : requests) { 199 assertSettingsSatisfied(schedule, request, false, true); 200 } 201 } 202 203 @Test 204 public void exceedMaxBatch() { 205 Collection<ScanSettings> requests = new ArrayList<>(); 206 requests.add(createRequest(channelsToSpec(5175), 30000, 10, 20, 207 WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL)); 208 209 mScheduler.setMaxBatch(5); 210 mScheduler.updateSchedule(requests); 211 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 212 213 assertEquals("base_period_ms", 30000, schedule.base_period_ms); 214 assertBuckets(schedule, 1); 215 for (ScanSettings request : requests) { 216 assertSettingsSatisfied(schedule, request, false, true); 217 } 218 assertEquals("maxScansToCache", 5, schedule.report_threshold_num_scans); 219 } 220 221 @Test 222 public void defaultMaxBatch() { 223 Collection<ScanSettings> requests = new ArrayList<>(); 224 requests.add(createRequest(channelsToSpec(5175), 60000, 0, 20, 225 WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL)); 226 227 mScheduler.setMaxBatch(6); 228 mScheduler.updateSchedule(requests); 229 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 230 231 assertEquals("base_period_ms", 60000, schedule.base_period_ms); 232 assertBuckets(schedule, 1); 233 for (ScanSettings request : requests) { 234 assertSettingsSatisfied(schedule, request, false, true); 235 } 236 assertEquals("maxScansToCache", 6, schedule.report_threshold_num_scans); 237 } 238 239 @Test 240 public void exceedMaxAps() { 241 Collection<ScanSettings> requests = new ArrayList<>(); 242 requests.add(createRequest(channelsToSpec(5175), 30000, 10, 20, 243 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 244 245 mScheduler.setMaxApPerScan(5); 246 mScheduler.updateSchedule(requests); 247 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 248 249 assertEquals("maxScansToCache", 5, schedule.max_ap_per_scan); 250 } 251 252 @Test 253 public void defaultMaxAps() { 254 Collection<ScanSettings> requests = new ArrayList<>(); 255 requests.add(createRequest(channelsToSpec(5175), 30000, 10, 0, 256 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 257 258 mScheduler.setMaxApPerScan(8); 259 mScheduler.updateSchedule(requests); 260 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 261 262 assertEquals("maxApsPerScan", 8, schedule.max_ap_per_scan); 263 } 264 265 @Test 266 public void optimalScheduleExceedsNumberOfAvailableBuckets() { 267 ArrayList<ScanSettings> requests = new ArrayList<>(); 268 requests.add(createRequest(channelsToSpec(2400), 30000, 0, 20, 269 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 270 requests.add(createRequest(channelsToSpec(2450), 10000, 0, 20, 271 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 272 requests.add(createRequest(channelsToSpec(5150), 120000, 0, 20, 273 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 274 275 mScheduler.setMaxBuckets(2); 276 mScheduler.updateSchedule(requests); 277 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 278 279 assertEquals("base_period_ms", 30000, schedule.base_period_ms); 280 assertBuckets(schedule, 2); 281 for (ScanSettings request : requests) { 282 assertSettingsSatisfied(schedule, request, true, true); 283 } 284 } 285 286 @Test 287 public void optimalScheduleExceedsNumberOfAvailableBuckets2() { 288 ArrayList<ScanSettings> requests = new ArrayList<>(); 289 requests.add(createRequest(channelsToSpec(2400), 30000, 0, 20, 290 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 291 requests.add(createRequest(channelsToSpec(2450), 60000, 0, 20, 292 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 293 requests.add(createRequest(channelsToSpec(5150), 3840000, 0, 20, 294 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 295 296 mScheduler.setMaxBuckets(2); 297 mScheduler.updateSchedule(requests); 298 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 299 300 assertEquals("base_period_ms", 30000, schedule.base_period_ms); 301 assertBuckets(schedule, 2); 302 for (ScanSettings request : requests) { 303 assertSettingsSatisfied(schedule, request, true, true); 304 } 305 } 306 307 /** 308 * Ensure that a channel request is placed in the bucket closest to the original 309 * period and not the bucket it is initially placed in. Here the 5 min period is 310 * initially placed in the 240s bucket, but that bucket is eliminated because it 311 * would be a 7th bucket. This test ensures that the request is placed in the 480s 312 * bucket and not the 120s bucket. 313 */ 314 @Test 315 public void optimalScheduleExceedsNumberOfAvailableBucketsClosestToOriginal() { 316 ArrayList<ScanSettings> requests = new ArrayList<>(); 317 requests.add(createRequest(channelsToSpec(2400), 30 * 1000, 0, 20, 318 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 319 requests.add(createRequest(channelsToSpec(2450), 120 * 1000, 0, 20, 320 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 321 requests.add(createRequest(channelsToSpec(5150), 480 * 1000, 0, 20, 322 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 323 requests.add(createRequest(channelsToSpec(5175), 10 * 1000, 0, 20, 324 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 325 requests.add(createRequest(channelsToSpec(5600), 60 * 1000, 0, 20, 326 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 327 requests.add(createRequest(channelsToSpec(5650), 1920 * 1000, 0, 20, 328 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 329 330 requests.add(createRequest(channelsToSpec(5660), 300 * 1000, 0, 20, // 5 min 331 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 332 333 mScheduler.setMaxBuckets(6); 334 mScheduler.updateSchedule(requests); 335 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 336 337 assertEquals("base_period_ms", 10000, schedule.base_period_ms); 338 assertBuckets(schedule, 6); 339 for (ScanSettings request : requests) { 340 assertSettingsSatisfied(schedule, request, true, true); 341 } 342 } 343 344 @Test 345 public void optimalScheduleExceedsMaxChannelsOnSingleBand() { 346 ArrayList<ScanSettings> requests = new ArrayList<>(); 347 requests.add(createRequest(channelsToSpec(2400, 2450), 30000, 0, 20, 348 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 349 350 mScheduler.setMaxBuckets(2); 351 mScheduler.setMaxChannelsPerBucket(1); 352 mScheduler.updateSchedule(requests); 353 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 354 355 assertEquals("base_period_ms", 30000, schedule.base_period_ms); 356 assertBuckets(schedule, 2); 357 for (ScanSettings request : requests) { 358 assertSettingsSatisfied(schedule, request, true, true); 359 } 360 } 361 362 @Test 363 public void optimalScheduleExceedsMaxChannelsOnMultipleBands() { 364 ArrayList<ScanSettings> requests = new ArrayList<>(); 365 requests.add(createRequest(channelsToSpec(2400, 2450, 5150), 30000, 0, 20, 366 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 367 368 mScheduler.setMaxBuckets(2); 369 mScheduler.setMaxChannelsPerBucket(2); 370 mScheduler.updateSchedule(requests); 371 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 372 373 assertEquals("base_period_ms", 30000, schedule.base_period_ms); 374 assertBuckets(schedule, 2); 375 for (ScanSettings request : requests) { 376 assertSettingsSatisfied(schedule, request, true, true); 377 } 378 } 379 380 @Test 381 public void optimalScheduleExceedsMaxChannelsOnMultipleBandsFromMultipleRequests() { 382 ArrayList<ScanSettings> requests = new ArrayList<>(); 383 requests.add(createRequest(channelsToSpec(2400, 2450), 30000, 0, 20, 384 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 385 requests.add(createRequest(WifiScanner.WIFI_BAND_5_GHZ, 30000, 0, 20, 386 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 387 388 mScheduler.setMaxBuckets(2); 389 mScheduler.setMaxChannelsPerBucket(2); 390 mScheduler.updateSchedule(requests); 391 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 392 393 assertEquals("base_period_ms", 30000, schedule.base_period_ms); 394 assertBuckets(schedule, 2); 395 for (ScanSettings request : requests) { 396 assertSettingsSatisfied(schedule, request, true, true); 397 } 398 } 399 400 @Test 401 public void exactRequests() { 402 scheduleAndTestExactRequest(createRequest(WifiScanner.WIFI_BAND_BOTH, 30000, 0, 403 20, WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL)); 404 scheduleAndTestExactRequest(createRequest(WifiScanner.WIFI_BAND_5_GHZ, 60000, 3, 405 13, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 406 scheduleAndTestExactRequest(createRequest(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY, 10000, 2, 407 10, WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); 408 scheduleAndTestExactRequest(createRequest(WifiScanner.WIFI_BAND_BOTH, 25000, 0, 409 10, WifiScanner.REPORT_EVENT_NO_BATCH)); 410 scheduleAndTestExactRequest(createRequest(WifiScanner.WIFI_BAND_BOTH, 25000, 3, 411 0, WifiScanner.REPORT_EVENT_NO_BATCH)); 412 scheduleAndTestExactRequest(createRequest(channelsToSpec(2400, 5175, 5650) , 25000, 3, 413 0, WifiScanner.REPORT_EVENT_NO_BATCH)); 414 } 415 416 @Test 417 public void singleExponentialBackOffRequest() { 418 Collection<ScanSettings> requests = Collections.singleton(createRequest( 419 WifiScanner.WIFI_BAND_BOTH, 30000, 160000, 2, 0, 20, 420 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN 421 )); 422 423 mScheduler.updateSchedule(requests); 424 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 425 426 assertEquals(30000, schedule.base_period_ms); 427 assertBuckets(schedule, 1); 428 for (ScanSettings request : requests) { 429 assertSettingsSatisfied(schedule, request, false, true); 430 } 431 } 432 433 @Test 434 public void exponentialBackOffAndRegularRequests() { 435 Collection<ScanSettings> requests = new ArrayList<>(); 436 requests.add(createRequest(WifiScanner.WIFI_BAND_BOTH, 30000, 200000, 1, 437 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 438 requests.add(createRequest(channelsToSpec(5175), 30000, 0, 20, 439 WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL)); 440 441 mScheduler.updateSchedule(requests); 442 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 443 444 assertEquals("base_period_ms", 30000, schedule.base_period_ms); 445 assertBuckets(schedule, 2); 446 for (ScanSettings request : requests) { 447 assertSettingsSatisfied(schedule, request, false, true); 448 } 449 } 450 451 /** 452 * Add 2 background scan requests with different time intervals, but one of the setting channels 453 * is totally contained in the other setting. Ensure that the requests are collapsed into a 454 * common bucket with the lower time period setting. 455 */ 456 @Test 457 public void optimalScheduleFullyCollapsesDuplicateChannelsInBand() { 458 ArrayList<ScanSettings> requests = new ArrayList<>(); 459 requests.add(createRequest(channelsToSpec(2400, 2450), 240000, 0, 20, 460 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 461 requests.add(createRequest(WifiScanner.WIFI_BAND_24_GHZ, 10000, 0, 20, 462 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 463 464 mScheduler.setMaxBuckets(2); 465 mScheduler.setMaxChannelsPerBucket(2); 466 mScheduler.updateSchedule(requests); 467 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 468 469 assertEquals("base_period_ms", 10000, schedule.base_period_ms); 470 assertBuckets(schedule, 1); 471 for (ScanSettings request : requests) { 472 assertSettingsSatisfied(schedule, request, false, false); 473 } 474 475 assertEquals("scheduled bucket", 0, mScheduler.getScheduledBucket(requests.get(0))); 476 assertEquals("scheduled bucket", 0, mScheduler.getScheduledBucket(requests.get(1))); 477 478 KnownBandsChannelCollection collection = mChannelHelper.createChannelCollection(); 479 collection.addBand(WifiScanner.WIFI_BAND_24_GHZ); 480 Set<Integer> expectedBucketChannelSet = collection.getAllChannels(); 481 assertBucketChannels(schedule.buckets[0], expectedBucketChannelSet); 482 } 483 484 /** 485 * Add 2 background scan requests with different time intervals, but one of the setting channels 486 * is totally contained in the other setting. Ensure that the requests are collapsed into a 487 * common bucket with the lower time period setting. 488 */ 489 @Test 490 public void optimalScheduleFullyCollapsesDuplicateChannels() { 491 ArrayList<ScanSettings> requests = new ArrayList<>(); 492 requests.add(createRequest(channelsToSpec(2400, 2450), 240000, 0, 20, 493 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 494 requests.add(createRequest(channelsToSpec(2400, 2450), 10000, 0, 20, 495 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 496 497 mScheduler.setMaxBuckets(2); 498 mScheduler.setMaxChannelsPerBucket(2); 499 mScheduler.updateSchedule(requests); 500 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 501 502 assertEquals("base_period_ms", 10000, schedule.base_period_ms); 503 assertBuckets(schedule, 1); 504 for (ScanSettings request : requests) { 505 assertSettingsSatisfied(schedule, request, false, false); 506 } 507 508 assertEquals("scheduled bucket", 0, mScheduler.getScheduledBucket(requests.get(0))); 509 assertEquals("scheduled bucket", 0, mScheduler.getScheduledBucket(requests.get(1))); 510 511 Set<Integer> expectedBucketChannelSet = new ArraySet<>(); 512 expectedBucketChannelSet.add(2400); 513 expectedBucketChannelSet.add(2450); 514 assertBucketChannels(schedule.buckets[0], expectedBucketChannelSet); 515 } 516 517 /** 518 * Add 2 background scan requests with different time intervals, but one of the setting channels 519 * is partially contained in the other setting. Ensure that the requests are partially split 520 * across the lower time period bucket. 521 */ 522 @Test 523 public void optimalSchedulePartiallyCollapsesDuplicateChannels() { 524 ArrayList<ScanSettings> requests = new ArrayList<>(); 525 requests.add(createRequest(channelsToSpec(2400, 2450), 10000, 0, 20, 526 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 527 requests.add(createRequest(channelsToSpec(2400, 2450, 5175), 240000, 0, 20, 528 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 529 530 mScheduler.setMaxBuckets(2); 531 mScheduler.setMaxChannelsPerBucket(2); 532 mScheduler.updateSchedule(requests); 533 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 534 535 assertEquals("base_period_ms", 10000, schedule.base_period_ms); 536 assertBuckets(schedule, 2); 537 for (ScanSettings request : requests) { 538 assertSettingsSatisfied(schedule, request, false, false); 539 } 540 541 assertEquals("scheduled bucket", 0, mScheduler.getScheduledBucket(requests.get(0))); 542 assertEquals("scheduled bucket", 1, mScheduler.getScheduledBucket(requests.get(1))); 543 544 Set<Integer> expectedBucketChannelSet = new ArraySet<>(); 545 expectedBucketChannelSet.add(2400); 546 expectedBucketChannelSet.add(2450); 547 assertBucketChannels(schedule.buckets[0], expectedBucketChannelSet); 548 549 expectedBucketChannelSet.clear(); 550 expectedBucketChannelSet.add(5175); 551 assertBucketChannels(schedule.buckets[1], expectedBucketChannelSet); 552 } 553 554 /** 555 * Add 2 background scan requests with different time intervals, but one of the setting channels 556 * is partially contained in the 2 other settings. Ensure that the requests are partially split 557 * across the lower time period buckets. 558 */ 559 @Test 560 public void optimalSchedulePartiallyCollapsesDuplicateChannelsAcrossMultipleBuckets() { 561 ArrayList<ScanSettings> requests = new ArrayList<>(); 562 requests.add(createRequest(channelsToSpec(2400, 2450), 10000, 0, 20, 563 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 564 requests.add(createRequest(channelsToSpec(2400, 2450, 5175), 30000, 0, 20, 565 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 566 requests.add(createRequest(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, 240000, 0, 20, 567 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 568 569 mScheduler.setMaxBuckets(3); 570 mScheduler.updateSchedule(requests); 571 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 572 573 assertEquals("base_period_ms", 10000, schedule.base_period_ms); 574 assertBuckets(schedule, 3); 575 for (ScanSettings request : requests) { 576 assertSettingsSatisfied(schedule, request, false, false); 577 } 578 579 assertEquals("scheduled bucket", 0, mScheduler.getScheduledBucket(requests.get(0))); 580 assertEquals("scheduled bucket", 1, mScheduler.getScheduledBucket(requests.get(1))); 581 assertEquals("scheduled bucket", 2, mScheduler.getScheduledBucket(requests.get(2))); 582 583 Set<Integer> expectedBucketChannelSet = new ArraySet<>(); 584 expectedBucketChannelSet.add(2400); 585 expectedBucketChannelSet.add(2450); 586 assertBucketChannels(schedule.buckets[0], expectedBucketChannelSet); 587 588 expectedBucketChannelSet.clear(); 589 expectedBucketChannelSet.add(5175); 590 assertBucketChannels(schedule.buckets[1], expectedBucketChannelSet); 591 592 KnownBandsChannelCollection collection = mChannelHelper.createChannelCollection(); 593 collection.addBand(WifiScanner.WIFI_BAND_BOTH_WITH_DFS); 594 expectedBucketChannelSet = collection.getAllChannels(); 595 expectedBucketChannelSet.remove(5175); 596 expectedBucketChannelSet.remove(2400); 597 expectedBucketChannelSet.remove(2450); 598 assertBucketChannels(schedule.buckets[2], expectedBucketChannelSet); 599 } 600 601 /** 602 * Add 2 background scan requests with different time intervals, but one of the setting channels 603 * is partially contained in the 2 other settings. Ensure that the requests are partially split 604 * across the lower time period buckets and the last bucket is split into 2 because the 605 * channel list does not fit into a single bucket. 606 */ 607 @Test 608 public void optimalSchedulePartiallyCollapsesDuplicateChannelsWithSplitBuckets() { 609 ArrayList<ScanSettings> requests = new ArrayList<>(); 610 requests.add(createRequest(channelsToSpec(2400, 2450), 10000, 0, 20, 611 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 612 requests.add(createRequest(channelsToSpec(2400, 2450, 5175), 30000, 0, 20, 613 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 614 requests.add(createRequest(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, 240000, 0, 20, 615 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 616 617 mScheduler.setMaxBuckets(5); 618 mScheduler.setMaxChannelsPerBucket(2); 619 mScheduler.updateSchedule(requests); 620 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 621 622 assertEquals("base_period_ms", 10000, schedule.base_period_ms); 623 assertBuckets(schedule, 4); 624 for (ScanSettings request : requests) { 625 assertSettingsSatisfied(schedule, request, false, false); 626 } 627 628 assertEquals("scheduled bucket", 0, mScheduler.getScheduledBucket(requests.get(0))); 629 assertEquals("scheduled bucket", 1, mScheduler.getScheduledBucket(requests.get(1))); 630 assertEquals("scheduled bucket", 2, mScheduler.getScheduledBucket(requests.get(2))); 631 632 Set<Integer> expectedBucketChannelSet = new ArraySet<>(); 633 expectedBucketChannelSet.add(2400); 634 expectedBucketChannelSet.add(2450); 635 assertBucketChannels(schedule.buckets[0], expectedBucketChannelSet); 636 637 expectedBucketChannelSet.clear(); 638 expectedBucketChannelSet.add(5175); 639 assertBucketChannels(schedule.buckets[1], expectedBucketChannelSet); 640 641 KnownBandsChannelCollection collection = mChannelHelper.createChannelCollection(); 642 collection.addBand(WifiScanner.WIFI_BAND_BOTH_WITH_DFS); 643 expectedBucketChannelSet = collection.getAllChannels(); 644 expectedBucketChannelSet.remove(5175); 645 expectedBucketChannelSet.remove(2400); 646 expectedBucketChannelSet.remove(2450); 647 // Check if the combined channel set matches what we expect 648 Set<Integer> combinedBucketChannelSet = getAllChannels(schedule.buckets[2]); 649 combinedBucketChannelSet.addAll(getAllChannels(schedule.buckets[3])); 650 assertChannels(combinedBucketChannelSet, expectedBucketChannelSet); 651 } 652 653 /** 654 * Add 2 background scan requests with different time intervals, but one of the setting channels 655 * is totally contained in the other setting. Ensure that the requests are collapsed into a 656 * common bucket with the lower time period setting. 657 * This is done with NoBandChannelHelper. 658 */ 659 @Test 660 public void optimalScheduleFullyCollapsesDuplicateChannelsInBandWithNoBandChannelHelper() { 661 BackgroundScanScheduler scheduler = createSchedulerWithNoBandChannelHelper(); 662 663 ArrayList<ScanSettings> requests = new ArrayList<>(); 664 requests.add(createRequest(channelsToSpec(2400, 2450), 160000, 0, 20, 665 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 666 requests.add(createRequest(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, 10000, 0, 20, 667 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 668 669 scheduler.setMaxBuckets(2); 670 scheduler.setMaxChannelsPerBucket(2); 671 scheduler.updateSchedule(requests); 672 WifiNative.ScanSettings schedule = scheduler.getSchedule(); 673 674 assertEquals("base_period_ms", 10000, schedule.base_period_ms); 675 assertBuckets(schedule, 1); 676 677 assertEquals("scheduled bucket", 0, scheduler.getScheduledBucket(requests.get(0))); 678 assertEquals("scheduled bucket", 0, scheduler.getScheduledBucket(requests.get(1))); 679 680 assertEquals("band", schedule.buckets[0].band, WifiScanner.WIFI_BAND_BOTH_WITH_DFS); 681 } 682 683 /** 684 * Add 2 background scan requests with different time intervals, but one of the setting channels 685 * is partially contained in the other setting. Ensure that the requests are partially split 686 * across the lower time period bucket. 687 */ 688 @Test 689 public void optimalSchedulePartiallyCollapsesDuplicateChannelsWithNoBandChannelHelper() { 690 BackgroundScanScheduler scheduler = createSchedulerWithNoBandChannelHelper(); 691 692 ArrayList<ScanSettings> requests = new ArrayList<>(); 693 requests.add(createRequest(channelsToSpec(2400, 2450), 10000, 0, 20, 694 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 695 requests.add(createRequest(channelsToSpec(2400, 2450, 5175), 240000, 0, 20, 696 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 697 698 scheduler.setMaxBuckets(2); 699 scheduler.setMaxChannelsPerBucket(3); 700 scheduler.updateSchedule(requests); 701 WifiNative.ScanSettings schedule = scheduler.getSchedule(); 702 703 assertEquals("base_period_ms", 10000, schedule.base_period_ms); 704 assertBuckets(schedule, 2); 705 706 assertEquals("scheduled bucket", 0, scheduler.getScheduledBucket(requests.get(0))); 707 assertEquals("scheduled bucket", 1, scheduler.getScheduledBucket(requests.get(1))); 708 709 Set<Integer> expectedBucketChannelSet = new ArraySet<>(); 710 expectedBucketChannelSet.add(2400); 711 expectedBucketChannelSet.add(2450); 712 assertBucketChannels(schedule.buckets[0], expectedBucketChannelSet); 713 714 expectedBucketChannelSet.clear(); 715 expectedBucketChannelSet.add(5175); 716 assertBucketChannels(schedule.buckets[1], expectedBucketChannelSet); 717 } 718 719 /** 720 * Add 2 background scan requests with the second scan request having channels more than the 721 * max, ensure that the last bucket is split. 722 */ 723 @Test 724 public void optimalScheduleShouldSplitBucketsWithNoBandChannelHelper() { 725 BackgroundScanScheduler scheduler = createSchedulerWithNoBandChannelHelper(); 726 727 ArrayList<ScanSettings> requests = new ArrayList<>(); 728 requests.add(createRequest(channelsToSpec(2400, 2450), 10000, 0, 20, 729 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 730 requests.add(createRequest(channelsToSpec(5150, 5175, 5600, 5650), 240000, 0, 20, 731 WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); 732 733 scheduler.setMaxBuckets(3); 734 scheduler.setMaxChannelsPerBucket(2); 735 scheduler.updateSchedule(requests); 736 WifiNative.ScanSettings schedule = scheduler.getSchedule(); 737 738 assertEquals("base_period_ms", 10000, schedule.base_period_ms); 739 assertBuckets(schedule, 3); 740 741 assertEquals("scheduled bucket", 0, scheduler.getScheduledBucket(requests.get(0))); 742 assertEquals("scheduled bucket", 1, scheduler.getScheduledBucket(requests.get(1))); 743 744 Set<Integer> expectedBucketChannelSet = new ArraySet<>(); 745 expectedBucketChannelSet.add(2400); 746 expectedBucketChannelSet.add(2450); 747 assertBucketChannels(schedule.buckets[0], expectedBucketChannelSet); 748 749 expectedBucketChannelSet.clear(); 750 expectedBucketChannelSet.add(5150); 751 expectedBucketChannelSet.add(5175); 752 assertBucketChannels(schedule.buckets[1], expectedBucketChannelSet); 753 754 expectedBucketChannelSet.clear(); 755 expectedBucketChannelSet.add(5600); 756 expectedBucketChannelSet.add(5650); 757 assertBucketChannels(schedule.buckets[2], expectedBucketChannelSet); 758 } 759 760 protected Set<Integer> getAllChannels(BucketSettings bucket) { 761 KnownBandsChannelCollection collection = mChannelHelper.createChannelCollection(); 762 collection.addChannels(bucket); 763 return collection.getAllChannels(); 764 } 765 766 protected Set<Integer> getAllChannels(WifiScanner.ScanSettings settings) { 767 KnownBandsChannelCollection collection = mChannelHelper.createChannelCollection(); 768 collection.addChannels(settings); 769 return collection.getAllChannels(); 770 } 771 772 public void scheduleAndTestExactRequest(ScanSettings settings) { 773 Collection<ScanSettings> requests = new ArrayList<>(); 774 requests.add(settings); 775 776 mScheduler.updateSchedule(requests); 777 WifiNative.ScanSettings schedule = mScheduler.getSchedule(); 778 779 int expectedPeriod = computeExpectedPeriod(settings.periodInMs); 780 NativeScanSettingsBuilder expectedBuilder = new NativeScanSettingsBuilder() 781 .withBasePeriod(expectedPeriod) 782 .withMaxApPerScan(settings.numBssidsPerScan == 0 783 ? DEFAULT_MAX_AP_PER_SCAN 784 : settings.numBssidsPerScan) 785 .withMaxScansToCache(settings.maxScansToCache == 0 786 ? DEFAULT_MAX_BATCH 787 : settings.maxScansToCache); 788 789 if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { 790 expectedBuilder.addBucketWithChannels(expectedPeriod, settings.reportEvents, 791 settings.channels); 792 } else { 793 expectedBuilder.addBucketWithBand(expectedPeriod, settings.reportEvents, settings.band); 794 } 795 assertNativeScanSettingsEquals(expectedBuilder.build(), schedule); 796 } 797 798 private void assertBuckets(WifiNative.ScanSettings schedule, int numBuckets) { 799 assertEquals("num_buckets", numBuckets, schedule.num_buckets); 800 assertNotNull("buckets was null", schedule.buckets); 801 assertEquals("num_buckets and actual buckets", schedule.num_buckets, 802 schedule.buckets.length); 803 for (int i = 0; i < numBuckets; i++) { 804 assertNotNull("bucket[" + i + "] was null", schedule.buckets[i]); 805 if (schedule.buckets[i].band == WifiScanner.WIFI_BAND_UNSPECIFIED) { 806 assertTrue("num channels <= 0", schedule.buckets[i].num_channels > 0); 807 assertTrue("bucket channels > max channels", 808 schedule.buckets[i].num_channels <= mScheduler.getMaxChannelsPerBucket()); 809 assertNotNull("Channels was null", schedule.buckets[i].channels); 810 for (int c = 0; c < schedule.buckets[i].num_channels; c++) { 811 assertNotNull("Channel was null", schedule.buckets[i].channels[c]); 812 } 813 } else { 814 assertTrue("Invalid band: " + schedule.buckets[i].band, 815 schedule.buckets[i].band > WifiScanner.WIFI_BAND_UNSPECIFIED 816 && schedule.buckets[i].band <= WifiScanner.WIFI_BAND_BOTH_WITH_DFS); 817 } 818 } 819 } 820 821 private void assertSettingsSatisfied(WifiNative.ScanSettings schedule, 822 ScanSettings settings, boolean bucketsLimited, boolean exactPeriod) { 823 assertTrue("bssids per scan: " + schedule.max_ap_per_scan + " /<= " 824 + settings.numBssidsPerScan, 825 schedule.max_ap_per_scan <= settings.numBssidsPerScan); 826 827 if (settings.maxScansToCache > 0) { 828 assertTrue("scans to cache: " + schedule.report_threshold_num_scans + " /<= " 829 + settings.maxScansToCache, 830 schedule.report_threshold_num_scans <= settings.maxScansToCache); 831 } 832 833 Set<Integer> channelSet = getAllChannels(settings); 834 835 StringBuilder ignoreString = new StringBuilder(); 836 837 KnownBandsChannelCollection scheduleChannels = mChannelHelper.createChannelCollection(); 838 for (int b = 0; b < schedule.num_buckets; b++) { 839 BucketSettings bucket = schedule.buckets[b]; 840 if ((settings.reportEvents & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) != 0) { 841 if ((bucket.report_events & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) == 0) { 842 ignoreString 843 .append(" ") 844 .append(getAllChannels(bucket)) 845 .append("=after_each_scan:") 846 .append(bucket.report_events & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) 847 .append("!=") 848 .append(settings.reportEvents 849 & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); 850 continue; 851 } 852 } 853 if ((settings.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) { 854 if ((bucket.report_events & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) == 0) { 855 ignoreString 856 .append(" ") 857 .append(getAllChannels(bucket)) 858 .append("=full_result:") 859 .append(bucket.report_events 860 & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) 861 .append("!=") 862 .append(settings.reportEvents 863 & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT); 864 continue; 865 } 866 } 867 if ((settings.reportEvents & WifiScanner.REPORT_EVENT_NO_BATCH) == 0) { 868 if ((bucket.report_events & WifiScanner.REPORT_EVENT_NO_BATCH) != 0) { 869 ignoreString 870 .append(" ") 871 .append(getAllChannels(bucket)) 872 .append("=no_batch:") 873 .append(bucket.report_events & WifiScanner.REPORT_EVENT_NO_BATCH) 874 .append("!=") 875 .append(settings.reportEvents & WifiScanner.REPORT_EVENT_NO_BATCH); 876 continue; 877 } 878 } 879 int expectedPeriod; 880 881 if (settings.maxPeriodInMs != 0 && settings.periodInMs != settings.maxPeriodInMs) { 882 // exponential back off scan 883 expectedPeriod = settings.periodInMs; 884 } else { 885 if (bucketsLimited) { 886 expectedPeriod = computeExpectedPeriod(settings.periodInMs, schedule); 887 } else { 888 expectedPeriod = computeExpectedPeriod(settings.periodInMs); 889 } 890 } 891 892 if (exactPeriod) { 893 if (bucket.period_ms != expectedPeriod) { 894 ignoreString 895 .append(" ") 896 .append(getAllChannels(bucket)) 897 .append("=period:") 898 .append(bucket.period_ms) 899 .append("!=") 900 .append(settings.periodInMs); 901 continue; 902 } 903 } else { 904 if (bucket.period_ms > expectedPeriod) { 905 ignoreString 906 .append(" ") 907 .append(getAllChannels(bucket)) 908 .append("=period:") 909 .append(bucket.period_ms) 910 .append(">") 911 .append(settings.periodInMs); 912 continue; 913 } 914 } 915 scheduleChannels.addChannels(bucket); 916 } 917 918 assertTrue("expected that " + scheduleChannels.getAllChannels() + " contained " 919 + channelSet + ", Channel ignore reasons:" + ignoreString.toString(), 920 scheduleChannels.getAllChannels().containsAll(channelSet)); 921 } 922 923 private void assertBucketChannels(BucketSettings bucket, Set<Integer> expectedChannelSet) { 924 Set<Integer> bucketChannelSet = getAllChannels(bucket); 925 assertChannels(bucketChannelSet, expectedChannelSet); 926 } 927 928 private void assertChannels(Set<Integer> channelSet, Set<Integer> expectedChannelSet) { 929 assertTrue("expected that " + channelSet + " contained " 930 + expectedChannelSet, channelSet.containsAll(expectedChannelSet)); 931 } 932 933 private BackgroundScanScheduler createSchedulerWithNoBandChannelHelper() { 934 NoBandChannelHelper channelHelper = new NoBandChannelHelper(); 935 BackgroundScanScheduler scheduler = new BackgroundScanScheduler(channelHelper); 936 scheduler.setMaxBuckets(DEFAULT_MAX_BUCKETS); 937 scheduler.setMaxChannelsPerBucket(DEFAULT_MAX_CHANNELS_PER_BUCKET); 938 scheduler.setMaxBatch(DEFAULT_MAX_BATCH); 939 scheduler.setMaxApPerScan(DEFAULT_MAX_AP_PER_SCAN); 940 return scheduler; 941 } 942 943 private static int[] getPredefinedBuckets() { 944 try { 945 Field f = BackgroundScanScheduler.class.getDeclaredField("PREDEFINED_BUCKET_PERIODS"); 946 f.setAccessible(true); 947 return (int[]) f.get(null); 948 } catch (Exception e) { 949 throw new RuntimeException("Could not get predefined buckets", e); 950 } 951 } 952 private static final int[] PREDEFINED_BUCKET_PERIODS = getPredefinedBuckets(); 953 954 // find closest bucket period to the requested period 955 private static int computeExpectedPeriod(int requestedPeriod) { 956 int period = 0; 957 int minDiff = Integer.MAX_VALUE; 958 for (int bucketPeriod : PREDEFINED_BUCKET_PERIODS) { 959 int diff = Math.abs(bucketPeriod - requestedPeriod); 960 if (diff < minDiff) { 961 minDiff = diff; 962 period = bucketPeriod; 963 } 964 } 965 return period; 966 } 967 968 // find closest bucket period to the requested period that exists in the schedule 969 private static int computeExpectedPeriod(int requestedPeriod, 970 WifiNative.ScanSettings schedule) { 971 int period = 0; 972 int minDiff = Integer.MAX_VALUE; 973 for (int i = 0; i < schedule.num_buckets; ++i) { 974 int bucketPeriod = schedule.buckets[i].period_ms; 975 int diff = Math.abs(bucketPeriod - requestedPeriod); 976 if (diff < minDiff) { 977 minDiff = diff; 978 period = bucketPeriod; 979 } 980 } 981 return period; 982 } 983} 984