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 static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ;
20 import static android.net.wifi.WifiScanner.WIFI_BAND_5_GHZ;
21 import static android.net.wifi.WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY;
22 import static android.net.wifi.WifiScanner.WIFI_BAND_6_GHZ;
23 import static android.net.wifi.WifiScanner.WIFI_BAND_ALL;
24 import static android.net.wifi.WifiScanner.WIFI_BAND_COUNT;
25 import static android.net.wifi.WifiScanner.WIFI_BAND_INDEX_24_GHZ;
26 import static android.net.wifi.WifiScanner.WIFI_BAND_INDEX_5_GHZ;
27 import static android.net.wifi.WifiScanner.WIFI_BAND_INDEX_5_GHZ_DFS_ONLY;
28 import static android.net.wifi.WifiScanner.WIFI_BAND_INDEX_6_GHZ;
29 import static android.net.wifi.WifiScanner.WIFI_BAND_UNSPECIFIED;
30 
31 import android.net.wifi.ScanResult;
32 import android.net.wifi.WifiAnnotations.WifiBandBasic;
33 import android.net.wifi.WifiScanner;
34 import android.net.wifi.WifiScanner.WifiBandIndex;
35 import android.util.ArraySet;
36 
37 import com.android.server.wifi.WifiNative;
38 
39 import java.util.Arrays;
40 import java.util.Set;
41 import java.util.stream.Collectors;
42 
43 /**
44  * ChannelHelper that offers channel manipulation utilities when the channels in a band are known.
45  * This allows more fine operations on channels than if band channels are not known.
46  */
47 public class KnownBandsChannelHelper extends ChannelHelper {
48     // 5G low includes U-NII-1 and Japan 4.9G band
49     public static final int BAND_5_GHZ_LOW_END_FREQ = 5240;
50     // 5G middle includes U-NII-2A and U-NII-2C
51     public static final int BAND_5_GHZ_MID_END_FREQ = 5710;
52     // 5G high includes U-NII-3
53     public static final int BAND_5_GHZ_HIGH_END_FREQ = ScanResult.BAND_5_GHZ_END_FREQ_MHZ;
54     // 6G low includes UNII-5
55     public static final int BAND_6_GHZ_LOW_END_FREQ = 6425;
56     // 6G middle includes UNII-6 and UNII-7
57     public static final int BAND_6_GHZ_MID_END_FREQ = 6875;
58     // 6G high includes UNII-8
59     public static final int BAND_6_GHZ_HIGH_END_FREQ = ScanResult.BAND_6_GHZ_END_FREQ_MHZ;
60 
61     private WifiScanner.ChannelSpec[][] mBandsToChannels;
62 
setBandChannels(int[] channels2G, int[] channels5G, int[] channelsDfs, int[] channels6G)63     protected void setBandChannels(int[] channels2G, int[] channels5G, int[] channelsDfs,
64             int[] channels6G) {
65         mBandsToChannels = new WifiScanner.ChannelSpec[WIFI_BAND_COUNT][];
66 
67         if (channels2G.length != 0) {
68             mBandsToChannels[WIFI_BAND_INDEX_24_GHZ] =
69                     new WifiScanner.ChannelSpec[channels2G.length];
70             copyChannels(mBandsToChannels[WIFI_BAND_INDEX_24_GHZ], channels2G);
71         } else {
72             mBandsToChannels[WIFI_BAND_INDEX_24_GHZ] = NO_CHANNELS;
73         }
74 
75         if (channels5G.length != 0) {
76             mBandsToChannels[WIFI_BAND_INDEX_5_GHZ] =
77                     new WifiScanner.ChannelSpec[channels5G.length];
78             copyChannels(mBandsToChannels[WIFI_BAND_INDEX_5_GHZ], channels5G);
79         } else {
80             mBandsToChannels[WIFI_BAND_INDEX_5_GHZ] = NO_CHANNELS;
81         }
82 
83         if (channelsDfs.length != 0) {
84             mBandsToChannels[WIFI_BAND_INDEX_5_GHZ_DFS_ONLY] =
85                     new WifiScanner.ChannelSpec[channelsDfs.length];
86             copyChannels(mBandsToChannels[WIFI_BAND_INDEX_5_GHZ_DFS_ONLY], channelsDfs);
87         } else {
88             mBandsToChannels[WIFI_BAND_INDEX_5_GHZ_DFS_ONLY] = NO_CHANNELS;
89         }
90 
91         if (channels6G.length != 0) {
92             mBandsToChannels[WIFI_BAND_INDEX_6_GHZ] =
93                     new WifiScanner.ChannelSpec[channels6G.length];
94             copyChannels(mBandsToChannels[WIFI_BAND_INDEX_6_GHZ], channels6G);
95         } else {
96             mBandsToChannels[WIFI_BAND_INDEX_6_GHZ] = NO_CHANNELS;
97         }
98     }
99 
copyChannels( WifiScanner.ChannelSpec[] channelSpec, int[] channels)100     private static void copyChannels(
101             WifiScanner.ChannelSpec[] channelSpec, int[] channels) {
102         for (int i = 0; i < channels.length; i++) {
103             channelSpec[i] = new WifiScanner.ChannelSpec(channels[i]);
104         }
105     }
106 
107     @Override
getAvailableScanChannels(int band)108     public WifiScanner.ChannelSpec[][] getAvailableScanChannels(int band) {
109         if (band <= WIFI_BAND_UNSPECIFIED || band > WIFI_BAND_ALL) {
110             // Invalid value for band.
111             return null;
112         }
113 
114         WifiScanner.ChannelSpec[][] channels = new WifiScanner.ChannelSpec[WIFI_BAND_COUNT][];
115         for (@WifiBandIndex int index = 0; index < WIFI_BAND_COUNT; index++) {
116             if ((band & (1 << index)) != 0) {
117                 channels[index] = mBandsToChannels[index];
118             } else {
119                 channels[index] = NO_CHANNELS;
120             }
121         }
122         return channels;
123     }
124 
125     @Override
satisfies(ChannelHelper otherChannelHelper)126     public boolean satisfies(ChannelHelper otherChannelHelper) {
127         if (!(otherChannelHelper instanceof KnownBandsChannelHelper)) return false;
128         KnownBandsChannelHelper otherKnownBandsChannelHelper =
129                 (KnownBandsChannelHelper) otherChannelHelper;
130         // Compare all the channels in every band
131         for (@WifiBandIndex int i = 0; i < WIFI_BAND_COUNT; i++) {
132             Set<Integer> thisFrequencies = Arrays.stream(mBandsToChannels[i])
133                     .map(spec -> spec.frequency)
134                     .collect(Collectors.toSet());
135             Set<Integer> otherFrequencies = Arrays.stream(
136                     otherKnownBandsChannelHelper.mBandsToChannels[i])
137                     .map(spec -> spec.frequency)
138                     .collect(Collectors.toSet());
139             if (!thisFrequencies.containsAll(otherFrequencies)) {
140                 return false;
141             }
142         }
143         return true;
144     }
145 
146     @Override
estimateScanDuration(WifiScanner.ScanSettings settings)147     public int estimateScanDuration(WifiScanner.ScanSettings settings) {
148         if (settings.band == WIFI_BAND_UNSPECIFIED) {
149             return settings.channels.length * SCAN_PERIOD_PER_CHANNEL_MS;
150         } else {
151             WifiScanner.ChannelSpec[][] channels = getAvailableScanChannels(settings.band);
152             int len = 0;
153             for (int i = 0; i < channels.length; ++i) {
154                 len += channels[i].length;
155             }
156             return  len * SCAN_PERIOD_PER_CHANNEL_MS;
157         }
158     }
159 
isDfsChannel(int frequency)160     private boolean isDfsChannel(int frequency) {
161         for (WifiScanner.ChannelSpec dfsChannel :
162                 mBandsToChannels[WIFI_BAND_INDEX_5_GHZ_DFS_ONLY]) {
163             if (frequency == dfsChannel.frequency) {
164                 return true;
165             }
166         }
167         return false;
168     }
169 
170     // TODO this should be rewritten to be based on the input data instead of hardcoded ranges
getBandFromChannel(int frequency)171     private int getBandFromChannel(int frequency) {
172         if (ScanResult.is24GHz(frequency)) {
173             return WIFI_BAND_24_GHZ;
174         } else if (ScanResult.is5GHz(frequency)) {
175             if (isDfsChannel(frequency)) {
176                 return WIFI_BAND_5_GHZ_DFS_ONLY;
177             } else {
178                 return WIFI_BAND_5_GHZ;
179             }
180         } else if (ScanResult.is6GHz(frequency)) {
181             return WIFI_BAND_6_GHZ;
182         } else {
183             return WIFI_BAND_UNSPECIFIED;
184         }
185     }
186 
getIndexForBand(@ifiBandBasic int band)187     private @WifiBandIndex int getIndexForBand(@WifiBandBasic int band) {
188         switch (band) {
189             case WIFI_BAND_24_GHZ:
190                 return WIFI_BAND_INDEX_24_GHZ;
191             case WIFI_BAND_5_GHZ:
192                 return WIFI_BAND_INDEX_5_GHZ;
193             case WIFI_BAND_5_GHZ_DFS_ONLY:
194                 return WIFI_BAND_INDEX_5_GHZ_DFS_ONLY;
195             case WIFI_BAND_6_GHZ:
196                 return WIFI_BAND_INDEX_6_GHZ;
197             default:
198                 return -1;
199         }
200     }
201 
202     @Override
settingsContainChannel(WifiScanner.ScanSettings settings, int channel)203     public boolean settingsContainChannel(WifiScanner.ScanSettings settings, int channel) {
204         WifiScanner.ChannelSpec[] settingsChannels;
205         @WifiBandBasic int band;
206         // If band is not specified in settings, limit check on channels in settings
207         if (settings.band == WIFI_BAND_UNSPECIFIED) {
208             settingsChannels = settings.channels;
209         } else {
210             // Get the proper band for this channel
211             band = getBandFromChannel(channel);
212             // Check if this band is included in band specified in settings
213             if ((settings.band & band) == WIFI_BAND_UNSPECIFIED) {
214                 return false;
215             }
216 
217             settingsChannels = mBandsToChannels[getIndexForBand(band)];
218         }
219         // Now search for the channel
220         for (int i = 0; i < settingsChannels.length; ++i) {
221             if (settingsChannels[i].frequency == channel) {
222                 return true;
223             }
224         }
225         return false;
226     }
227 
228     /**
229      * ChannelCollection that merges channels so that the optimal schedule will be generated.
230      * When the max channels value is satisfied this implementation will always create a channel
231      * list that includes no more than the added channels.
232      */
233     public class KnownBandsChannelCollection extends ChannelCollection {
234         /**
235          * Stores all channels, including those that belong to added bands.
236          */
237         private final ArraySet<Integer> mChannels = new ArraySet<Integer>();
238         /**
239          * Contains only the bands that were explicitly added as bands.
240          */
241         private int mExactBands = 0;
242         /**
243          * Contains all bands, including those that were added because an added channel was in that
244          * band.
245          */
246         private int mAllBands = 0;
247 
248         @Override
addChannel(int frequency)249         public void addChannel(int frequency) {
250             mChannels.add(frequency);
251             mAllBands |= getBandFromChannel(frequency);
252         }
253 
254         @Override
addBand(int band)255         public void addBand(int band) {
256             mExactBands |= band;
257             mAllBands |= band;
258             WifiScanner.ChannelSpec[][] bandChannels = getAvailableScanChannels(band);
259             for (int i = 0; i < bandChannels.length; ++i) {
260                 for (int j = 0; j < bandChannels[i].length; ++j) {
261                     mChannels.add(bandChannels[i][j].frequency);
262                 }
263             }
264         }
265 
266         @Override
containsChannel(int channel)267         public boolean containsChannel(int channel) {
268             return mChannels.contains(channel);
269         }
270 
271         @Override
containsBand(int band)272         public boolean containsBand(int band) {
273             WifiScanner.ChannelSpec[][] bandChannels = getAvailableScanChannels(band);
274             for (int i = 0; i < bandChannels.length; ++i) {
275                 for (int j = 0; j < bandChannels[i].length; ++j) {
276                     if (!mChannels.contains(bandChannels[i][j].frequency)) {
277                         return false;
278                     }
279                 }
280             }
281             return true;
282         }
283 
284         @Override
partiallyContainsBand(int band)285         public boolean partiallyContainsBand(int band) {
286             WifiScanner.ChannelSpec[][] bandChannels = getAvailableScanChannels(band);
287             for (int i = 0; i < bandChannels.length; ++i) {
288                 for (int j = 0; j < bandChannels[i].length; ++j) {
289                     if (mChannels.contains(bandChannels[i][j].frequency)) {
290                         return true;
291                     }
292                 }
293             }
294             return false;
295         }
296 
297         @Override
isEmpty()298         public boolean isEmpty() {
299             return mChannels.isEmpty();
300         }
301 
302         @Override
isAllChannels()303         public boolean isAllChannels() {
304             return containsBand(WIFI_BAND_ALL);
305         }
306 
307         @Override
clear()308         public void clear() {
309             mAllBands = 0;
310             mExactBands = 0;
311             mChannels.clear();
312         }
313 
314         @Override
getMissingChannelsFromBand(int band)315         public Set<Integer> getMissingChannelsFromBand(int band) {
316             ArraySet<Integer> missingChannels = new ArraySet<>();
317             WifiScanner.ChannelSpec[][] bandChannels = getAvailableScanChannels(band);
318             for (int i = 0; i < bandChannels.length; ++i) {
319                 for (int j = 0; j < bandChannels[i].length; ++j) {
320                     if (!mChannels.contains(bandChannels[i][j].frequency)) {
321                         missingChannels.add(bandChannels[i][j].frequency);
322                     }
323                 }
324             }
325             return missingChannels;
326         }
327 
328         @Override
getContainingChannelsFromBand(int band)329         public Set<Integer> getContainingChannelsFromBand(int band) {
330             ArraySet<Integer> containingChannels = new ArraySet<>();
331             WifiScanner.ChannelSpec[][] bandChannels = getAvailableScanChannels(band);
332             for (int i = 0; i < bandChannels.length; ++i) {
333                 for (int j = 0; j < bandChannels[i].length; ++j) {
334                     if (mChannels.contains(bandChannels[i][j].frequency)) {
335                         containingChannels.add(bandChannels[i][j].frequency);
336                     }
337                 }
338             }
339             return containingChannels;
340         }
341 
342         @Override
getChannelSet()343         public Set<Integer> getChannelSet() {
344             if (!isEmpty() && mAllBands != mExactBands) {
345                 return mChannels;
346             } else {
347                 return new ArraySet<>();
348             }
349         }
350 
351         @Override
fillBucketSettings(WifiNative.BucketSettings bucketSettings, int maxChannels)352         public void fillBucketSettings(WifiNative.BucketSettings bucketSettings, int maxChannels) {
353             if ((mChannels.size() > maxChannels || mAllBands == mExactBands)
354                     && mAllBands != 0) {
355                 bucketSettings.band = mAllBands;
356                 bucketSettings.num_channels = 0;
357                 bucketSettings.channels = null;
358             } else {
359                 bucketSettings.band = WIFI_BAND_UNSPECIFIED;
360                 bucketSettings.num_channels = mChannels.size();
361                 bucketSettings.channels = new WifiNative.ChannelSettings[mChannels.size()];
362                 for (int i = 0; i < mChannels.size(); ++i) {
363                     WifiNative.ChannelSettings channelSettings = new WifiNative.ChannelSettings();
364                     channelSettings.frequency = mChannels.valueAt(i);
365                     bucketSettings.channels[i] = channelSettings;
366                 }
367             }
368         }
369 
370         @Override
getScanFreqs()371         public Set<Integer> getScanFreqs() {
372             if (mExactBands == WIFI_BAND_ALL) {
373                 return null;
374             } else {
375                 return new ArraySet<Integer>(mChannels);
376             }
377         }
378 
getAllChannels()379         public Set<Integer> getAllChannels() {
380             return new ArraySet<Integer>(mChannels);
381         }
382     }
383 
384     @Override
385 
createChannelCollection()386     public KnownBandsChannelCollection createChannelCollection() {
387         return new KnownBandsChannelCollection();
388     }
389 }
390