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 static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ; 20 import static android.net.wifi.WifiScanner.WIFI_BAND_5_GHZ; 21 import static android.net.wifi.WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY; 22 import static android.net.wifi.WifiScanner.WIFI_BAND_60_GHZ; 23 import static android.net.wifi.WifiScanner.WIFI_BAND_6_GHZ; 24 import static android.net.wifi.WifiScanner.WIFI_BAND_ALL; 25 import static android.net.wifi.WifiScanner.WIFI_BAND_COUNT; 26 import static android.net.wifi.WifiScanner.WIFI_BAND_INDEX_24_GHZ; 27 import static android.net.wifi.WifiScanner.WIFI_BAND_INDEX_5_GHZ; 28 import static android.net.wifi.WifiScanner.WIFI_BAND_INDEX_5_GHZ_DFS_ONLY; 29 import static android.net.wifi.WifiScanner.WIFI_BAND_INDEX_60_GHZ; 30 import static android.net.wifi.WifiScanner.WIFI_BAND_INDEX_6_GHZ; 31 import static android.net.wifi.WifiScanner.WIFI_BAND_UNSPECIFIED; 32 33 import android.net.wifi.ScanResult; 34 import android.net.wifi.WifiAnnotations.WifiBandBasic; 35 import android.net.wifi.WifiScanner; 36 import android.net.wifi.WifiScanner.WifiBandIndex; 37 import android.util.ArraySet; 38 39 import com.android.server.wifi.WifiNative; 40 import com.android.server.wifi.proto.WifiStatsLog; 41 42 import java.util.ArrayList; 43 import java.util.Arrays; 44 import java.util.List; 45 import java.util.Set; 46 import java.util.stream.Collectors; 47 48 /** 49 * ChannelHelper that offers channel manipulation utilities when the channels in a band are known. 50 * This allows more fine operations on channels than if band channels are not known. 51 */ 52 public class KnownBandsChannelHelper extends ChannelHelper { 53 // 5G low includes U-NII-1 and Japan 4.9G band 54 public static final int BAND_5_GHZ_LOW_END_FREQ = 5240; 55 // 5G middle includes U-NII-2A and U-NII-2C 56 public static final int BAND_5_GHZ_MID_END_FREQ = 5710; 57 // 5G high includes U-NII-3 58 public static final int BAND_5_GHZ_HIGH_END_FREQ = ScanResult.BAND_5_GHZ_END_FREQ_MHZ; 59 // 6G low includes UNII-5 60 public static final int BAND_6_GHZ_LOW_END_FREQ = 6425; 61 // 6G middle includes UNII-6 and UNII-7 62 public static final int BAND_6_GHZ_MID_END_FREQ = 6875; 63 // 6G high includes UNII-8 64 public static final int BAND_6_GHZ_HIGH_END_FREQ = ScanResult.BAND_6_GHZ_END_FREQ_MHZ; 65 66 private WifiScanner.ChannelSpec[][] mBandsToChannels; 67 setBandChannels(int[] channels2G, int[] channels5G, int[] channelsDfs, int[] channels6G, int[] channels60G)68 protected void setBandChannels(int[] channels2G, int[] channels5G, int[] channelsDfs, 69 int[] channels6G, int[] channels60G) { 70 mBandsToChannels = new WifiScanner.ChannelSpec[WIFI_BAND_COUNT][]; 71 72 for (int i = 0; i < WIFI_BAND_COUNT; i++) { 73 mBandsToChannels[i] = NO_CHANNELS; 74 } 75 76 if (channels2G.length != 0) { 77 mBandsToChannels[WIFI_BAND_INDEX_24_GHZ] = 78 new WifiScanner.ChannelSpec[channels2G.length]; 79 copyChannels(mBandsToChannels[WIFI_BAND_INDEX_24_GHZ], channels2G); 80 } else { 81 mBandsToChannels[WIFI_BAND_INDEX_24_GHZ] = NO_CHANNELS; 82 } 83 84 if (channels5G.length != 0) { 85 mBandsToChannels[WIFI_BAND_INDEX_5_GHZ] = 86 new WifiScanner.ChannelSpec[channels5G.length]; 87 copyChannels(mBandsToChannels[WIFI_BAND_INDEX_5_GHZ], channels5G); 88 } else { 89 mBandsToChannels[WIFI_BAND_INDEX_5_GHZ] = NO_CHANNELS; 90 } 91 92 if (channelsDfs.length != 0) { 93 mBandsToChannels[WIFI_BAND_INDEX_5_GHZ_DFS_ONLY] = 94 new WifiScanner.ChannelSpec[channelsDfs.length]; 95 copyChannels(mBandsToChannels[WIFI_BAND_INDEX_5_GHZ_DFS_ONLY], channelsDfs); 96 } else { 97 mBandsToChannels[WIFI_BAND_INDEX_5_GHZ_DFS_ONLY] = NO_CHANNELS; 98 } 99 100 if (channels6G.length != 0) { 101 mBandsToChannels[WIFI_BAND_INDEX_6_GHZ] = 102 new WifiScanner.ChannelSpec[channels6G.length]; 103 copyChannels(mBandsToChannels[WIFI_BAND_INDEX_6_GHZ], channels6G); 104 } else { 105 mBandsToChannels[WIFI_BAND_INDEX_6_GHZ] = NO_CHANNELS; 106 } 107 108 if (channels60G.length != 0) { 109 mBandsToChannels[WIFI_BAND_INDEX_60_GHZ] = 110 new WifiScanner.ChannelSpec[channels60G.length]; 111 copyChannels(mBandsToChannels[WIFI_BAND_INDEX_60_GHZ], channels60G); 112 } else { 113 mBandsToChannels[WIFI_BAND_INDEX_60_GHZ] = NO_CHANNELS; 114 } 115 } 116 copyChannels( WifiScanner.ChannelSpec[] channelSpec, int[] channels)117 private static void copyChannels( 118 WifiScanner.ChannelSpec[] channelSpec, int[] channels) { 119 for (int i = 0; i < channels.length; i++) { 120 channelSpec[i] = new WifiScanner.ChannelSpec(channels[i]); 121 } 122 } 123 124 @Override getAvailableScanChannels(int band)125 public WifiScanner.ChannelSpec[][] getAvailableScanChannels(int band) { 126 if (band <= WIFI_BAND_UNSPECIFIED || band > WIFI_BAND_ALL) { 127 // Invalid value for band. 128 return null; 129 } 130 131 List<WifiScanner.ChannelSpec[]> channelList = new ArrayList<>(); 132 for (@WifiBandIndex int index = 0; index < WIFI_BAND_COUNT; index++) { 133 if ((band & (1 << index)) != 0 && mBandsToChannels[index].length > 0) { 134 channelList.add(mBandsToChannels[index]); 135 } 136 } 137 138 return channelList.toArray(new WifiScanner.ChannelSpec[0][0]); 139 } 140 141 @Override satisfies(ChannelHelper otherChannelHelper)142 public boolean satisfies(ChannelHelper otherChannelHelper) { 143 if (!(otherChannelHelper instanceof KnownBandsChannelHelper)) return false; 144 KnownBandsChannelHelper otherKnownBandsChannelHelper = 145 (KnownBandsChannelHelper) otherChannelHelper; 146 // Compare all the channels in every band 147 for (@WifiBandIndex int i = 0; i < WIFI_BAND_COUNT; i++) { 148 Set<Integer> thisFrequencies = Arrays.stream(mBandsToChannels[i]) 149 .map(spec -> spec.frequency) 150 .collect(Collectors.toSet()); 151 Set<Integer> otherFrequencies = Arrays.stream( 152 otherKnownBandsChannelHelper.mBandsToChannels[i]) 153 .map(spec -> spec.frequency) 154 .collect(Collectors.toSet()); 155 if (!thisFrequencies.containsAll(otherFrequencies)) { 156 return false; 157 } 158 } 159 return true; 160 } 161 162 @Override estimateScanDuration(WifiScanner.ScanSettings settings)163 public int estimateScanDuration(WifiScanner.ScanSettings settings) { 164 if (settings.band == WIFI_BAND_UNSPECIFIED) { 165 return settings.channels.length * SCAN_PERIOD_PER_CHANNEL_MS; 166 } else { 167 WifiScanner.ChannelSpec[][] channels = getAvailableScanChannels(settings.band); 168 int len = 0; 169 for (int i = 0; i < channels.length; ++i) { 170 len += channels[i].length; 171 } 172 return len * SCAN_PERIOD_PER_CHANNEL_MS; 173 } 174 } 175 isDfsChannel(int frequency)176 private boolean isDfsChannel(int frequency) { 177 for (WifiScanner.ChannelSpec dfsChannel : 178 mBandsToChannels[WIFI_BAND_INDEX_5_GHZ_DFS_ONLY]) { 179 if (frequency == dfsChannel.frequency) { 180 return true; 181 } 182 } 183 return false; 184 } 185 186 // TODO this should be rewritten to be based on the input data instead of hardcoded ranges getBandFromChannel(int frequency)187 private int getBandFromChannel(int frequency) { 188 if (ScanResult.is24GHz(frequency)) { 189 return WIFI_BAND_24_GHZ; 190 } else if (ScanResult.is5GHz(frequency)) { 191 if (isDfsChannel(frequency)) { 192 return WIFI_BAND_5_GHZ_DFS_ONLY; 193 } else { 194 return WIFI_BAND_5_GHZ; 195 } 196 } else if (ScanResult.is6GHz(frequency)) { 197 return WIFI_BAND_6_GHZ; 198 } else if (ScanResult.is60GHz(frequency)) { 199 return WIFI_BAND_60_GHZ; 200 } else { 201 return WIFI_BAND_UNSPECIFIED; 202 } 203 } 204 getIndexForBand(@ifiBandBasic int band)205 private @WifiBandIndex int getIndexForBand(@WifiBandBasic int band) { 206 switch (band) { 207 case WIFI_BAND_24_GHZ: 208 return WIFI_BAND_INDEX_24_GHZ; 209 case WIFI_BAND_5_GHZ: 210 return WIFI_BAND_INDEX_5_GHZ; 211 case WIFI_BAND_5_GHZ_DFS_ONLY: 212 return WIFI_BAND_INDEX_5_GHZ_DFS_ONLY; 213 case WIFI_BAND_6_GHZ: 214 return WIFI_BAND_INDEX_6_GHZ; 215 case WIFI_BAND_60_GHZ: 216 return WIFI_BAND_INDEX_60_GHZ; 217 default: 218 return -1; 219 } 220 } 221 222 @Override settingsContainChannel(WifiScanner.ScanSettings settings, int channel)223 public boolean settingsContainChannel(WifiScanner.ScanSettings settings, int channel) { 224 WifiScanner.ChannelSpec[] settingsChannels; 225 @WifiBandBasic int band; 226 // If band is not specified in settings, limit check on channels in settings 227 if (settings.band == WIFI_BAND_UNSPECIFIED) { 228 settingsChannels = settings.channels; 229 } else { 230 // Get the proper band for this channel 231 band = getBandFromChannel(channel); 232 // Check if this band is included in band specified in settings 233 if ((settings.band & band) == WIFI_BAND_UNSPECIFIED) { 234 return false; 235 } 236 237 settingsChannels = mBandsToChannels[getIndexForBand(band)]; 238 } 239 // Now search for the channel 240 for (int i = 0; i < settingsChannels.length; ++i) { 241 if (settingsChannels[i].frequency == channel) { 242 return true; 243 } 244 } 245 return false; 246 } 247 248 /** 249 * Convert Wifi channel frequency to a bucketed band value. 250 * 251 * @param frequency Frequency (e.g. 2417) 252 * @return WifiBandBucket enum value (e.g. BAND_2G) 253 */ getBand(int frequency)254 public static int getBand(int frequency) { 255 int band = WifiStatsLog.WIFI_HEALTH_STAT_REPORTED__BAND__UNKNOWN; 256 257 if (ScanResult.is24GHz(frequency)) { 258 band = WifiStatsLog.WIFI_HEALTH_STAT_REPORTED__BAND__BAND_2G; 259 } else if (ScanResult.is5GHz(frequency)) { 260 if (frequency <= BAND_5_GHZ_LOW_END_FREQ) { 261 band = WifiStatsLog.WIFI_HEALTH_STAT_REPORTED__BAND__BAND_5G_LOW; 262 } else if (frequency <= BAND_5_GHZ_MID_END_FREQ) { 263 band = WifiStatsLog.WIFI_HEALTH_STAT_REPORTED__BAND__BAND_5G_MIDDLE; 264 } else { 265 band = WifiStatsLog.WIFI_HEALTH_STAT_REPORTED__BAND__BAND_5G_HIGH; 266 } 267 } else if (ScanResult.is6GHz(frequency)) { 268 if (frequency <= BAND_6_GHZ_LOW_END_FREQ) { 269 band = WifiStatsLog.WIFI_HEALTH_STAT_REPORTED__BAND__BAND_6G_LOW; 270 } else if (frequency <= BAND_6_GHZ_MID_END_FREQ) { 271 band = WifiStatsLog.WIFI_HEALTH_STAT_REPORTED__BAND__BAND_6G_MIDDLE; 272 } else { 273 band = WifiStatsLog.WIFI_HEALTH_STAT_REPORTED__BAND__BAND_6G_HIGH; 274 } 275 } 276 277 return band; 278 } 279 280 /** 281 * ChannelCollection that merges channels so that the optimal schedule will be generated. 282 * When the max channels value is satisfied this implementation will always create a channel 283 * list that includes no more than the added channels. 284 */ 285 public class KnownBandsChannelCollection extends ChannelCollection { 286 /** 287 * Stores all channels, including those that belong to added bands. 288 */ 289 private final ArraySet<Integer> mChannels = new ArraySet<Integer>(); 290 /** 291 * Contains only the bands that were explicitly added as bands. 292 */ 293 private int mExactBands = 0; 294 /** 295 * Contains all bands, including those that were added because an added channel was in that 296 * band. 297 */ 298 private int mAllBands = 0; 299 300 @Override addChannel(int frequency)301 public void addChannel(int frequency) { 302 mChannels.add(frequency); 303 mAllBands |= getBandFromChannel(frequency); 304 } 305 306 @Override addBand(int band)307 public void addBand(int band) { 308 mExactBands |= band; 309 mAllBands |= band; 310 WifiScanner.ChannelSpec[][] bandChannels = getAvailableScanChannels(band); 311 for (int i = 0; i < bandChannels.length; ++i) { 312 for (int j = 0; j < bandChannels[i].length; ++j) { 313 mChannels.add(bandChannels[i][j].frequency); 314 } 315 } 316 } 317 318 @Override containsChannel(int channel)319 public boolean containsChannel(int channel) { 320 return mChannels.contains(channel); 321 } 322 323 @Override containsBand(int band)324 public boolean containsBand(int band) { 325 WifiScanner.ChannelSpec[][] bandChannels = getAvailableScanChannels(band); 326 327 for (int i = 0; i < bandChannels.length; ++i) { 328 for (int j = 0; j < bandChannels[i].length; ++j) { 329 if (!mChannels.contains(bandChannels[i][j].frequency)) { 330 return false; 331 } 332 } 333 } 334 return true; 335 } 336 337 @Override partiallyContainsBand(int band)338 public boolean partiallyContainsBand(int band) { 339 WifiScanner.ChannelSpec[][] bandChannels = getAvailableScanChannels(band); 340 for (int i = 0; i < bandChannels.length; ++i) { 341 for (int j = 0; j < bandChannels[i].length; ++j) { 342 if (mChannels.contains(bandChannels[i][j].frequency)) { 343 return true; 344 } 345 } 346 } 347 return false; 348 } 349 350 @Override isEmpty()351 public boolean isEmpty() { 352 return mChannels.isEmpty(); 353 } 354 355 @Override isAllChannels()356 public boolean isAllChannels() { 357 return containsBand(WIFI_BAND_ALL); 358 } 359 360 @Override clear()361 public void clear() { 362 mAllBands = 0; 363 mExactBands = 0; 364 mChannels.clear(); 365 } 366 367 @Override getMissingChannelsFromBand(int band)368 public Set<Integer> getMissingChannelsFromBand(int band) { 369 ArraySet<Integer> missingChannels = new ArraySet<>(); 370 WifiScanner.ChannelSpec[][] bandChannels = getAvailableScanChannels(band); 371 for (int i = 0; i < bandChannels.length; ++i) { 372 for (int j = 0; j < bandChannels[i].length; ++j) { 373 if (!mChannels.contains(bandChannels[i][j].frequency)) { 374 missingChannels.add(bandChannels[i][j].frequency); 375 } 376 } 377 } 378 return missingChannels; 379 } 380 381 @Override getContainingChannelsFromBand(int band)382 public Set<Integer> getContainingChannelsFromBand(int band) { 383 ArraySet<Integer> containingChannels = new ArraySet<>(); 384 WifiScanner.ChannelSpec[][] bandChannels = getAvailableScanChannels(band); 385 for (int i = 0; i < bandChannels.length; ++i) { 386 for (int j = 0; j < bandChannels[i].length; ++j) { 387 if (mChannels.contains(bandChannels[i][j].frequency)) { 388 containingChannels.add(bandChannels[i][j].frequency); 389 } 390 } 391 } 392 return containingChannels; 393 } 394 395 @Override getChannelSet()396 public Set<Integer> getChannelSet() { 397 if (!isEmpty() && mAllBands != mExactBands) { 398 return mChannels; 399 } else { 400 return new ArraySet<>(); 401 } 402 } 403 404 @Override add6GhzPscChannels()405 public void add6GhzPscChannels() { 406 Set<Integer> missingChannels = getMissingChannelsFromBand(WIFI_BAND_6_GHZ); 407 if (missingChannels.isEmpty()) { 408 return; 409 } 410 for (int freq : missingChannels) { 411 if (ScanResult.is6GHzPsc(freq)) { 412 mChannels.add(freq); 413 mAllBands |= WIFI_BAND_6_GHZ; 414 } 415 } 416 } 417 418 @Override fillBucketSettings(WifiNative.BucketSettings bucketSettings, int maxChannels)419 public void fillBucketSettings(WifiNative.BucketSettings bucketSettings, int maxChannels) { 420 if ((mChannels.size() > maxChannels || mAllBands == mExactBands) && mAllBands != 0) { 421 bucketSettings.band = mAllBands; 422 bucketSettings.num_channels = 0; 423 bucketSettings.channels = null; 424 } else { 425 bucketSettings.band = WIFI_BAND_UNSPECIFIED; 426 bucketSettings.num_channels = mChannels.size(); 427 bucketSettings.channels = new WifiNative.ChannelSettings[mChannels.size()]; 428 for (int i = 0; i < mChannels.size(); ++i) { 429 WifiNative.ChannelSettings channelSettings = new WifiNative.ChannelSettings(); 430 channelSettings.frequency = mChannels.valueAt(i); 431 bucketSettings.channels[i] = channelSettings; 432 } 433 } 434 } 435 436 @Override getScanFreqs()437 public Set<Integer> getScanFreqs() { 438 if (mExactBands == WIFI_BAND_ALL) { 439 return null; 440 } else { 441 return new ArraySet<Integer>(mChannels); 442 } 443 } 444 getAllChannels()445 public Set<Integer> getAllChannels() { 446 return new ArraySet<Integer>(mChannels); 447 } 448 } 449 450 @Override createChannelCollection()451 public KnownBandsChannelCollection createChannelCollection() { 452 return new KnownBandsChannelCollection(); 453 } 454 } 455