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