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