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