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