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