1 /*
2  * Copyright (C) 2016 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.scanner;
18 
19 import android.net.wifi.WifiScanner;
20 import android.util.ArraySet;
21 
22 import com.android.server.wifi.WifiNative;
23 
24 import java.util.Set;
25 
26 /**
27  * ChannelHelper that offers channel manipulation utilities when the channels in a band are known.
28  * This allows more fine operations on channels than if band channels are not known.
29  */
30 public class KnownBandsChannelHelper extends ChannelHelper {
31 
32     private WifiScanner.ChannelSpec[][] mBandsToChannels;
33 
setBandChannels(int[] channels2G, int[] channels5G, int[] channelsDfs)34     protected void setBandChannels(int[] channels2G, int[] channels5G, int[] channelsDfs) {
35         mBandsToChannels = new WifiScanner.ChannelSpec[8][];
36 
37         mBandsToChannels[0] = NO_CHANNELS;
38 
39         mBandsToChannels[1] = new WifiScanner.ChannelSpec[channels2G.length];
40         copyChannels(mBandsToChannels[1], 0, channels2G);
41 
42         mBandsToChannels[2] = new WifiScanner.ChannelSpec[channels5G.length];
43         copyChannels(mBandsToChannels[2], 0, channels5G);
44 
45         mBandsToChannels[3] = new WifiScanner.ChannelSpec[channels2G.length + channels5G.length];
46         copyChannels(mBandsToChannels[3], 0, channels2G);
47         copyChannels(mBandsToChannels[3], channels2G.length, channels5G);
48 
49         mBandsToChannels[4] = new WifiScanner.ChannelSpec[channelsDfs.length];
50         copyChannels(mBandsToChannels[4], 0, channelsDfs);
51 
52         mBandsToChannels[5] = new WifiScanner.ChannelSpec[channels2G.length + channelsDfs.length];
53         copyChannels(mBandsToChannels[5], 0, channels2G);
54         copyChannels(mBandsToChannels[5], channels2G.length, channelsDfs);
55 
56         mBandsToChannels[6] = new WifiScanner.ChannelSpec[channels5G.length + channelsDfs.length];
57         copyChannels(mBandsToChannels[6], 0, channels5G);
58         copyChannels(mBandsToChannels[6], channels5G.length, channelsDfs);
59 
60         mBandsToChannels[7] = new WifiScanner.ChannelSpec[
61                 channels2G.length + channels5G.length + channelsDfs.length];
62         copyChannels(mBandsToChannels[7], 0, channels2G);
63         copyChannels(mBandsToChannels[7], channels2G.length, channels5G);
64         copyChannels(mBandsToChannels[7], channels2G.length + channels5G.length, channelsDfs);
65     }
66 
copyChannels( WifiScanner.ChannelSpec[] channelSpec, int offset, int[] channels)67     private static void copyChannels(
68             WifiScanner.ChannelSpec[] channelSpec, int offset, int[] channels) {
69         for (int i = 0; i < channels.length; i++) {
70             channelSpec[offset + i] = new WifiScanner.ChannelSpec(channels[i]);
71         }
72     }
73 
74     @Override
getAvailableScanChannels(int band)75     public WifiScanner.ChannelSpec[] getAvailableScanChannels(int band) {
76         if (band < WifiScanner.WIFI_BAND_24_GHZ || band > WifiScanner.WIFI_BAND_BOTH_WITH_DFS) {
77             // invalid value for band
78             return NO_CHANNELS;
79         } else {
80             return mBandsToChannels[band];
81         }
82     }
83 
84     @Override
estimateScanDuration(WifiScanner.ScanSettings settings)85     public int estimateScanDuration(WifiScanner.ScanSettings settings) {
86         if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
87             return settings.channels.length * SCAN_PERIOD_PER_CHANNEL_MS;
88         } else {
89             return getAvailableScanChannels(settings.band).length * SCAN_PERIOD_PER_CHANNEL_MS;
90         }
91     }
92 
isDfsChannel(int frequency)93     private boolean isDfsChannel(int frequency) {
94         for (WifiScanner.ChannelSpec dfsChannel :
95                 mBandsToChannels[WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY]) {
96             if (frequency == dfsChannel.frequency) {
97                 return true;
98             }
99         }
100         return false;
101     }
102 
103     // TODO this should be rewritten to be based on the input data instead of hardcoded ranges
getBandFromChannel(int frequency)104     private int getBandFromChannel(int frequency) {
105         if (2400 <= frequency && frequency < 2500) {
106             return WifiScanner.WIFI_BAND_24_GHZ;
107         } else if (isDfsChannel(frequency)) {
108             return WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY;
109         } else if (5100 <= frequency && frequency < 6000) {
110             return WifiScanner.WIFI_BAND_5_GHZ;
111         } else {
112             return WifiScanner.WIFI_BAND_UNSPECIFIED;
113         }
114     }
115 
116     @Override
settingsContainChannel(WifiScanner.ScanSettings settings, int channel)117     public boolean settingsContainChannel(WifiScanner.ScanSettings settings, int channel) {
118         WifiScanner.ChannelSpec[] settingsChannels;
119         if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
120             settingsChannels = settings.channels;
121         } else {
122             settingsChannels = getAvailableScanChannels(settings.band);
123         }
124         for (int i = 0; i < settingsChannels.length; ++i) {
125             if (settingsChannels[i].frequency == channel) {
126                 return true;
127             }
128         }
129         return false;
130     }
131 
132     /**
133      * ChannelCollection that merges channels so that the optimal schedule will be generated.
134      * When the max channels value is satisfied this implementation will always create a channel
135      * list that includes no more than the added channels.
136      */
137     public class KnownBandsChannelCollection extends ChannelCollection {
138         /**
139          * Stores all channels, including those that belong to added bands.
140          */
141         private final ArraySet<Integer> mChannels = new ArraySet<Integer>();
142         /**
143          * Contains only the bands that were explicitly added as bands.
144          */
145         private int mExactBands = 0;
146         /**
147          * Contains all bands, including those that were added because an added channel was in that
148          * band.
149          */
150         private int mAllBands = 0;
151 
152         @Override
addChannel(int frequency)153         public void addChannel(int frequency) {
154             mChannels.add(frequency);
155             mAllBands |= getBandFromChannel(frequency);
156         }
157 
158         @Override
addBand(int band)159         public void addBand(int band) {
160             mExactBands |= band;
161             mAllBands |= band;
162             WifiScanner.ChannelSpec[] bandChannels = getAvailableScanChannels(band);
163             for (int i = 0; i < bandChannels.length; ++i) {
164                 mChannels.add(bandChannels[i].frequency);
165             }
166         }
167 
168         @Override
containsChannel(int channel)169         public boolean containsChannel(int channel) {
170             return mChannels.contains(channel);
171         }
172 
173         @Override
containsBand(int band)174         public boolean containsBand(int band) {
175             WifiScanner.ChannelSpec[] bandChannels = getAvailableScanChannels(band);
176             for (int i = 0; i < bandChannels.length; ++i) {
177                 if (!mChannels.contains(bandChannels[i].frequency)) {
178                     return false;
179                 }
180             }
181             return true;
182         }
183 
184         @Override
partiallyContainsBand(int band)185         public boolean partiallyContainsBand(int band) {
186             WifiScanner.ChannelSpec[] bandChannels = getAvailableScanChannels(band);
187             for (int i = 0; i < bandChannels.length; ++i) {
188                 if (mChannels.contains(bandChannels[i].frequency)) {
189                     return true;
190                 }
191             }
192             return false;
193         }
194 
195         @Override
isEmpty()196         public boolean isEmpty() {
197             return mChannels.isEmpty();
198         }
199 
200         @Override
isAllChannels()201         public boolean isAllChannels() {
202             return getAvailableScanChannels(WifiScanner.WIFI_BAND_BOTH_WITH_DFS).length ==
203                     mChannels.size();
204         }
205 
206         @Override
clear()207         public void clear() {
208             mAllBands = 0;
209             mExactBands = 0;
210             mChannels.clear();
211         }
212 
213         @Override
getMissingChannelsFromBand(int band)214         public Set<Integer> getMissingChannelsFromBand(int band) {
215             ArraySet<Integer> missingChannels = new ArraySet<>();
216             WifiScanner.ChannelSpec[] bandChannels = getAvailableScanChannels(band);
217             for (int i = 0; i < bandChannels.length; ++i) {
218                 if (!mChannels.contains(bandChannels[i].frequency)) {
219                     missingChannels.add(bandChannels[i].frequency);
220                 }
221             }
222             return missingChannels;
223         }
224 
225         @Override
getContainingChannelsFromBand(int band)226         public Set<Integer> getContainingChannelsFromBand(int band) {
227             ArraySet<Integer> containingChannels = new ArraySet<>();
228             WifiScanner.ChannelSpec[] bandChannels = getAvailableScanChannels(band);
229             for (int i = 0; i < bandChannels.length; ++i) {
230                 if (mChannels.contains(bandChannels[i].frequency)) {
231                     containingChannels.add(bandChannels[i].frequency);
232                 }
233             }
234             return containingChannels;
235         }
236 
237         @Override
getChannelSet()238         public Set<Integer> getChannelSet() {
239             if (!isEmpty() && mAllBands != mExactBands) {
240                 return mChannels;
241             } else {
242                 return new ArraySet<>();
243             }
244         }
245 
246         @Override
fillBucketSettings(WifiNative.BucketSettings bucketSettings, int maxChannels)247         public void fillBucketSettings(WifiNative.BucketSettings bucketSettings, int maxChannels) {
248             if ((mChannels.size() > maxChannels || mAllBands == mExactBands)
249                     && mAllBands != 0) {
250                 bucketSettings.band = mAllBands;
251                 bucketSettings.num_channels = 0;
252                 bucketSettings.channels = null;
253             } else {
254                 bucketSettings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
255                 bucketSettings.num_channels = mChannels.size();
256                 bucketSettings.channels = new WifiNative.ChannelSettings[mChannels.size()];
257                 for (int i = 0; i < mChannels.size(); ++i) {
258                     WifiNative.ChannelSettings channelSettings = new WifiNative.ChannelSettings();
259                     channelSettings.frequency = mChannels.valueAt(i);
260                     bucketSettings.channels[i] = channelSettings;
261                 }
262             }
263         }
264 
265         @Override
getScanFreqs()266         public Set<Integer> getScanFreqs() {
267             if (mExactBands == WifiScanner.WIFI_BAND_BOTH_WITH_DFS) {
268                 return null;
269             } else {
270                 return new ArraySet<Integer>(mChannels);
271             }
272         }
273 
getAllChannels()274         public Set<Integer> getAllChannels() {
275             return new ArraySet<Integer>(mChannels);
276         }
277     }
278 
279     @Override
280 
createChannelCollection()281     public KnownBandsChannelCollection createChannelCollection() {
282         return new KnownBandsChannelCollection();
283     }
284 }
285