/* * Copyright (C) 2016 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 android.net.wifi.WifiScanner; import android.util.ArraySet; import com.android.server.wifi.WifiNative; import java.util.Set; /** * ChannelHelper offers an abstraction for channel manipulation utilities allowing operation to be * adjusted based on the amount of information known about the available channels. */ public abstract class ChannelHelper { // TODO: Currently this is simply an estimate and is used for both active and passive channels // scans. Eventually it should be split between passive and active and perhaps retrieved // from the driver. /** * The estimated period spent scanning each channel. This is used for estimating scan duration. */ public static final int SCAN_PERIOD_PER_CHANNEL_MS = 200; protected static final WifiScanner.ChannelSpec[] NO_CHANNELS = new WifiScanner.ChannelSpec[0]; /** * Create a new collection that can be used to store channels */ public abstract ChannelCollection createChannelCollection(); /** * Return true if the specified channel is expected for a scan with the given settings */ public abstract boolean settingsContainChannel(WifiScanner.ScanSettings settings, int channel); /** * Get the channels that are available for scanning on the supplied band. * This method may return empty if the information is not available. */ public abstract WifiScanner.ChannelSpec[] getAvailableScanChannels(int band); /** * Estimates the duration that the chip will spend scanning with the given settings */ public abstract int estimateScanDuration(WifiScanner.ScanSettings settings); /** * Update the channel information that this object has. The source of the update is * implementation dependent and may result in no change. Warning the behavior of a * ChannelCollection created using {@link #createChannelCollection createChannelCollection} is * undefined after calling this method until the {@link ChannelColleciton#clear() clear} method * is called on it. */ public void updateChannels() { // default implementation does nothing } /** * Object that supports accumulation of channels and bands */ public abstract class ChannelCollection { /** * Add a channel to the collection */ public abstract void addChannel(int channel); /** * Add all channels in the band to the collection */ public abstract void addBand(int band); /** * @return true if the collection contains the supplied channel */ public abstract boolean containsChannel(int channel); /** * @return true if the collection contains all the channels of the supplied band */ public abstract boolean containsBand(int band); /** * @return true if the collection contains some of the channels of the supplied band */ public abstract boolean partiallyContainsBand(int band); /** * @return true if the collection contains no channels */ public abstract boolean isEmpty(); /** * Remove all channels from the collection */ public abstract void clear(); /** * Retrieves a list of channels from the band which are missing in the channel collection. */ public abstract Set getMissingChannelsFromBand(int band); /** * Retrieves a list of channels from the band which are contained in the channel collection. */ public abstract Set getContainingChannelsFromBand(int band); /** * Gets a list of channels specified in the current channel collection. This will return * an empty set if an entire Band if specified or if the list is empty. */ public abstract Set getChannelSet(); /** * Add all channels in the ScanSetting to the collection */ public void addChannels(WifiScanner.ScanSettings scanSettings) { if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { for (int j = 0; j < scanSettings.channels.length; ++j) { addChannel(scanSettings.channels[j].frequency); } } else { addBand(scanSettings.band); } } /** * Add all channels in the BucketSettings to the collection */ public void addChannels(WifiNative.BucketSettings bucketSettings) { if (bucketSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { for (int j = 0; j < bucketSettings.channels.length; ++j) { addChannel(bucketSettings.channels[j].frequency); } } else { addBand(bucketSettings.band); } } /** * Checks if all channels in ScanSetting is in the collection */ public boolean containsSettings(WifiScanner.ScanSettings scanSettings) { if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { for (int j = 0; j < scanSettings.channels.length; ++j) { if (!containsChannel(scanSettings.channels[j].frequency)) { return false; } } return true; } else { return containsBand(scanSettings.band); } } /** * Checks if at least some of the channels in ScanSetting is in the collection */ public boolean partiallyContainsSettings(WifiScanner.ScanSettings scanSettings) { if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { for (int j = 0; j < scanSettings.channels.length; ++j) { if (containsChannel(scanSettings.channels[j].frequency)) { return true; } } return false; } else { return partiallyContainsBand(scanSettings.band); } } /** * Retrieves a list of missing channels in the collection from the provided settings. */ public Set getMissingChannelsFromSettings(WifiScanner.ScanSettings scanSettings) { if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { ArraySet missingChannels = new ArraySet<>(); for (int j = 0; j < scanSettings.channels.length; ++j) { if (!containsChannel(scanSettings.channels[j].frequency)) { missingChannels.add(scanSettings.channels[j].frequency); } } return missingChannels; } else { return getMissingChannelsFromBand(scanSettings.band); } } /** * Retrieves a list of containing channels in the collection from the provided settings. */ public Set getContainingChannelsFromSettings( WifiScanner.ScanSettings scanSettings) { if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { ArraySet containingChannels = new ArraySet<>(); for (int j = 0; j < scanSettings.channels.length; ++j) { if (containsChannel(scanSettings.channels[j].frequency)) { containingChannels.add(scanSettings.channels[j].frequency); } } return containingChannels; } else { return getContainingChannelsFromBand(scanSettings.band); } } /** * Store the channels in this collection in the supplied BucketSettings. If maxChannels is * exceeded or a band better describes the channels then a band is specified instead of a * channel list. */ public abstract void fillBucketSettings(WifiNative.BucketSettings bucket, int maxChannels); /** * Gets the list of channels that should be supplied to supplicant for a scan. Will either * be a collection of all channels or null if all channels should be scanned. */ public abstract Set getSupplicantScanFreqs(); } /* * Utility methods for converting band/channels to strings */ /** * Create a string representation of the channels in the ScanSettings. * If it contains a list of channels then the channels are returned, otherwise a string name of * the band is returned. */ public static String toString(WifiScanner.ScanSettings scanSettings) { if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { return toString(scanSettings.channels); } else { return toString(scanSettings.band); } } /** * Create a string representation of the channels in the BucketSettings. * If it contains a list of channels then the channels are returned, otherwise a string name of * the band is returned. */ public static String toString(WifiNative.BucketSettings bucketSettings) { if (bucketSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { return toString(bucketSettings.channels, bucketSettings.num_channels); } else { return toString(bucketSettings.band); } } private static String toString(WifiScanner.ChannelSpec[] channels) { if (channels == null) { return "null"; } StringBuilder sb = new StringBuilder(); sb.append("["); for (int c = 0; c < channels.length; c++) { sb.append(channels[c].frequency); if (c != channels.length - 1) { sb.append(","); } } sb.append("]"); return sb.toString(); } private static String toString(WifiNative.ChannelSettings[] channels, int numChannels) { if (channels == null) { return "null"; } StringBuilder sb = new StringBuilder(); sb.append("["); for (int c = 0; c < numChannels; c++) { sb.append(channels[c].frequency); if (c != numChannels - 1) { sb.append(","); } } sb.append("]"); return sb.toString(); } private static String toString(int band) { switch (band) { case WifiScanner.WIFI_BAND_UNSPECIFIED: return "unspecified"; case WifiScanner.WIFI_BAND_24_GHZ: return "24Ghz"; case WifiScanner.WIFI_BAND_5_GHZ: return "5Ghz (no DFS)"; case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY: return "5Ghz (DFS only)"; case WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS: return "5Ghz (DFS incl)"; case WifiScanner.WIFI_BAND_BOTH: return "24Ghz & 5Ghz (no DFS)"; case WifiScanner.WIFI_BAND_BOTH_WITH_DFS: return "24Ghz & 5Ghz (DFS incl)"; } return "invalid band"; } }