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 17 package com.android.server.wifi.scanner; 18 19 import android.app.AlarmManager; 20 import android.content.Context; 21 import android.net.wifi.ScanResult; 22 import android.net.wifi.WifiScanner; 23 import android.net.wifi.WifiScanner.WifiBandIndex; 24 import android.net.wifi.util.ScanResultUtil; 25 import android.os.Handler; 26 import android.os.Looper; 27 import android.os.Message; 28 import android.util.Log; 29 30 import com.android.server.wifi.Clock; 31 import com.android.server.wifi.ScanDetail; 32 import com.android.server.wifi.WifiGlobals; 33 import com.android.server.wifi.WifiMonitor; 34 import com.android.server.wifi.WifiNative; 35 import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection; 36 import com.android.server.wifi.util.NativeUtil; 37 38 import java.io.FileDescriptor; 39 import java.io.PrintWriter; 40 import java.util.ArrayList; 41 import java.util.Collections; 42 import java.util.List; 43 import java.util.Set; 44 import java.util.stream.Collectors; 45 46 import javax.annotation.concurrent.GuardedBy; 47 48 /** 49 * Implementation of the WifiScanner HAL API that uses wificond to perform all scans 50 * @see com.android.server.wifi.scanner.WifiScannerImpl for more details on each method. 51 */ 52 public class WificondScannerImpl extends WifiScannerImpl implements Handler.Callback { 53 private static final String TAG = "WificondScannerImpl"; 54 private static final boolean DBG = false; 55 56 public static final String TIMEOUT_ALARM_TAG = TAG + " Scan Timeout"; 57 // Default number of networks that can be specified to wificond per scan request 58 public static final int DEFAULT_NUM_HIDDEN_NETWORK_IDS_PER_SCAN = 16; 59 60 private static final int SCAN_BUFFER_CAPACITY = 10; 61 private static final int MAX_APS_PER_SCAN = 32; 62 private static final int MAX_SCAN_BUCKETS = 16; 63 64 private final Context mContext; 65 private final WifiGlobals mWifiGlobals; 66 private final WifiNative mWifiNative; 67 private final WifiMonitor mWifiMonitor; 68 private final AlarmManager mAlarmManager; 69 private final Handler mEventHandler; 70 private final ChannelHelper mChannelHelper; 71 private final Clock mClock; 72 73 private final Object mSettingsLock = new Object(); 74 75 private ArrayList<ScanDetail> mNativeScanResults; 76 private ArrayList<ScanDetail> mNativePnoScanResults; 77 private WifiScanner.ScanData mLatestSingleScanResult = 78 new WifiScanner.ScanData(0, 0, new ScanResult[0]); 79 private int mMaxNumScanSsids = -1; 80 private int mNextHiddenNetworkScanId = 0; 81 82 // Settings for the currently running single scan, null if no scan active 83 private LastScanSettings mLastScanSettings = null; 84 // Settings for the currently running pno scan, null if no scan active 85 private LastPnoScanSettings mLastPnoScanSettings = null; 86 87 /** 88 * Duration to wait before timing out a scan. 89 * 90 * The expected behavior is that the hardware will return a failed scan if it does not 91 * complete, but timeout just in case it does not. 92 */ 93 private static final long SCAN_TIMEOUT_MS = 15000; 94 95 @GuardedBy("mSettingsLock") 96 private AlarmManager.OnAlarmListener mScanTimeoutListener; 97 WificondScannerImpl(Context context, String ifaceName, WifiGlobals wifiGlobals, WifiNative wifiNative, WifiMonitor wifiMonitor, ChannelHelper channelHelper, Looper looper, Clock clock)98 public WificondScannerImpl(Context context, String ifaceName, WifiGlobals wifiGlobals, 99 WifiNative wifiNative, WifiMonitor wifiMonitor, 100 ChannelHelper channelHelper, Looper looper, Clock clock) { 101 super(ifaceName); 102 mContext = context; 103 mWifiGlobals = wifiGlobals; 104 mWifiNative = wifiNative; 105 mWifiMonitor = wifiMonitor; 106 mChannelHelper = channelHelper; 107 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 108 mEventHandler = new Handler(looper, this); 109 mClock = clock; 110 111 wifiMonitor.registerHandler(getIfaceName(), 112 WifiMonitor.SCAN_FAILED_EVENT, mEventHandler); 113 wifiMonitor.registerHandler(getIfaceName(), 114 WifiMonitor.PNO_SCAN_RESULTS_EVENT, mEventHandler); 115 wifiMonitor.registerHandler(getIfaceName(), 116 WifiMonitor.SCAN_RESULTS_EVENT, mEventHandler); 117 } 118 119 @Override cleanup()120 public void cleanup() { 121 synchronized (mSettingsLock) { 122 cancelScanTimeout(); 123 reportScanFailure(WifiScanner.REASON_UNSPECIFIED); 124 stopHwPnoScan(); 125 mMaxNumScanSsids = -1; 126 mNextHiddenNetworkScanId = 0; 127 mLastScanSettings = null; // finally clear any active scan 128 mLastPnoScanSettings = null; // finally clear any active scan 129 mWifiMonitor.deregisterHandler(getIfaceName(), 130 WifiMonitor.SCAN_FAILED_EVENT, mEventHandler); 131 mWifiMonitor.deregisterHandler(getIfaceName(), 132 WifiMonitor.PNO_SCAN_RESULTS_EVENT, mEventHandler); 133 mWifiMonitor.deregisterHandler(getIfaceName(), 134 WifiMonitor.SCAN_RESULTS_EVENT, mEventHandler); 135 } 136 } 137 138 @Override getScanCapabilities(WifiNative.ScanCapabilities capabilities)139 public boolean getScanCapabilities(WifiNative.ScanCapabilities capabilities) { 140 capabilities.max_scan_cache_size = Integer.MAX_VALUE; 141 capabilities.max_scan_buckets = MAX_SCAN_BUCKETS; 142 capabilities.max_ap_cache_per_scan = MAX_APS_PER_SCAN; 143 capabilities.max_rssi_sample_size = 8; 144 capabilities.max_scan_reporting_threshold = SCAN_BUFFER_CAPACITY; 145 return true; 146 } 147 148 @Override getChannelHelper()149 public ChannelHelper getChannelHelper() { 150 return mChannelHelper; 151 } 152 153 @Override startSingleScan(WifiNative.ScanSettings settings, WifiNative.ScanEventHandler eventHandler)154 public boolean startSingleScan(WifiNative.ScanSettings settings, 155 WifiNative.ScanEventHandler eventHandler) { 156 if (eventHandler == null || settings == null) { 157 Log.w(TAG, "Invalid arguments for startSingleScan: settings=" + settings 158 + ",eventHandler=" + eventHandler); 159 return false; 160 } 161 synchronized (mSettingsLock) { 162 if (mLastScanSettings != null) { 163 Log.w(TAG, "A single scan is already running"); 164 return false; 165 } 166 167 ChannelCollection allFreqs = mChannelHelper.createChannelCollection(); 168 boolean reportFullResults = false; 169 170 for (int i = 0; i < settings.num_buckets; ++i) { 171 WifiNative.BucketSettings bucketSettings = settings.buckets[i]; 172 if ((bucketSettings.report_events 173 & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) { 174 reportFullResults = true; 175 } 176 allFreqs.addChannels(bucketSettings); 177 } 178 179 List<String> hiddenNetworkSSIDSet = new ArrayList<>(); 180 if (settings.hiddenNetworks != null) { 181 boolean executeRoundRobin = true; 182 int maxNumScanSsids = mMaxNumScanSsids; 183 if (maxNumScanSsids <= 0) { 184 // Subtract 1 to account for the wildcard/broadcast probe request that 185 // wificond adds to the scan set. 186 mMaxNumScanSsids = mWifiNative.getMaxSsidsPerScan(getIfaceName()) - 1; 187 if (mMaxNumScanSsids > 0) { 188 maxNumScanSsids = mMaxNumScanSsids; 189 } else { 190 maxNumScanSsids = DEFAULT_NUM_HIDDEN_NETWORK_IDS_PER_SCAN; 191 executeRoundRobin = false; 192 } 193 } 194 int numHiddenNetworksPerScan = 195 Math.min(settings.hiddenNetworks.length, maxNumScanSsids); 196 if (numHiddenNetworksPerScan == settings.hiddenNetworks.length 197 || mNextHiddenNetworkScanId >= settings.hiddenNetworks.length 198 || !executeRoundRobin) { 199 mNextHiddenNetworkScanId = 0; 200 } 201 if (DBG) { 202 Log.d(TAG, "Scanning for " + numHiddenNetworksPerScan + " out of " 203 + settings.hiddenNetworks.length + " total hidden networks"); 204 Log.d(TAG, "Scan hidden networks starting at id=" + mNextHiddenNetworkScanId); 205 } 206 207 int id = mNextHiddenNetworkScanId; 208 for (int i = 0; i < numHiddenNetworksPerScan; i++, id++) { 209 hiddenNetworkSSIDSet.add( 210 settings.hiddenNetworks[id % settings.hiddenNetworks.length].ssid); 211 } 212 mNextHiddenNetworkScanId = id % settings.hiddenNetworks.length; 213 } 214 mLastScanSettings = new LastScanSettings( 215 mClock.getElapsedSinceBootNanos(), 216 reportFullResults, allFreqs, eventHandler); 217 218 int scanStatus = WifiScanner.REASON_UNSPECIFIED; 219 Set<Integer> freqs = Collections.emptySet(); 220 if (!allFreqs.isEmpty()) { 221 freqs = allFreqs.getScanFreqs(); 222 scanStatus = mWifiNative.scan( 223 getIfaceName(), settings.scanType, freqs, hiddenNetworkSSIDSet, 224 settings.enable6GhzRnr, settings.vendorIes); 225 if (scanStatus != WifiScanner.REASON_SUCCEEDED) { 226 Log.e(TAG, "Failed to start scan, freqs=" + freqs + " status: " 227 + scanStatus); 228 } 229 } else { 230 // There is a scan request but no available channels could be scanned for. 231 // We regard it as a scan failure in this case. 232 Log.e(TAG, "Failed to start scan because there is no available channel to scan"); 233 } 234 if (scanStatus == WifiScanner.REASON_SUCCEEDED) { 235 if (DBG) { 236 Log.d(TAG, "Starting wifi scan for freqs=" + freqs 237 + " on iface " + getIfaceName()); 238 } 239 240 mScanTimeoutListener = new AlarmManager.OnAlarmListener() { 241 @Override public void onAlarm() { 242 handleScanTimeout(); 243 } 244 }; 245 246 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 247 mClock.getElapsedSinceBootMillis() + SCAN_TIMEOUT_MS, 248 TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler); 249 } else { 250 // indicate scan failure async 251 int finalScanStatus = scanStatus; 252 mEventHandler.post(() -> reportScanFailure(finalScanStatus)); 253 } 254 255 return true; 256 } 257 } 258 259 @Override getLatestSingleScanResults()260 public WifiScanner.ScanData getLatestSingleScanResults() { 261 return mLatestSingleScanResult; 262 } 263 264 @Override startBatchedScan(WifiNative.ScanSettings settings, WifiNative.ScanEventHandler eventHandler)265 public boolean startBatchedScan(WifiNative.ScanSettings settings, 266 WifiNative.ScanEventHandler eventHandler) { 267 Log.w(TAG, "startBatchedScan() is not supported"); 268 return false; 269 } 270 271 @Override stopBatchedScan()272 public void stopBatchedScan() { 273 Log.w(TAG, "stopBatchedScan() is not supported"); 274 } 275 276 @Override pauseBatchedScan()277 public void pauseBatchedScan() { 278 Log.w(TAG, "pauseBatchedScan() is not supported"); 279 } 280 281 @Override restartBatchedScan()282 public void restartBatchedScan() { 283 Log.w(TAG, "restartBatchedScan() is not supported"); 284 } 285 handleScanTimeout()286 private void handleScanTimeout() { 287 synchronized (mSettingsLock) { 288 Log.e(TAG, "Timed out waiting for scan result from wificond"); 289 reportScanFailure(WifiScanner.REASON_TIMEOUT); 290 mScanTimeoutListener = null; 291 } 292 } 293 294 @Override handleMessage(Message msg)295 public boolean handleMessage(Message msg) { 296 switch(msg.what) { 297 case WifiMonitor.SCAN_FAILED_EVENT: 298 Log.w(TAG, "Scan failed: error code: " + msg.arg1); 299 cancelScanTimeout(); 300 reportScanFailure(msg.arg1); 301 break; 302 case WifiMonitor.PNO_SCAN_RESULTS_EVENT: 303 pollLatestScanDataForPno(); 304 break; 305 case WifiMonitor.SCAN_RESULTS_EVENT: 306 cancelScanTimeout(); 307 pollLatestScanData(); 308 break; 309 default: 310 // ignore unknown event 311 } 312 return true; 313 } 314 cancelScanTimeout()315 private void cancelScanTimeout() { 316 synchronized (mSettingsLock) { 317 if (mScanTimeoutListener != null) { 318 mAlarmManager.cancel(mScanTimeoutListener); 319 mScanTimeoutListener = null; 320 } 321 } 322 } 323 reportScanFailure(int errorCode)324 private void reportScanFailure(int errorCode) { 325 synchronized (mSettingsLock) { 326 if (mLastScanSettings != null) { 327 if (mLastScanSettings.singleScanEventHandler != null) { 328 mLastScanSettings.singleScanEventHandler 329 .onScanRequestFailed(errorCode); 330 } 331 mLastScanSettings = null; 332 } 333 } 334 } 335 reportPnoScanFailure()336 private void reportPnoScanFailure() { 337 synchronized (mSettingsLock) { 338 if (mLastPnoScanSettings != null) { 339 if (mLastPnoScanSettings.pnoScanEventHandler != null) { 340 mLastPnoScanSettings.pnoScanEventHandler.onPnoScanFailed(); 341 } 342 // Clean up PNO state, we don't want to continue PNO scanning. 343 mLastPnoScanSettings = null; 344 } 345 } 346 } 347 pollLatestScanDataForPno()348 private void pollLatestScanDataForPno() { 349 synchronized (mSettingsLock) { 350 if (mLastPnoScanSettings == null) { 351 // got a scan before we started scanning or after scan was canceled 352 return; 353 } 354 mNativePnoScanResults = mWifiNative.getPnoScanResults(getIfaceName()); 355 List<ScanResult> hwPnoScanResults = new ArrayList<>(); 356 int numFilteredScanResults = 0; 357 for (int i = 0; i < mNativePnoScanResults.size(); ++i) { 358 ScanResult result = mNativePnoScanResults.get(i).getScanResult(); 359 // nanoseconds -> microseconds 360 if (result.timestamp >= mLastPnoScanSettings.startTimeNanos / 1_000) { 361 hwPnoScanResults.add(result); 362 } else { 363 numFilteredScanResults++; 364 } 365 } 366 367 if (numFilteredScanResults != 0) { 368 Log.d(TAG, "Filtering out " + numFilteredScanResults + " pno scan results."); 369 } 370 371 if (mLastPnoScanSettings.pnoScanEventHandler != null) { 372 ScanResult[] pnoScanResultsArray = 373 hwPnoScanResults.toArray(new ScanResult[hwPnoScanResults.size()]); 374 mLastPnoScanSettings.pnoScanEventHandler.onPnoNetworkFound(pnoScanResultsArray); 375 } 376 } 377 } 378 379 /** 380 * Return one of the WIFI_BAND_# values that was scanned for in this scan. 381 */ getScannedBandsInternal(ChannelCollection channelCollection)382 private static int getScannedBandsInternal(ChannelCollection channelCollection) { 383 int bandsScanned = WifiScanner.WIFI_BAND_UNSPECIFIED; 384 385 for (@WifiBandIndex int i = 0; i < WifiScanner.WIFI_BAND_COUNT; i++) { 386 if (channelCollection.containsBand(1 << i)) { 387 bandsScanned |= 1 << i; 388 } 389 } 390 return bandsScanned; 391 } 392 pollLatestScanData()393 private void pollLatestScanData() { 394 synchronized (mSettingsLock) { 395 if (mLastScanSettings == null) { 396 // got a scan before we started scanning or after scan was canceled 397 return; 398 } 399 400 mNativeScanResults = mWifiNative.getScanResults(getIfaceName()); 401 List<ScanResult> singleScanResults = new ArrayList<>(); 402 int numFilteredScanResults = 0; 403 for (int i = 0; i < mNativeScanResults.size(); ++i) { 404 ScanResult result = mNativeScanResults.get(i).getScanResult(); 405 // nanoseconds -> microseconds 406 if (result.timestamp >= mLastScanSettings.startTimeNanos / 1_000) { 407 // Allow even not explicitly requested 6Ghz results because they could be found 408 // via 6Ghz RNR. 409 if (mLastScanSettings.singleScanFreqs.containsChannel( 410 result.frequency) || ScanResult.is6GHz(result.frequency)) { 411 singleScanResults.add(result); 412 } else { 413 numFilteredScanResults++; 414 } 415 } else { 416 numFilteredScanResults++; 417 } 418 } 419 if (numFilteredScanResults != 0) { 420 Log.d(TAG, "Filtering out " + numFilteredScanResults + " scan results."); 421 } 422 423 if (mLastScanSettings.singleScanEventHandler != null) { 424 if (mLastScanSettings.reportSingleScanFullResults) { 425 for (ScanResult scanResult : singleScanResults) { 426 // ignore buckets scanned since there is only one bucket for a single scan 427 mLastScanSettings.singleScanEventHandler.onFullScanResult(scanResult, 428 /* bucketsScanned */ 0); 429 } 430 } 431 Collections.sort(singleScanResults, SCAN_RESULT_SORT_COMPARATOR); 432 mLatestSingleScanResult = new WifiScanner.ScanData(0, 0, 0, 433 getScannedBandsInternal(mLastScanSettings.singleScanFreqs), 434 singleScanResults.toArray(new ScanResult[singleScanResults.size()])); 435 mLastScanSettings.singleScanEventHandler 436 .onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE); 437 } 438 439 mLastScanSettings = null; 440 } 441 } 442 443 444 @Override getLatestBatchedScanResults(boolean flush)445 public WifiScanner.ScanData[] getLatestBatchedScanResults(boolean flush) { 446 return null; 447 } 448 startHwPnoScan(WifiNative.PnoSettings pnoSettings)449 private boolean startHwPnoScan(WifiNative.PnoSettings pnoSettings) { 450 return mWifiNative.startPnoScan(getIfaceName(), pnoSettings); 451 } 452 stopHwPnoScan()453 private void stopHwPnoScan() { 454 mWifiNative.stopPnoScan(getIfaceName()); 455 } 456 457 /** 458 * Hw Pno Scan is required only for disconnected PNO when the device supports it. 459 * @param isConnectedPno Whether this is connected PNO vs disconnected PNO. 460 * @return true if HW PNO scan is required, false otherwise. 461 */ isHwPnoScanRequired(boolean isConnectedPno)462 private boolean isHwPnoScanRequired(boolean isConnectedPno) { 463 return (!isConnectedPno 464 && mWifiGlobals.isBackgroundScanSupported()); 465 } 466 467 @Override setHwPnoList(WifiNative.PnoSettings settings, WifiNative.PnoEventHandler eventHandler)468 public boolean setHwPnoList(WifiNative.PnoSettings settings, 469 WifiNative.PnoEventHandler eventHandler) { 470 synchronized (mSettingsLock) { 471 if (mLastPnoScanSettings != null) { 472 Log.w(TAG, "Already running a PNO scan"); 473 return false; 474 } 475 if (!isHwPnoScanRequired(settings.isConnected)) { 476 return false; 477 } 478 479 mLastPnoScanSettings = new LastPnoScanSettings( 480 mClock.getElapsedSinceBootNanos(), 481 settings.networkList, eventHandler); 482 483 if (!startHwPnoScan(settings)) { 484 Log.e(TAG, "Failed to start PNO scan"); 485 reportPnoScanFailure(); 486 } 487 return true; 488 } 489 } 490 491 @Override resetHwPnoList()492 public boolean resetHwPnoList() { 493 synchronized (mSettingsLock) { 494 if (mLastPnoScanSettings == null) { 495 Log.w(TAG, "No PNO scan running"); 496 return false; 497 } 498 mLastPnoScanSettings = null; 499 // For wificond based PNO, we stop the scan immediately when we reset pno list. 500 stopHwPnoScan(); 501 return true; 502 } 503 } 504 505 @Override isHwPnoSupported(boolean isConnectedPno)506 public boolean isHwPnoSupported(boolean isConnectedPno) { 507 // Hw Pno Scan is supported only for disconnected PNO when the device supports it. 508 return isHwPnoScanRequired(isConnectedPno); 509 } 510 511 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)512 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 513 synchronized (mSettingsLock) { 514 long nowMs = mClock.getElapsedSinceBootMillis(); 515 Log.d(TAG, "Latest native scan results nowMs = " + nowMs); 516 pw.println("Latest native scan results:"); 517 if (mNativeScanResults != null) { 518 List<ScanResult> scanResults = mNativeScanResults.stream().map(r -> { 519 return r.getScanResult(); 520 }).collect(Collectors.toList()); 521 ScanResultUtil.dumpScanResults(pw, scanResults, nowMs); 522 } 523 pw.println("Latest native pno scan results:"); 524 if (mNativePnoScanResults != null) { 525 List<ScanResult> pnoScanResults = mNativePnoScanResults.stream().map(r -> { 526 return r.getScanResult(); 527 }).collect(Collectors.toList()); 528 ScanResultUtil.dumpScanResults(pw, pnoScanResults, nowMs); 529 } 530 pw.println("Latest native scan results IEs:"); 531 if (mNativeScanResults != null) { 532 for (ScanDetail detail : mNativeScanResults) { 533 if (detail.getInformationElementRawData() != null) { 534 pw.println(NativeUtil.hexStringFromByteArray( 535 detail.getInformationElementRawData())); 536 } 537 } 538 } 539 pw.println(""); 540 } 541 } 542 543 private static class LastScanSettings { LastScanSettings(long startTimeNanos, boolean reportSingleScanFullResults, ChannelCollection singleScanFreqs, WifiNative.ScanEventHandler singleScanEventHandler)544 LastScanSettings(long startTimeNanos, 545 boolean reportSingleScanFullResults, 546 ChannelCollection singleScanFreqs, 547 WifiNative.ScanEventHandler singleScanEventHandler) { 548 this.startTimeNanos = startTimeNanos; 549 this.reportSingleScanFullResults = reportSingleScanFullResults; 550 this.singleScanFreqs = singleScanFreqs; 551 this.singleScanEventHandler = singleScanEventHandler; 552 } 553 554 public long startTimeNanos; 555 public boolean reportSingleScanFullResults; 556 public ChannelCollection singleScanFreqs; 557 public WifiNative.ScanEventHandler singleScanEventHandler; 558 559 } 560 561 private static class LastPnoScanSettings { LastPnoScanSettings(long startTimeNanos, WifiNative.PnoNetwork[] pnoNetworkList, WifiNative.PnoEventHandler pnoScanEventHandler)562 LastPnoScanSettings(long startTimeNanos, 563 WifiNative.PnoNetwork[] pnoNetworkList, 564 WifiNative.PnoEventHandler pnoScanEventHandler) { 565 this.startTimeNanos = startTimeNanos; 566 this.pnoNetworkList = pnoNetworkList; 567 this.pnoScanEventHandler = pnoScanEventHandler; 568 } 569 570 public long startTimeNanos; 571 public WifiNative.PnoNetwork[] pnoNetworkList; 572 public WifiNative.PnoEventHandler pnoScanEventHandler; 573 574 } 575 576 } 577