| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.wifi.scanner; |
| |
| import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder; |
| import static com.android.server.wifi.ScanTestUtil.assertNativeScanSettingsEquals; |
| import static com.android.server.wifi.ScanTestUtil.channelsToSpec; |
| import static com.android.server.wifi.ScanTestUtil.createRequest; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.mockito.Mockito.validateMockitoUsage; |
| |
| import android.net.wifi.WifiScanner; |
| import android.net.wifi.WifiScanner.ScanSettings; |
| import android.util.ArraySet; |
| |
| import androidx.test.filters.SmallTest; |
| |
| import com.android.server.wifi.WifiBaseTest; |
| import com.android.server.wifi.WifiNative; |
| import com.android.server.wifi.WifiNative.BucketSettings; |
| import com.android.server.wifi.scanner.KnownBandsChannelHelper.KnownBandsChannelCollection; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import java.lang.reflect.Field; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Set; |
| |
| /** |
| * Unit tests for {@link com.android.server.wifi.scanner.BackgroundScanScheduler}. |
| */ |
| @SmallTest |
| public class BackgroundScanSchedulerTest extends WifiBaseTest { |
| |
| private static final int DEFAULT_MAX_BUCKETS = 9; |
| private static final int DEFAULT_MAX_CHANNELS_PER_BUCKET = 23; |
| private static final int DEFAULT_MAX_BATCH = 11; |
| private static final int DEFAULT_MAX_AP_PER_SCAN = 33; |
| |
| private KnownBandsChannelHelper mChannelHelper; |
| private BackgroundScanScheduler mScheduler; |
| |
| @Before |
| public void setUp() throws Exception { |
| mChannelHelper = new PresetKnownBandsChannelHelper( |
| new int[]{2400, 2450}, |
| new int[]{5150, 5175}, |
| new int[]{5600, 5650, 5660}, |
| new int[]{5945, 5985}, |
| new int[]{58320, 60480}); |
| mScheduler = new BackgroundScanScheduler(mChannelHelper); |
| mScheduler.setMaxBuckets(DEFAULT_MAX_BUCKETS); |
| mScheduler.setMaxChannelsPerBucket(DEFAULT_MAX_CHANNELS_PER_BUCKET); |
| mScheduler.setMaxBatch(DEFAULT_MAX_BATCH); |
| mScheduler.setMaxApPerScan(DEFAULT_MAX_AP_PER_SCAN); |
| } |
| |
| @After |
| public void cleanup() { |
| validateMockitoUsage(); |
| } |
| |
| @Test |
| public void noRequest() { |
| Collection<ScanSettings> requests = Collections.emptyList(); |
| |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals(30000, schedule.base_period_ms); |
| assertBuckets(schedule, 0); |
| } |
| |
| @Test |
| public void singleRequest() { |
| Collection<ScanSettings> requests = Collections.singleton(createRequest( |
| WifiScanner.WIFI_BAND_BOTH, 30000, 0, 20, |
| WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT |
| )); |
| |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals(30000, schedule.base_period_ms); |
| assertBuckets(schedule, 1); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, false, true); |
| } |
| } |
| |
| @Test |
| public void singleRequestWithoutPredefinedBucket() { |
| Collection<ScanSettings> requests = Collections.singleton(createRequest( |
| WifiScanner.WIFI_BAND_BOTH, 7500, 0, 20, |
| WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT |
| )); |
| |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 10000, schedule.base_period_ms); |
| assertBuckets(schedule, 1); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, false, true); |
| } |
| } |
| |
| @Test |
| public void fewRequests() { |
| Collection<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(WifiScanner.WIFI_BAND_BOTH, 30000, 0, 20, |
| WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); |
| requests.add(createRequest(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY, 14000, 0, 20, |
| WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); |
| |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 10000, schedule.base_period_ms); |
| assertBuckets(schedule, 2); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, false, true); |
| } |
| } |
| |
| @Test |
| public void manyRequests() { |
| Collection<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(WifiScanner.WIFI_BAND_BOTH, 30000, 0, 20, |
| WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); |
| requests.add(createRequest(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY, 15000, 0, 20, |
| WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); |
| requests.add(createRequest(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY, 10000, 0, 20, |
| WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); |
| |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 10000, schedule.base_period_ms); |
| assertBuckets(schedule, 2); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, false, false); |
| } |
| } |
| |
| @Test |
| public void requestsWithNoPeriodCommonDenominator() { |
| ArrayList<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(WifiScanner.WIFI_BAND_BOTH, 299999, 0, 20, |
| WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); |
| requests.add(createRequest(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY, 10500, 0, 20, |
| WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); |
| |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 10000, schedule.base_period_ms); |
| assertBuckets(schedule, 2); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, false, true); |
| } |
| } |
| |
| @Test |
| public void manyRequestsDifferentReportScans() { |
| Collection<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(5175), 60000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL)); |
| requests.add(createRequest(channelsToSpec(2400), 60000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(channelsToSpec(2450), 60000, 0, 20, |
| WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); |
| requests.add(createRequest(channelsToSpec(5150), 60000, 0, 20, |
| WifiScanner.REPORT_EVENT_NO_BATCH)); |
| |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 60000, schedule.base_period_ms); |
| assertBuckets(schedule, 1); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, false, true); |
| } |
| } |
| |
| @Test |
| public void exceedMaxBatch() { |
| Collection<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(5175), 30000, 10, 20, |
| WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL)); |
| |
| mScheduler.setMaxBatch(5); |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 30000, schedule.base_period_ms); |
| assertBuckets(schedule, 1); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, false, true); |
| } |
| assertEquals("maxScansToCache", 5, schedule.report_threshold_num_scans); |
| } |
| |
| @Test |
| public void defaultMaxBatch() { |
| Collection<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(5175), 60000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL)); |
| |
| mScheduler.setMaxBatch(6); |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 60000, schedule.base_period_ms); |
| assertBuckets(schedule, 1); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, false, true); |
| } |
| assertEquals("maxScansToCache", 6, schedule.report_threshold_num_scans); |
| } |
| |
| @Test |
| public void exceedMaxAps() { |
| Collection<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(5175), 30000, 10, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| |
| mScheduler.setMaxApPerScan(5); |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("maxScansToCache", 5, schedule.max_ap_per_scan); |
| } |
| |
| @Test |
| public void defaultMaxAps() { |
| Collection<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(5175), 30000, 10, 0, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| |
| mScheduler.setMaxApPerScan(8); |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("maxApsPerScan", 8, schedule.max_ap_per_scan); |
| } |
| |
| @Test |
| public void optimalScheduleExceedsNumberOfAvailableBuckets() { |
| ArrayList<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(2400), 30000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(channelsToSpec(2450), 10000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(channelsToSpec(5150), 120000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| |
| mScheduler.setMaxBuckets(2); |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 30000, schedule.base_period_ms); |
| assertBuckets(schedule, 2); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, true, true); |
| } |
| } |
| |
| @Test |
| public void optimalScheduleExceedsNumberOfAvailableBuckets2() { |
| ArrayList<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(2400), 30000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(channelsToSpec(2450), 60000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(channelsToSpec(5150), 3840000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| |
| mScheduler.setMaxBuckets(2); |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 30000, schedule.base_period_ms); |
| assertBuckets(schedule, 2); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, true, true); |
| } |
| } |
| |
| /** |
| * Ensure that a channel request is placed in the bucket closest to the original |
| * period and not the bucket it is initially placed in. Here the 5 min period is |
| * initially placed in the 240s bucket, but that bucket is eliminated because it |
| * would be a 7th bucket. This test ensures that the request is placed in the 480s |
| * bucket and not the 120s bucket. |
| */ |
| @Test |
| public void optimalScheduleExceedsNumberOfAvailableBucketsClosestToOriginal() { |
| ArrayList<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(2400), 30 * 1000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(channelsToSpec(2450), 120 * 1000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(channelsToSpec(5150), 480 * 1000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(channelsToSpec(5175), 10 * 1000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(channelsToSpec(5600), 60 * 1000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(channelsToSpec(5650), 1920 * 1000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| |
| requests.add(createRequest(channelsToSpec(5660), 300 * 1000, 0, 20, // 5 min |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| |
| mScheduler.setMaxBuckets(6); |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 10000, schedule.base_period_ms); |
| assertBuckets(schedule, 6); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, true, true); |
| } |
| } |
| |
| @Test |
| public void optimalScheduleExceedsMaxChannelsOnSingleBand() { |
| ArrayList<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(2400, 2450), 30000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| |
| mScheduler.setMaxBuckets(2); |
| mScheduler.setMaxChannelsPerBucket(1); |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 30000, schedule.base_period_ms); |
| assertBuckets(schedule, 2); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, true, true); |
| } |
| } |
| |
| @Test |
| public void optimalScheduleExceedsMaxChannelsOnMultipleBands() { |
| ArrayList<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(2400, 2450, 5150), 30000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| |
| mScheduler.setMaxBuckets(2); |
| mScheduler.setMaxChannelsPerBucket(2); |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 30000, schedule.base_period_ms); |
| assertBuckets(schedule, 2); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, true, true); |
| } |
| } |
| |
| @Test |
| public void optimalScheduleExceedsMaxChannelsOnMultipleBandsFromMultipleRequests() { |
| ArrayList<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(2400, 2450), 30000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(WifiScanner.WIFI_BAND_5_GHZ, 30000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| |
| mScheduler.setMaxBuckets(2); |
| mScheduler.setMaxChannelsPerBucket(2); |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 30000, schedule.base_period_ms); |
| assertBuckets(schedule, 2); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, true, true); |
| } |
| } |
| |
| @Test |
| public void exactRequests() { |
| scheduleAndTestExactRequest(createRequest(WifiScanner.WIFI_BAND_BOTH, 30000, 0, |
| 20, WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL)); |
| scheduleAndTestExactRequest(createRequest(WifiScanner.WIFI_BAND_5_GHZ, 60000, 3, |
| 13, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| scheduleAndTestExactRequest(createRequest(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY, 10000, 2, |
| 10, WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)); |
| scheduleAndTestExactRequest(createRequest(WifiScanner.WIFI_BAND_BOTH, 25000, 0, |
| 10, WifiScanner.REPORT_EVENT_NO_BATCH)); |
| scheduleAndTestExactRequest(createRequest(WifiScanner.WIFI_BAND_BOTH, 25000, 3, |
| 0, WifiScanner.REPORT_EVENT_NO_BATCH)); |
| scheduleAndTestExactRequest(createRequest(channelsToSpec(2400, 5175, 5650) , 25000, 3, |
| 0, WifiScanner.REPORT_EVENT_NO_BATCH)); |
| } |
| |
| @Test |
| public void singleExponentialBackOffRequest() { |
| Collection<ScanSettings> requests = Collections.singleton(createRequest( |
| WifiScanner.SCAN_TYPE_LOW_LATENCY, WifiScanner.WIFI_BAND_BOTH, |
| 30000, 160000, 2, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN |
| )); |
| |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals(30000, schedule.base_period_ms); |
| assertBuckets(schedule, 1); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, false, true); |
| } |
| } |
| |
| @Test |
| public void exponentialBackOffAndRegularRequests() { |
| Collection<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(WifiScanner.SCAN_TYPE_LOW_LATENCY, WifiScanner.WIFI_BAND_BOTH, |
| 30000, 200000, 1, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(channelsToSpec(5175), 30000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL)); |
| |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 30000, schedule.base_period_ms); |
| assertBuckets(schedule, 2); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, false, true); |
| } |
| } |
| |
| /** |
| * Add 2 background scan requests with different time intervals, but one of the setting channels |
| * is totally contained in the other setting. Ensure that the requests are collapsed into a |
| * common bucket with the lower time period setting. |
| */ |
| @Test |
| public void optimalScheduleFullyCollapsesDuplicateChannelsInBand() { |
| ArrayList<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(2400, 2450), 240000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(WifiScanner.WIFI_BAND_24_GHZ, 10000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| |
| mScheduler.setMaxBuckets(2); |
| mScheduler.setMaxChannelsPerBucket(2); |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 10000, schedule.base_period_ms); |
| assertBuckets(schedule, 1); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, false, false); |
| } |
| |
| assertEquals("scheduled bucket", 0, mScheduler.getScheduledBucket(requests.get(0))); |
| assertEquals("scheduled bucket", 0, mScheduler.getScheduledBucket(requests.get(1))); |
| |
| KnownBandsChannelCollection collection = mChannelHelper.createChannelCollection(); |
| collection.addBand(WifiScanner.WIFI_BAND_24_GHZ); |
| Set<Integer> expectedBucketChannelSet = collection.getAllChannels(); |
| assertBucketChannels(schedule.buckets[0], expectedBucketChannelSet); |
| } |
| |
| /** |
| * Add 2 background scan requests with different time intervals, but one of the setting channels |
| * is totally contained in the other setting. Ensure that the requests are collapsed into a |
| * common bucket with the lower time period setting. |
| */ |
| @Test |
| public void optimalScheduleFullyCollapsesDuplicateChannels() { |
| ArrayList<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(2400, 2450), 240000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(channelsToSpec(2400, 2450), 10000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| |
| mScheduler.setMaxBuckets(2); |
| mScheduler.setMaxChannelsPerBucket(2); |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 10000, schedule.base_period_ms); |
| assertBuckets(schedule, 1); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, false, false); |
| } |
| |
| assertEquals("scheduled bucket", 0, mScheduler.getScheduledBucket(requests.get(0))); |
| assertEquals("scheduled bucket", 0, mScheduler.getScheduledBucket(requests.get(1))); |
| |
| Set<Integer> expectedBucketChannelSet = new ArraySet<>(); |
| expectedBucketChannelSet.add(2400); |
| expectedBucketChannelSet.add(2450); |
| assertBucketChannels(schedule.buckets[0], expectedBucketChannelSet); |
| } |
| |
| /** |
| * Add 2 background scan requests with different time intervals, but one of the setting channels |
| * is partially contained in the other setting. Ensure that the requests are partially split |
| * across the lower time period bucket. |
| */ |
| @Test |
| public void optimalSchedulePartiallyCollapsesDuplicateChannels() { |
| ArrayList<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(2400, 2450), 10000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(channelsToSpec(2400, 2450, 5175), 240000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| |
| mScheduler.setMaxBuckets(2); |
| mScheduler.setMaxChannelsPerBucket(2); |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 10000, schedule.base_period_ms); |
| assertBuckets(schedule, 2); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, false, false); |
| } |
| |
| assertEquals("scheduled bucket", 0, mScheduler.getScheduledBucket(requests.get(0))); |
| assertEquals("scheduled bucket", 1, mScheduler.getScheduledBucket(requests.get(1))); |
| |
| Set<Integer> expectedBucketChannelSet = new ArraySet<>(); |
| expectedBucketChannelSet.add(2400); |
| expectedBucketChannelSet.add(2450); |
| assertBucketChannels(schedule.buckets[0], expectedBucketChannelSet); |
| |
| expectedBucketChannelSet.clear(); |
| expectedBucketChannelSet.add(5175); |
| assertBucketChannels(schedule.buckets[1], expectedBucketChannelSet); |
| } |
| |
| /** |
| * Add 2 background scan requests with different time intervals, but one of the setting channels |
| * is partially contained in the 2 other settings. Ensure that the requests are partially split |
| * across the lower time period buckets. |
| */ |
| @Test |
| public void optimalSchedulePartiallyCollapsesDuplicateChannelsAcrossMultipleBuckets() { |
| ArrayList<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(2400, 2450), 10000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(channelsToSpec(2400, 2450, 5175), 30000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(WifiScanner.WIFI_BAND_24_5_WITH_DFS_6_60_GHZ, 240000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| |
| mScheduler.setMaxBuckets(3); |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 10000, schedule.base_period_ms); |
| assertBuckets(schedule, 3); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, false, false); |
| } |
| |
| assertEquals("scheduled bucket", 0, mScheduler.getScheduledBucket(requests.get(0))); |
| assertEquals("scheduled bucket", 1, mScheduler.getScheduledBucket(requests.get(1))); |
| assertEquals("scheduled bucket", 2, mScheduler.getScheduledBucket(requests.get(2))); |
| |
| Set<Integer> expectedBucketChannelSet = new ArraySet<>(); |
| expectedBucketChannelSet.add(2400); |
| expectedBucketChannelSet.add(2450); |
| assertBucketChannels(schedule.buckets[0], expectedBucketChannelSet); |
| |
| expectedBucketChannelSet.clear(); |
| expectedBucketChannelSet.add(5175); |
| assertBucketChannels(schedule.buckets[1], expectedBucketChannelSet); |
| |
| KnownBandsChannelCollection collection = mChannelHelper.createChannelCollection(); |
| collection.addBand(WifiScanner.WIFI_BAND_24_5_WITH_DFS_6_60_GHZ); |
| expectedBucketChannelSet = collection.getAllChannels(); |
| expectedBucketChannelSet.remove(5175); |
| expectedBucketChannelSet.remove(2400); |
| expectedBucketChannelSet.remove(2450); |
| assertBucketChannels(schedule.buckets[2], expectedBucketChannelSet); |
| } |
| |
| /** |
| * Add 2 background scan requests with different time intervals, but one of the setting channels |
| * is partially contained in the 2 other settings. Ensure that the requests are partially split |
| * across the lower time period buckets and the last bucket is split into 2 because the |
| * channel list does not fit into a single bucket. |
| */ |
| @Test |
| public void optimalSchedulePartiallyCollapsesDuplicateChannelsWithSplitBuckets() { |
| ArrayList<ScanSettings> requests = new ArrayList<>(); |
| requests.add(createRequest(channelsToSpec(2400, 2450), 10000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(channelsToSpec(2400, 2450, 5175), 30000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| requests.add(createRequest(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, 240000, 0, 20, |
| WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)); |
| |
| mScheduler.setMaxBuckets(5); |
| mScheduler.setMaxChannelsPerBucket(2); |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| assertEquals("base_period_ms", 10000, schedule.base_period_ms); |
| assertBuckets(schedule, 4); |
| for (ScanSettings request : requests) { |
| assertSettingsSatisfied(schedule, request, false, false); |
| } |
| |
| assertEquals("scheduled bucket", 0, mScheduler.getScheduledBucket(requests.get(0))); |
| assertEquals("scheduled bucket", 1, mScheduler.getScheduledBucket(requests.get(1))); |
| assertEquals("scheduled bucket", 2, mScheduler.getScheduledBucket(requests.get(2))); |
| |
| Set<Integer> expectedBucketChannelSet = new ArraySet<>(); |
| expectedBucketChannelSet.add(2400); |
| expectedBucketChannelSet.add(2450); |
| assertBucketChannels(schedule.buckets[0], expectedBucketChannelSet); |
| |
| expectedBucketChannelSet.clear(); |
| expectedBucketChannelSet.add(5175); |
| assertBucketChannels(schedule.buckets[1], expectedBucketChannelSet); |
| |
| KnownBandsChannelCollection collection = mChannelHelper.createChannelCollection(); |
| collection.addBand(WifiScanner.WIFI_BAND_BOTH_WITH_DFS); |
| expectedBucketChannelSet = collection.getAllChannels(); |
| expectedBucketChannelSet.remove(5175); |
| expectedBucketChannelSet.remove(2400); |
| expectedBucketChannelSet.remove(2450); |
| // Check if the combined channel set matches what we expect |
| Set<Integer> combinedBucketChannelSet = getAllChannels(schedule.buckets[2]); |
| combinedBucketChannelSet.addAll(getAllChannels(schedule.buckets[3])); |
| assertChannels(combinedBucketChannelSet, expectedBucketChannelSet); |
| } |
| |
| protected Set<Integer> getAllChannels(BucketSettings bucket) { |
| KnownBandsChannelCollection collection = mChannelHelper.createChannelCollection(); |
| collection.addChannels(bucket); |
| return collection.getAllChannels(); |
| } |
| |
| protected Set<Integer> getAllChannels(WifiScanner.ScanSettings settings) { |
| KnownBandsChannelCollection collection = mChannelHelper.createChannelCollection(); |
| collection.addChannels(settings); |
| return collection.getAllChannels(); |
| } |
| |
| public void scheduleAndTestExactRequest(ScanSettings settings) { |
| Collection<ScanSettings> requests = new ArrayList<>(); |
| requests.add(settings); |
| |
| mScheduler.updateSchedule(requests); |
| WifiNative.ScanSettings schedule = mScheduler.getSchedule(); |
| |
| int expectedPeriod = computeExpectedPeriod(settings.periodInMs); |
| NativeScanSettingsBuilder expectedBuilder = new NativeScanSettingsBuilder() |
| .withBasePeriod(expectedPeriod) |
| .withMaxApPerScan(settings.numBssidsPerScan == 0 |
| ? DEFAULT_MAX_AP_PER_SCAN |
| : settings.numBssidsPerScan) |
| .withMaxScansToCache(settings.maxScansToCache == 0 |
| ? DEFAULT_MAX_BATCH |
| : settings.maxScansToCache); |
| |
| if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { |
| expectedBuilder.addBucketWithChannels(expectedPeriod, settings.reportEvents, |
| settings.channels); |
| } else { |
| expectedBuilder.addBucketWithBand(expectedPeriod, settings.reportEvents, settings.band); |
| } |
| assertNativeScanSettingsEquals(expectedBuilder.build(), schedule); |
| } |
| |
| private void assertBuckets(WifiNative.ScanSettings schedule, int numBuckets) { |
| assertEquals("num_buckets", numBuckets, schedule.num_buckets); |
| assertNotNull("buckets was null", schedule.buckets); |
| assertEquals("num_buckets and actual buckets", schedule.num_buckets, |
| schedule.buckets.length); |
| for (int i = 0; i < numBuckets; i++) { |
| assertNotNull("bucket[" + i + "] was null", schedule.buckets[i]); |
| if (schedule.buckets[i].band == WifiScanner.WIFI_BAND_UNSPECIFIED) { |
| assertTrue("num channels <= 0", schedule.buckets[i].num_channels > 0); |
| assertTrue("bucket channels > max channels", |
| schedule.buckets[i].num_channels <= mScheduler.getMaxChannelsPerBucket()); |
| assertNotNull("Channels was null", schedule.buckets[i].channels); |
| for (int c = 0; c < schedule.buckets[i].num_channels; c++) { |
| assertNotNull("Channel was null", schedule.buckets[i].channels[c]); |
| } |
| } else { |
| assertTrue("Invalid band: " + schedule.buckets[i].band, |
| schedule.buckets[i].band > WifiScanner.WIFI_BAND_UNSPECIFIED |
| && schedule.buckets[i].band |
| <= WifiScanner.WIFI_BAND_24_5_WITH_DFS_6_60_GHZ); |
| } |
| } |
| } |
| |
| private void assertSettingsSatisfied(WifiNative.ScanSettings schedule, |
| ScanSettings settings, boolean bucketsLimited, boolean exactPeriod) { |
| assertTrue("bssids per scan: " + schedule.max_ap_per_scan + " /<= " |
| + settings.numBssidsPerScan, |
| schedule.max_ap_per_scan <= settings.numBssidsPerScan); |
| |
| if (settings.maxScansToCache > 0) { |
| assertTrue("scans to cache: " + schedule.report_threshold_num_scans + " /<= " |
| + settings.maxScansToCache, |
| schedule.report_threshold_num_scans <= settings.maxScansToCache); |
| } |
| |
| Set<Integer> channelSet = getAllChannels(settings); |
| |
| StringBuilder ignoreString = new StringBuilder(); |
| |
| KnownBandsChannelCollection scheduleChannels = mChannelHelper.createChannelCollection(); |
| for (int b = 0; b < schedule.num_buckets; b++) { |
| BucketSettings bucket = schedule.buckets[b]; |
| if ((settings.reportEvents & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) != 0) { |
| if ((bucket.report_events & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) == 0) { |
| ignoreString |
| .append(" ") |
| .append(getAllChannels(bucket)) |
| .append("=after_each_scan:") |
| .append(bucket.report_events & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) |
| .append("!=") |
| .append(settings.reportEvents |
| & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN); |
| continue; |
| } |
| } |
| if ((settings.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) { |
| if ((bucket.report_events & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) == 0) { |
| ignoreString |
| .append(" ") |
| .append(getAllChannels(bucket)) |
| .append("=full_result:") |
| .append(bucket.report_events |
| & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) |
| .append("!=") |
| .append(settings.reportEvents |
| & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT); |
| continue; |
| } |
| } |
| if ((settings.reportEvents & WifiScanner.REPORT_EVENT_NO_BATCH) == 0) { |
| if ((bucket.report_events & WifiScanner.REPORT_EVENT_NO_BATCH) != 0) { |
| ignoreString |
| .append(" ") |
| .append(getAllChannels(bucket)) |
| .append("=no_batch:") |
| .append(bucket.report_events & WifiScanner.REPORT_EVENT_NO_BATCH) |
| .append("!=") |
| .append(settings.reportEvents & WifiScanner.REPORT_EVENT_NO_BATCH); |
| continue; |
| } |
| } |
| int expectedPeriod; |
| |
| if (settings.maxPeriodInMs != 0 && settings.periodInMs != settings.maxPeriodInMs) { |
| // exponential back off scan |
| expectedPeriod = settings.periodInMs; |
| } else { |
| if (bucketsLimited) { |
| expectedPeriod = computeExpectedPeriod(settings.periodInMs, schedule); |
| } else { |
| expectedPeriod = computeExpectedPeriod(settings.periodInMs); |
| } |
| } |
| |
| if (exactPeriod) { |
| if (bucket.period_ms != expectedPeriod) { |
| ignoreString |
| .append(" ") |
| .append(getAllChannels(bucket)) |
| .append("=period:") |
| .append(bucket.period_ms) |
| .append("!=") |
| .append(settings.periodInMs); |
| continue; |
| } |
| } else { |
| if (bucket.period_ms > expectedPeriod) { |
| ignoreString |
| .append(" ") |
| .append(getAllChannels(bucket)) |
| .append("=period:") |
| .append(bucket.period_ms) |
| .append(">") |
| .append(settings.periodInMs); |
| continue; |
| } |
| } |
| scheduleChannels.addChannels(bucket); |
| } |
| |
| assertTrue("expected that " + scheduleChannels.getAllChannels() + " contained " |
| + channelSet + ", Channel ignore reasons:" + ignoreString.toString(), |
| scheduleChannels.getAllChannels().containsAll(channelSet)); |
| } |
| |
| private void assertBucketChannels(BucketSettings bucket, Set<Integer> expectedChannelSet) { |
| Set<Integer> bucketChannelSet = getAllChannels(bucket); |
| assertChannels(bucketChannelSet, expectedChannelSet); |
| } |
| |
| private void assertChannels(Set<Integer> channelSet, Set<Integer> expectedChannelSet) { |
| assertTrue("expected that " + channelSet + " contained " |
| + expectedChannelSet, channelSet.containsAll(expectedChannelSet)); |
| } |
| |
| private static int[] getPredefinedBuckets() { |
| try { |
| Field f = BackgroundScanScheduler.class.getDeclaredField("PREDEFINED_BUCKET_PERIODS"); |
| f.setAccessible(true); |
| return (int[]) f.get(null); |
| } catch (Exception e) { |
| throw new RuntimeException("Could not get predefined buckets", e); |
| } |
| } |
| private static final int[] PREDEFINED_BUCKET_PERIODS = getPredefinedBuckets(); |
| |
| // find closest bucket period to the requested period |
| private static int computeExpectedPeriod(int requestedPeriod) { |
| int period = 0; |
| int minDiff = Integer.MAX_VALUE; |
| for (int bucketPeriod : PREDEFINED_BUCKET_PERIODS) { |
| int diff = Math.abs(bucketPeriod - requestedPeriod); |
| if (diff < minDiff) { |
| minDiff = diff; |
| period = bucketPeriod; |
| } |
| } |
| return period; |
| } |
| |
| // find closest bucket period to the requested period that exists in the schedule |
| private static int computeExpectedPeriod(int requestedPeriod, |
| WifiNative.ScanSettings schedule) { |
| int period = 0; |
| int minDiff = Integer.MAX_VALUE; |
| for (int i = 0; i < schedule.num_buckets; ++i) { |
| int bucketPeriod = schedule.buckets[i].period_ms; |
| int diff = Math.abs(bucketPeriod - requestedPeriod); |
| if (diff < minDiff) { |
| minDiff = diff; |
| period = bucketPeriod; |
| } |
| } |
| return period; |
| } |
| } |