ScanScheduleUtil.java revision c4f23cbd6de85cbffcd91b398e51eff106ef08d4
1/* 2 * Copyright (C) 2015 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 17package com.android.server.wifi.scanner; 18 19import android.annotation.Nullable; 20import android.net.wifi.ScanResult; 21import android.net.wifi.WifiScanner.ScanData; 22import android.net.wifi.WifiScanner.ScanSettings; 23 24import com.android.server.wifi.WifiNative; 25 26import java.util.ArrayList; 27import java.util.List; 28 29/** 30 * A class with utilities for dealing with scan schedules. 31 */ 32public class ScanScheduleUtil { 33 34 /** 35 * Compares two ChannelSettings for equality. 36 */ 37 public static boolean channelEquals(@Nullable WifiNative.ChannelSettings channel1, 38 @Nullable WifiNative.ChannelSettings channel2) { 39 if (channel1 == null || channel2 == null) return false; 40 if (channel1 == channel2) return true; 41 42 if (channel1.frequency != channel2.frequency) return false; 43 if (channel1.dwell_time_ms != channel2.dwell_time_ms) return false; 44 return channel1.passive == channel2.passive; 45 } 46 47 /** 48 * Compares two BucketSettings for equality. 49 */ 50 public static boolean bucketEquals(@Nullable WifiNative.BucketSettings bucket1, 51 @Nullable WifiNative.BucketSettings bucket2) { 52 if (bucket1 == null || bucket2 == null) return false; 53 if (bucket1 == bucket2) return true; 54 55 if (bucket1.bucket != bucket2.bucket) return false; 56 if (bucket1.band != bucket2.band) return false; 57 if (bucket1.period_ms != bucket2.period_ms) return false; 58 if (bucket1.report_events != bucket2.report_events) return false; 59 if (bucket1.num_channels != bucket2.num_channels) return false; 60 for (int c = 0; c < bucket1.num_channels; c++) { 61 if (!channelEquals(bucket1.channels[c], bucket2.channels[c])) { 62 return false; 63 } 64 } 65 66 return true; 67 } 68 69 /** 70 * Compares two ScanSettings for equality. 71 */ 72 public static boolean scheduleEquals(@Nullable WifiNative.ScanSettings schedule1, 73 @Nullable WifiNative.ScanSettings schedule2) { 74 if (schedule1 == null || schedule2 == null) return false; 75 if (schedule1 == schedule2) return true; 76 77 if (schedule1.base_period_ms != schedule2.base_period_ms) return false; 78 if (schedule1.max_ap_per_scan != schedule2.max_ap_per_scan) return false; 79 if (schedule1.report_threshold_percent != schedule2.report_threshold_percent) return false; 80 if (schedule1.report_threshold_num_scans != schedule2.report_threshold_num_scans) { 81 return false; 82 } 83 if (schedule1.num_buckets != schedule2.num_buckets) return false; 84 for (int b = 0; b < schedule1.num_buckets; b++) { 85 if (!bucketEquals(schedule1.buckets[b], schedule2.buckets[b])) { 86 return false; 87 } 88 } 89 90 return true; 91 } 92 93 /** 94 * Check if the specified bucket was scanned. If not all information is available then this 95 * method will return true. 96 * 97 * @param scheduledBucket Index of the bucket to check for, zero indexed, or -1 if unavailable 98 * @param bucketsScannedBitSet The bitset of all buckets scanned, 0 if unavailable 99 */ 100 private static boolean isBucketMaybeScanned(int scheduledBucket, int bucketsScannedBitSet) { 101 if (bucketsScannedBitSet == 0 || scheduledBucket < 0) { 102 return true; 103 } else { 104 return (bucketsScannedBitSet & (1 << scheduledBucket)) != 0; 105 } 106 } 107 108 /** 109 * Check if the specified bucket was scanned. If not all information is available then this 110 * method will return false. 111 * 112 * @param scheduledBucket Index of the bucket to check for, zero indexed, or -1 if unavailable 113 * @param bucketsScannedBitSet The bitset of all buckets scanned, 0 if unavailable 114 */ 115 private static boolean isBucketDefinitlyScanned(int scheduledBucket, int bucketsScannedBitSet) { 116 if (bucketsScannedBitSet == 0 || scheduledBucket < 0) { 117 return false; 118 } else { 119 return (bucketsScannedBitSet & (1 << scheduledBucket)) != 0; 120 } 121 } 122 123 /** 124 * Returns true if the given scan result should be reported to a listener with the given 125 * settings. 126 */ 127 public static boolean shouldReportFullScanResultForSettings(ChannelHelper channelHelper, 128 ScanResult result, int bucketsScanned, ScanSettings settings, int scheduledBucket) { 129 if (isBucketMaybeScanned(scheduledBucket, bucketsScanned)) { 130 return channelHelper.settingsContainChannel(settings, result.frequency); 131 } else { 132 return false; 133 } 134 } 135 136 /** 137 * Returns a filtered version of the scan results from the chip that represents only the data 138 * requested in the settings. Will return null if the result should not be reported. 139 * 140 * If a ScanData indicates that the bucket the settings were placed in was scanned then it 141 * will always be included (filtered to only include requested channels). If it indicates that 142 * the bucket was definitely not scanned then the scan data will not be reported. 143 * If it is not possible to determine if the settings bucket was scanned or not then a 144 * ScanData will be included if the scan was empty or there was at least one scan result that 145 * matches a requested channel (again the results will be filtered to only include requested 146 * channels. 147 */ 148 public static ScanData[] filterResultsForSettings(ChannelHelper channelHelper, 149 ScanData[] scanDatas, ScanSettings settings, int scheduledBucket) { 150 List<ScanData> filteredScanDatas = new ArrayList<>(scanDatas.length); 151 List<ScanResult> filteredResults = new ArrayList<>(); 152 for (ScanData scanData : scanDatas) { 153 // only report ScanData if the settings bucket could have been scanned 154 if (isBucketMaybeScanned(scheduledBucket, scanData.getBucketsScanned())) { 155 filteredResults.clear(); 156 for (ScanResult scanResult : scanData.getResults()) { 157 if (channelHelper.settingsContainChannel(settings, scanResult.frequency)) { 158 filteredResults.add(scanResult); 159 } 160 if (settings.numBssidsPerScan > 0 161 && filteredResults.size() >= settings.numBssidsPerScan) { 162 break; 163 } 164 } 165 // will include scan results if the scan was empty, there was at least one 166 // one result that matched the scan request or we are sure that all the requested 167 // channels were scanned. 168 if (filteredResults.size() == scanData.getResults().length) { 169 filteredScanDatas.add(scanData); 170 } else if (filteredResults.size() > 0 || isBucketDefinitlyScanned(scheduledBucket, 171 scanData.getBucketsScanned())) { 172 filteredScanDatas.add(new ScanData(scanData.getId(), 173 scanData.getFlags(), 174 filteredResults.toArray( 175 new ScanResult[filteredResults.size()]))); 176 } 177 } 178 } 179 if (filteredScanDatas.size() == 0) { 180 return null; 181 } else { 182 return filteredScanDatas.toArray(new ScanData[filteredScanDatas.size()]); 183 } 184 } 185} 186