blob: ac158592e1a085c86d488c7f2b94802b46c202fa [file] [log] [blame]
/*
* 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;
}
}