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