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