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