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 */ 45 public abstract ChannelCollection createChannelCollection(); 46 47 /** 48 * Return true if the specified channel is expected for a scan with the given settings 49 */ 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 */ 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 */ 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 */ 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 */ 81 public abstract void addChannel(int channel); 82 /** 83 * Add all channels in the band to the collection 84 */ 85 public abstract void addBand(int band); 86 /** 87 * @return true if the collection contains the supplied channel 88 */ 89 public abstract boolean containsChannel(int channel); 90 /** 91 * @return true if the collection contains all the channels of the supplied band 92 */ 93 public abstract boolean containsBand(int band); 94 /** 95 * @return true if the collection contains some of the channels of the supplied band 96 */ 97 public abstract boolean partiallyContainsBand(int band); 98 /** 99 * @return true if the collection contains no channels 100 */ 101 public abstract boolean isEmpty(); 102 /** 103 * Remove all channels from the collection 104 */ 105 public abstract void clear(); 106 /** 107 * Retrieves a list of channels from the band which are missing in the channel collection. 108 */ 109 public abstract Set<Integer> getMissingChannelsFromBand(int band); 110 /** 111 * Retrieves a list of channels from the band which are contained in the channel collection. 112 */ 113 public abstract Set<Integer> getContainingChannelsFromBand(int band); 114 /** 115 * Gets a list of channels specified in the current channel collection. This will return 116 * an empty set if an entire Band if specified or if the list is empty. 117 */ 118 public abstract Set<Integer> getChannelSet(); 119 120 /** 121 * Add all channels in the ScanSetting to the collection 122 */ 123 public void addChannels(WifiScanner.ScanSettings scanSettings) { 124 if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { 125 for (int j = 0; j < scanSettings.channels.length; ++j) { 126 addChannel(scanSettings.channels[j].frequency); 127 } 128 } else { 129 addBand(scanSettings.band); 130 } 131 } 132 133 /** 134 * Add all channels in the BucketSettings to the collection 135 */ 136 public void addChannels(WifiNative.BucketSettings bucketSettings) { 137 if (bucketSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { 138 for (int j = 0; j < bucketSettings.channels.length; ++j) { 139 addChannel(bucketSettings.channels[j].frequency); 140 } 141 } else { 142 addBand(bucketSettings.band); 143 } 144 } 145 146 /** 147 * Checks if all channels in ScanSetting is in the collection 148 */ 149 public boolean containsSettings(WifiScanner.ScanSettings scanSettings) { 150 if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { 151 for (int j = 0; j < scanSettings.channels.length; ++j) { 152 if (!containsChannel(scanSettings.channels[j].frequency)) { 153 return false; 154 } 155 } 156 return true; 157 } else { 158 return containsBand(scanSettings.band); 159 } 160 } 161 162 /** 163 * Checks if at least some of the channels in ScanSetting is in the collection 164 */ 165 public boolean partiallyContainsSettings(WifiScanner.ScanSettings scanSettings) { 166 if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { 167 for (int j = 0; j < scanSettings.channels.length; ++j) { 168 if (containsChannel(scanSettings.channels[j].frequency)) { 169 return true; 170 } 171 } 172 return false; 173 } else { 174 return partiallyContainsBand(scanSettings.band); 175 } 176 } 177 178 /** 179 * Retrieves a list of missing channels in the collection from the provided settings. 180 */ 181 public Set<Integer> getMissingChannelsFromSettings(WifiScanner.ScanSettings scanSettings) { 182 if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { 183 ArraySet<Integer> missingChannels = new ArraySet<>(); 184 for (int j = 0; j < scanSettings.channels.length; ++j) { 185 if (!containsChannel(scanSettings.channels[j].frequency)) { 186 missingChannels.add(scanSettings.channels[j].frequency); 187 } 188 } 189 return missingChannels; 190 } else { 191 return getMissingChannelsFromBand(scanSettings.band); 192 } 193 } 194 195 /** 196 * Retrieves a list of containing channels in the collection from the provided settings. 197 */ 198 public Set<Integer> getContainingChannelsFromSettings( 199 WifiScanner.ScanSettings scanSettings) { 200 if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { 201 ArraySet<Integer> containingChannels = new ArraySet<>(); 202 for (int j = 0; j < scanSettings.channels.length; ++j) { 203 if (containsChannel(scanSettings.channels[j].frequency)) { 204 containingChannels.add(scanSettings.channels[j].frequency); 205 } 206 } 207 return containingChannels; 208 } else { 209 return getContainingChannelsFromBand(scanSettings.band); 210 } 211 } 212 213 /** 214 * Store the channels in this collection in the supplied BucketSettings. If maxChannels is 215 * exceeded or a band better describes the channels then a band is specified instead of a 216 * channel list. 217 */ 218 public abstract void fillBucketSettings(WifiNative.BucketSettings bucket, int maxChannels); 219 220 /** 221 * Gets the list of channels that should be supplied to supplicant for a scan. Will either 222 * be a collection of all channels or null if all channels should be scanned. 223 */ 224 public abstract Set<Integer> getSupplicantScanFreqs(); 225 } 226 227 228 /* 229 * Utility methods for converting band/channels to strings 230 */ 231 232 /** 233 * Create a string representation of the channels in the ScanSettings. 234 * If it contains a list of channels then the channels are returned, otherwise a string name of 235 * the band is returned. 236 */ 237 public static String toString(WifiScanner.ScanSettings scanSettings) { 238 if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { 239 return toString(scanSettings.channels); 240 } else { 241 return toString(scanSettings.band); 242 } 243 } 244 245 /** 246 * Create a string representation of the channels in the BucketSettings. 247 * If it contains a list of channels then the channels are returned, otherwise a string name of 248 * the band is returned. 249 */ 250 public static String toString(WifiNative.BucketSettings bucketSettings) { 251 if (bucketSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { 252 return toString(bucketSettings.channels, bucketSettings.num_channels); 253 } else { 254 return toString(bucketSettings.band); 255 } 256 } 257 258 private static String toString(WifiScanner.ChannelSpec[] channels) { 259 if (channels == null) { 260 return "null"; 261 } 262 263 StringBuilder sb = new StringBuilder(); 264 sb.append("["); 265 for (int c = 0; c < channels.length; c++) { 266 sb.append(channels[c].frequency); 267 if (c != channels.length - 1) { 268 sb.append(","); 269 } 270 } 271 sb.append("]"); 272 return sb.toString(); 273 } 274 275 private static String toString(WifiNative.ChannelSettings[] channels, int numChannels) { 276 if (channels == null) { 277 return "null"; 278 } 279 280 StringBuilder sb = new StringBuilder(); 281 sb.append("["); 282 for (int c = 0; c < numChannels; c++) { 283 sb.append(channels[c].frequency); 284 if (c != numChannels - 1) { 285 sb.append(","); 286 } 287 } 288 sb.append("]"); 289 return sb.toString(); 290 } 291 292 private static String toString(int band) { 293 switch (band) { 294 case WifiScanner.WIFI_BAND_UNSPECIFIED: 295 return "unspecified"; 296 case WifiScanner.WIFI_BAND_24_GHZ: 297 return "24Ghz"; 298 case WifiScanner.WIFI_BAND_5_GHZ: 299 return "5Ghz (no DFS)"; 300 case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY: 301 return "5Ghz (DFS only)"; 302 case WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS: 303 return "5Ghz (DFS incl)"; 304 case WifiScanner.WIFI_BAND_BOTH: 305 return "24Ghz & 5Ghz (no DFS)"; 306 case WifiScanner.WIFI_BAND_BOTH_WITH_DFS: 307 return "24Ghz & 5Ghz (DFS incl)"; 308 } 309 310 return "invalid band"; 311 } 312 } 313