| /* |
| * 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 that offers channel manipulation utilities when the channels in a band are known. |
| * This allows more fine operations on channels than if band channels are not known. |
| */ |
| public class KnownBandsChannelHelper extends ChannelHelper { |
| |
| private WifiScanner.ChannelSpec[][] mBandsToChannels; |
| |
| protected void setBandChannels(int[] channels2G, int[] channels5G, int[] channelsDfs) { |
| mBandsToChannels = new WifiScanner.ChannelSpec[8][]; |
| |
| mBandsToChannels[0] = NO_CHANNELS; |
| |
| mBandsToChannels[1] = new WifiScanner.ChannelSpec[channels2G.length]; |
| copyChannels(mBandsToChannels[1], 0, channels2G); |
| |
| mBandsToChannels[2] = new WifiScanner.ChannelSpec[channels5G.length]; |
| copyChannels(mBandsToChannels[2], 0, channels5G); |
| |
| mBandsToChannels[3] = new WifiScanner.ChannelSpec[channels2G.length + channels5G.length]; |
| copyChannels(mBandsToChannels[3], 0, channels2G); |
| copyChannels(mBandsToChannels[3], channels2G.length, channels5G); |
| |
| mBandsToChannels[4] = new WifiScanner.ChannelSpec[channelsDfs.length]; |
| copyChannels(mBandsToChannels[4], 0, channelsDfs); |
| |
| mBandsToChannels[5] = new WifiScanner.ChannelSpec[channels2G.length + channelsDfs.length]; |
| copyChannels(mBandsToChannels[5], 0, channels2G); |
| copyChannels(mBandsToChannels[5], channels2G.length, channelsDfs); |
| |
| mBandsToChannels[6] = new WifiScanner.ChannelSpec[channels5G.length + channelsDfs.length]; |
| copyChannels(mBandsToChannels[6], 0, channels5G); |
| copyChannels(mBandsToChannels[6], channels5G.length, channelsDfs); |
| |
| mBandsToChannels[7] = new WifiScanner.ChannelSpec[ |
| channels2G.length + channels5G.length + channelsDfs.length]; |
| copyChannels(mBandsToChannels[7], 0, channels2G); |
| copyChannels(mBandsToChannels[7], channels2G.length, channels5G); |
| copyChannels(mBandsToChannels[7], channels2G.length + channels5G.length, channelsDfs); |
| } |
| |
| private static void copyChannels( |
| WifiScanner.ChannelSpec[] channelSpec, int offset, int[] channels) { |
| for (int i = 0; i < channels.length; i++) { |
| channelSpec[offset + i] = new WifiScanner.ChannelSpec(channels[i]); |
| } |
| } |
| |
| @Override |
| public WifiScanner.ChannelSpec[] getAvailableScanChannels(int band) { |
| if (band < WifiScanner.WIFI_BAND_24_GHZ || band > WifiScanner.WIFI_BAND_BOTH_WITH_DFS) { |
| // invalid value for band |
| return NO_CHANNELS; |
| } else { |
| return mBandsToChannels[band]; |
| } |
| } |
| |
| @Override |
| public int estimateScanDuration(WifiScanner.ScanSettings settings) { |
| if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { |
| return settings.channels.length * SCAN_PERIOD_PER_CHANNEL_MS; |
| } else { |
| return getAvailableScanChannels(settings.band).length * SCAN_PERIOD_PER_CHANNEL_MS; |
| } |
| } |
| |
| private boolean isDfsChannel(int frequency) { |
| for (WifiScanner.ChannelSpec dfsChannel : |
| mBandsToChannels[WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY]) { |
| if (frequency == dfsChannel.frequency) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| // TODO this should be rewritten to be based on the input data instead of hardcoded ranges |
| private int getBandFromChannel(int frequency) { |
| if (2400 <= frequency && frequency < 2500) { |
| return WifiScanner.WIFI_BAND_24_GHZ; |
| } else if (isDfsChannel(frequency)) { |
| return WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY; |
| } else if (5100 <= frequency && frequency < 6000) { |
| return WifiScanner.WIFI_BAND_5_GHZ; |
| } else { |
| return WifiScanner.WIFI_BAND_UNSPECIFIED; |
| } |
| } |
| |
| @Override |
| public boolean settingsContainChannel(WifiScanner.ScanSettings settings, int channel) { |
| WifiScanner.ChannelSpec[] settingsChannels; |
| if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { |
| settingsChannels = settings.channels; |
| } else { |
| settingsChannels = getAvailableScanChannels(settings.band); |
| } |
| for (int i = 0; i < settingsChannels.length; ++i) { |
| if (settingsChannels[i].frequency == channel) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * ChannelCollection that merges channels so that the optimal schedule will be generated. |
| * When the max channels value is satisfied this implementation will always create a channel |
| * list that includes no more than the added channels. |
| */ |
| public class KnownBandsChannelCollection extends ChannelCollection { |
| /** |
| * Stores all channels, including those that belong to added bands. |
| */ |
| private final ArraySet<Integer> mChannels = new ArraySet<Integer>(); |
| /** |
| * Contains only the bands that were explicitly added as bands. |
| */ |
| private int mExactBands = 0; |
| /** |
| * Contains all bands, including those that were added because an added channel was in that |
| * band. |
| */ |
| private int mAllBands = 0; |
| |
| @Override |
| public void addChannel(int frequency) { |
| mChannels.add(frequency); |
| mAllBands |= getBandFromChannel(frequency); |
| } |
| |
| @Override |
| public void addBand(int band) { |
| mExactBands |= band; |
| mAllBands |= band; |
| WifiScanner.ChannelSpec[] bandChannels = getAvailableScanChannels(band); |
| for (int i = 0; i < bandChannels.length; ++i) { |
| mChannels.add(bandChannels[i].frequency); |
| } |
| } |
| |
| @Override |
| public boolean containsChannel(int channel) { |
| return mChannels.contains(channel); |
| } |
| |
| @Override |
| public boolean containsBand(int band) { |
| WifiScanner.ChannelSpec[] bandChannels = getAvailableScanChannels(band); |
| for (int i = 0; i < bandChannels.length; ++i) { |
| if (!mChannels.contains(bandChannels[i].frequency)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean partiallyContainsBand(int band) { |
| WifiScanner.ChannelSpec[] bandChannels = getAvailableScanChannels(band); |
| for (int i = 0; i < bandChannels.length; ++i) { |
| if (mChannels.contains(bandChannels[i].frequency)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean isEmpty() { |
| return mChannels.isEmpty(); |
| } |
| |
| @Override |
| public boolean isAllChannels() { |
| return getAvailableScanChannels(WifiScanner.WIFI_BAND_BOTH_WITH_DFS).length == |
| mChannels.size(); |
| } |
| |
| @Override |
| public void clear() { |
| mAllBands = 0; |
| mExactBands = 0; |
| mChannels.clear(); |
| } |
| |
| @Override |
| public Set<Integer> getMissingChannelsFromBand(int band) { |
| ArraySet<Integer> missingChannels = new ArraySet<>(); |
| WifiScanner.ChannelSpec[] bandChannels = getAvailableScanChannels(band); |
| for (int i = 0; i < bandChannels.length; ++i) { |
| if (!mChannels.contains(bandChannels[i].frequency)) { |
| missingChannels.add(bandChannels[i].frequency); |
| } |
| } |
| return missingChannels; |
| } |
| |
| @Override |
| public Set<Integer> getContainingChannelsFromBand(int band) { |
| ArraySet<Integer> containingChannels = new ArraySet<>(); |
| WifiScanner.ChannelSpec[] bandChannels = getAvailableScanChannels(band); |
| for (int i = 0; i < bandChannels.length; ++i) { |
| if (mChannels.contains(bandChannels[i].frequency)) { |
| containingChannels.add(bandChannels[i].frequency); |
| } |
| } |
| return containingChannels; |
| } |
| |
| @Override |
| public Set<Integer> getChannelSet() { |
| if (!isEmpty() && mAllBands != mExactBands) { |
| return mChannels; |
| } else { |
| return new ArraySet<>(); |
| } |
| } |
| |
| @Override |
| public void fillBucketSettings(WifiNative.BucketSettings bucketSettings, int maxChannels) { |
| if ((mChannels.size() > maxChannels || mAllBands == mExactBands) |
| && mAllBands != 0) { |
| bucketSettings.band = mAllBands; |
| bucketSettings.num_channels = 0; |
| bucketSettings.channels = null; |
| } else { |
| bucketSettings.band = WifiScanner.WIFI_BAND_UNSPECIFIED; |
| bucketSettings.num_channels = mChannels.size(); |
| bucketSettings.channels = new WifiNative.ChannelSettings[mChannels.size()]; |
| for (int i = 0; i < mChannels.size(); ++i) { |
| WifiNative.ChannelSettings channelSettings = new WifiNative.ChannelSettings(); |
| channelSettings.frequency = mChannels.valueAt(i); |
| bucketSettings.channels[i] = channelSettings; |
| } |
| } |
| } |
| |
| @Override |
| public Set<Integer> getScanFreqs() { |
| if (mExactBands == WifiScanner.WIFI_BAND_BOTH_WITH_DFS) { |
| return null; |
| } else { |
| return new ArraySet<Integer>(mChannels); |
| } |
| } |
| |
| public Set<Integer> getAllChannels() { |
| return new ArraySet<Integer>(mChannels); |
| } |
| } |
| |
| @Override |
| |
| public KnownBandsChannelCollection createChannelCollection() { |
| return new KnownBandsChannelCollection(); |
| } |
| } |