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