| /* |
| * 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<Integer> getMissingChannelsFromBand(int band); |
| /** |
| * Retrieves a list of channels from the band which are contained in the channel collection. |
| */ |
| public abstract Set<Integer> 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<Integer> 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<Integer> getMissingChannelsFromSettings(WifiScanner.ScanSettings scanSettings) { |
| if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { |
| ArraySet<Integer> 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<Integer> getContainingChannelsFromSettings( |
| WifiScanner.ScanSettings scanSettings) { |
| if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { |
| ArraySet<Integer> 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<Integer> 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"; |
| } |
| } |