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