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 offers an abstraction for channel manipulation utilities allowing operation to be
28  * adjusted based on the amount of information known about the available channels.
29  */
30 public abstract class ChannelHelper {
31 
32     // TODO: Currently this is simply an estimate and is used for both active and passive channels
33     //       scans. Eventually it should be split between passive and active and perhaps retrieved
34     //       from the driver.
35     /**
36      * The estimated period spent scanning each channel. This is used for estimating scan duration.
37      */
38     public static final int SCAN_PERIOD_PER_CHANNEL_MS = 200;
39 
40     protected static final WifiScanner.ChannelSpec[] NO_CHANNELS = new WifiScanner.ChannelSpec[0];
41 
42     /**
43      * Create a new collection that can be used to store channels
44      */
createChannelCollection()45     public abstract ChannelCollection createChannelCollection();
46 
47     /**
48      * Return true if the specified channel is expected for a scan with the given settings
49      */
settingsContainChannel(WifiScanner.ScanSettings settings, int channel)50     public abstract boolean settingsContainChannel(WifiScanner.ScanSettings settings, int channel);
51 
52     /**
53      * Get the channels that are available for scanning on the supplied band.
54      * This method may return empty if the information is not available.
55      */
getAvailableScanChannels(int band)56     public abstract WifiScanner.ChannelSpec[] getAvailableScanChannels(int band);
57 
58     /**
59      * Estimates the duration that the chip will spend scanning with the given settings
60      */
estimateScanDuration(WifiScanner.ScanSettings settings)61     public abstract int estimateScanDuration(WifiScanner.ScanSettings settings);
62 
63     /**
64      * Update the channel information that this object has. The source of the update is
65      * implementation dependent and may result in no change. Warning the behavior of a
66      * ChannelCollection created using {@link #createChannelCollection createChannelCollection} is
67      * undefined after calling this method until the {@link ChannelColleciton#clear() clear} method
68      * is called on it.
69      */
updateChannels()70     public void updateChannels() {
71         // default implementation does nothing
72     }
73 
74     /**
75      * Object that supports accumulation of channels and bands
76      */
77     public abstract class ChannelCollection {
78         /**
79          * Add a channel to the collection
80          */
addChannel(int channel)81         public abstract void addChannel(int channel);
82         /**
83          * Add all channels in the band to the collection
84          */
addBand(int band)85         public abstract void addBand(int band);
86         /**
87          * @return true if the collection contains the supplied channel
88          */
containsChannel(int channel)89         public abstract boolean containsChannel(int channel);
90         /**
91          * @return true if the collection contains all the channels of the supplied band
92          */
containsBand(int band)93         public abstract boolean containsBand(int band);
94         /**
95          * @return true if the collection contains some of the channels of the supplied band
96          */
partiallyContainsBand(int band)97         public abstract boolean partiallyContainsBand(int band);
98         /**
99          * @return true if the collection contains no channels
100          */
isEmpty()101         public abstract boolean isEmpty();
102         /**
103          * @return true if the collection contains all available channels
104          */
isAllChannels()105         public abstract boolean isAllChannels();
106         /**
107          * Remove all channels from the collection
108          */
clear()109         public abstract void clear();
110         /**
111          * Retrieves a list of channels from the band which are missing in the channel collection.
112          */
getMissingChannelsFromBand(int band)113         public abstract Set<Integer> getMissingChannelsFromBand(int band);
114         /**
115          * Retrieves a list of channels from the band which are contained in the channel collection.
116          */
getContainingChannelsFromBand(int band)117         public abstract Set<Integer> getContainingChannelsFromBand(int band);
118         /**
119          * Gets a list of channels specified in the current channel collection. This will return
120          * an empty set if an entire Band if specified or if the list is empty.
121          */
getChannelSet()122         public abstract Set<Integer> getChannelSet();
123 
124         /**
125          * Add all channels in the ScanSetting to the collection
126          */
addChannels(WifiScanner.ScanSettings scanSettings)127         public void addChannels(WifiScanner.ScanSettings scanSettings) {
128             if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
129                 for (int j = 0; j < scanSettings.channels.length; ++j) {
130                     addChannel(scanSettings.channels[j].frequency);
131                 }
132             } else {
133                 addBand(scanSettings.band);
134             }
135         }
136 
137         /**
138          * Add all channels in the BucketSettings to the collection
139          */
addChannels(WifiNative.BucketSettings bucketSettings)140         public void addChannels(WifiNative.BucketSettings bucketSettings) {
141             if (bucketSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
142                 for (int j = 0; j < bucketSettings.channels.length; ++j) {
143                     addChannel(bucketSettings.channels[j].frequency);
144                 }
145             } else {
146                 addBand(bucketSettings.band);
147             }
148         }
149 
150         /**
151          * Checks if all channels in ScanSetting is in the collection
152          */
containsSettings(WifiScanner.ScanSettings scanSettings)153         public boolean containsSettings(WifiScanner.ScanSettings scanSettings) {
154             if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
155                 for (int j = 0; j < scanSettings.channels.length; ++j) {
156                     if (!containsChannel(scanSettings.channels[j].frequency)) {
157                         return false;
158                     }
159                 }
160                 return true;
161             } else {
162                 return containsBand(scanSettings.band);
163             }
164         }
165 
166         /**
167          * Checks if at least some of the channels in ScanSetting is in the collection
168          */
partiallyContainsSettings(WifiScanner.ScanSettings scanSettings)169         public boolean partiallyContainsSettings(WifiScanner.ScanSettings scanSettings) {
170             if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
171                 for (int j = 0; j < scanSettings.channels.length; ++j) {
172                     if (containsChannel(scanSettings.channels[j].frequency)) {
173                         return true;
174                     }
175                 }
176                 return false;
177             } else {
178                 return partiallyContainsBand(scanSettings.band);
179             }
180         }
181 
182         /**
183          * Retrieves a list of missing channels in the collection from the provided settings.
184          */
getMissingChannelsFromSettings(WifiScanner.ScanSettings scanSettings)185         public Set<Integer> getMissingChannelsFromSettings(WifiScanner.ScanSettings scanSettings) {
186             if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
187                 ArraySet<Integer> missingChannels = new ArraySet<>();
188                 for (int j = 0; j < scanSettings.channels.length; ++j) {
189                     if (!containsChannel(scanSettings.channels[j].frequency)) {
190                         missingChannels.add(scanSettings.channels[j].frequency);
191                     }
192                 }
193                 return missingChannels;
194             } else {
195                 return getMissingChannelsFromBand(scanSettings.band);
196             }
197         }
198 
199         /**
200          * Retrieves a list of containing channels in the collection from the provided settings.
201          */
getContainingChannelsFromSettings( WifiScanner.ScanSettings scanSettings)202         public Set<Integer> getContainingChannelsFromSettings(
203                 WifiScanner.ScanSettings scanSettings) {
204             if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
205                 ArraySet<Integer> containingChannels = new ArraySet<>();
206                 for (int j = 0; j < scanSettings.channels.length; ++j) {
207                     if (containsChannel(scanSettings.channels[j].frequency)) {
208                         containingChannels.add(scanSettings.channels[j].frequency);
209                     }
210                 }
211                 return containingChannels;
212             } else {
213                 return getContainingChannelsFromBand(scanSettings.band);
214             }
215         }
216 
217         /**
218          * Store the channels in this collection in the supplied BucketSettings. If maxChannels is
219          * exceeded or a band better describes the channels then a band is specified instead of a
220          * channel list.
221          */
fillBucketSettings(WifiNative.BucketSettings bucket, int maxChannels)222         public abstract void fillBucketSettings(WifiNative.BucketSettings bucket, int maxChannels);
223 
224         /**
225          * Gets the list of channels scan. Will either be a collection of all channels or null
226          * if all channels should be scanned.
227          */
getScanFreqs()228         public abstract Set<Integer> getScanFreqs();
229     }
230 
231 
232     /*
233      * Utility methods for converting band/channels to strings
234      */
235 
236     /**
237      * Create a string representation of the channels in the ScanSettings.
238      * If it contains a list of channels then the channels are returned, otherwise a string name of
239      * the band is returned.
240      */
toString(WifiScanner.ScanSettings scanSettings)241     public static String toString(WifiScanner.ScanSettings scanSettings) {
242         if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
243             return toString(scanSettings.channels);
244         } else {
245             return bandToString(scanSettings.band);
246         }
247     }
248 
249     /**
250      * Create a string representation of the channels in the BucketSettings.
251      * If it contains a list of channels then the channels are returned, otherwise a string name of
252      * the band is returned.
253      */
toString(WifiNative.BucketSettings bucketSettings)254     public static String toString(WifiNative.BucketSettings bucketSettings) {
255         if (bucketSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
256             return toString(bucketSettings.channels, bucketSettings.num_channels);
257         } else {
258             return bandToString(bucketSettings.band);
259         }
260     }
261 
toString(WifiScanner.ChannelSpec[] channels)262     private static String toString(WifiScanner.ChannelSpec[] channels) {
263         if (channels == null) {
264             return "null";
265         }
266 
267         StringBuilder sb = new StringBuilder();
268         sb.append("[");
269         for (int c = 0; c < channels.length; c++) {
270             sb.append(channels[c].frequency);
271             if (c != channels.length - 1) {
272                 sb.append(",");
273             }
274         }
275         sb.append("]");
276         return sb.toString();
277     }
278 
toString(WifiNative.ChannelSettings[] channels, int numChannels)279     private static String toString(WifiNative.ChannelSettings[] channels, int numChannels) {
280         if (channels == null) {
281             return "null";
282         }
283 
284         StringBuilder sb = new StringBuilder();
285         sb.append("[");
286         for (int c = 0; c < numChannels; c++) {
287             sb.append(channels[c].frequency);
288             if (c != numChannels - 1) {
289                 sb.append(",");
290             }
291         }
292         sb.append("]");
293         return sb.toString();
294     }
295 
296     /**
297      * Converts a WifiScanner.WIFI_BAND_* constant to a meaningful String
298      */
bandToString(int band)299     public static String bandToString(int band) {
300         switch (band) {
301             case WifiScanner.WIFI_BAND_UNSPECIFIED:
302                 return "unspecified";
303             case WifiScanner.WIFI_BAND_24_GHZ:
304                 return "24Ghz";
305             case WifiScanner.WIFI_BAND_5_GHZ:
306                 return "5Ghz (no DFS)";
307             case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY:
308                 return "5Ghz (DFS only)";
309             case WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS:
310                 return "5Ghz (DFS incl)";
311             case WifiScanner.WIFI_BAND_BOTH:
312                 return "24Ghz & 5Ghz (no DFS)";
313             case WifiScanner.WIFI_BAND_BOTH_WITH_DFS:
314                 return "24Ghz & 5Ghz (DFS incl)";
315         }
316         return "invalid band";
317     }
318 }
319