1 /* 2 * Copyright (C) 2008 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.Manifest; 20 import android.app.AlarmManager; 21 import android.content.BroadcastReceiver; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.content.pm.PackageManager; 26 import android.net.wifi.IWifiScanner; 27 import android.net.wifi.ScanResult; 28 import android.net.wifi.WifiManager; 29 import android.net.wifi.WifiScanner; 30 import android.net.wifi.WifiScanner.ChannelSpec; 31 import android.net.wifi.WifiScanner.PnoSettings; 32 import android.net.wifi.WifiScanner.ScanData; 33 import android.net.wifi.WifiScanner.ScanSettings; 34 import android.os.Binder; 35 import android.os.Bundle; 36 import android.os.Looper; 37 import android.os.Message; 38 import android.os.Messenger; 39 import android.os.RemoteException; 40 import android.os.UserHandle; 41 import android.os.WorkSource; 42 import android.util.ArrayMap; 43 import android.util.LocalLog; 44 import android.util.Log; 45 import android.util.Pair; 46 47 import com.android.internal.annotations.VisibleForTesting; 48 import com.android.internal.app.IBatteryStats; 49 import com.android.internal.util.ArrayUtils; 50 import com.android.internal.util.AsyncChannel; 51 import com.android.internal.util.Protocol; 52 import com.android.internal.util.State; 53 import com.android.internal.util.StateMachine; 54 import com.android.server.wifi.Clock; 55 import com.android.server.wifi.FrameworkFacade; 56 import com.android.server.wifi.WifiInjector; 57 import com.android.server.wifi.WifiLog; 58 import com.android.server.wifi.WifiMetrics; 59 import com.android.server.wifi.WifiNative; 60 import com.android.server.wifi.WifiStateMachine; 61 import com.android.server.wifi.nano.WifiMetricsProto; 62 import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection; 63 import com.android.server.wifi.util.WifiHandler; 64 65 import java.io.FileDescriptor; 66 import java.io.PrintWriter; 67 import java.util.ArrayList; 68 import java.util.Arrays; 69 import java.util.Collection; 70 import java.util.Iterator; 71 import java.util.List; 72 73 public class WifiScanningServiceImpl extends IWifiScanner.Stub { 74 75 private static final String TAG = WifiScanningService.TAG; 76 private static final boolean DBG = false; 77 78 private static final int MIN_PERIOD_PER_CHANNEL_MS = 200; // DFS needs 120 ms 79 private static final int UNKNOWN_PID = -1; 80 81 private final LocalLog mLocalLog = new LocalLog(512); 82 83 private WifiLog mLog; 84 85 private void localLog(String message) { 86 mLocalLog.log(message); 87 } 88 89 private void logw(String message) { 90 Log.w(TAG, message); 91 mLocalLog.log(message); 92 } 93 94 private void loge(String message) { 95 Log.e(TAG, message); 96 mLocalLog.log(message); 97 } 98 99 private WifiScannerImpl mScannerImpl; 100 101 @Override 102 public Messenger getMessenger() { 103 if (mClientHandler != null) { 104 mLog.trace("getMessenger() uid=%").c(Binder.getCallingUid()).flush(); 105 return new Messenger(mClientHandler); 106 } 107 loge("WifiScanningServiceImpl trying to get messenger w/o initialization"); 108 return null; 109 } 110 111 @Override 112 public Bundle getAvailableChannels(int band) { 113 mChannelHelper.updateChannels(); 114 ChannelSpec[] channelSpecs = mChannelHelper.getAvailableScanChannels(band); 115 ArrayList<Integer> list = new ArrayList<Integer>(channelSpecs.length); 116 for (ChannelSpec channelSpec : channelSpecs) { 117 list.add(channelSpec.frequency); 118 } 119 Bundle b = new Bundle(); 120 b.putIntegerArrayList(WifiScanner.GET_AVAILABLE_CHANNELS_EXTRA, list); 121 mLog.trace("getAvailableChannels uid=%").c(Binder.getCallingUid()).flush(); 122 return b; 123 } 124 125 private void enforceLocationHardwarePermission(int uid) { 126 mContext.enforcePermission( 127 Manifest.permission.LOCATION_HARDWARE, 128 UNKNOWN_PID, uid, 129 "LocationHardware"); 130 } 131 132 private class ClientHandler extends WifiHandler { 133 134 ClientHandler(String tag, Looper looper) { 135 super(tag, looper); 136 } 137 138 @Override 139 public void handleMessage(Message msg) { 140 super.handleMessage(msg); 141 switch (msg.what) { 142 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { 143 ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo); 144 if (client != null) { 145 logw("duplicate client connection: " + msg.sendingUid + ", messenger=" 146 + msg.replyTo); 147 client.mChannel.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, 148 AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED); 149 return; 150 } 151 152 AsyncChannel ac = mFrameworkFacade.makeWifiAsyncChannel(TAG); 153 ac.connected(mContext, this, msg.replyTo); 154 155 client = new ExternalClientInfo(msg.sendingUid, msg.replyTo, ac); 156 client.register(); 157 158 ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, 159 AsyncChannel.STATUS_SUCCESSFUL); 160 localLog("client connected: " + client); 161 return; 162 } 163 case AsyncChannel.CMD_CHANNEL_DISCONNECT: { 164 ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo); 165 if (client != null) { 166 client.mChannel.disconnect(); 167 } 168 return; 169 } 170 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 171 ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo); 172 if (client != null && msg.arg1 != AsyncChannel.STATUS_SEND_UNSUCCESSFUL 173 && msg.arg1 174 != AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED) { 175 localLog("client disconnected: " + client + ", reason: " + msg.arg1); 176 client.cleanup(); 177 } 178 return; 179 } 180 } 181 182 try { 183 enforceLocationHardwarePermission(msg.sendingUid); 184 } catch (SecurityException e) { 185 localLog("failed to authorize app: " + e); 186 replyFailed(msg, WifiScanner.REASON_NOT_AUTHORIZED, "Not authorized"); 187 return; 188 } 189 190 // Since the CMD_GET_SCAN_RESULTS and CMD_GET_SINGLE_SCAN_RESULTS messages are 191 // sent from WifiScanner using |sendMessageSynchronously|, handle separately since 192 // the |msg.replyTo| field does not actually correspond to the Messenger that is 193 // registered for that client. 194 if (msg.what == WifiScanner.CMD_GET_SCAN_RESULTS) { 195 mBackgroundScanStateMachine.sendMessage(Message.obtain(msg)); 196 return; 197 } 198 if (msg.what == WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS) { 199 mSingleScanStateMachine.sendMessage(Message.obtain(msg)); 200 return; 201 } 202 203 ClientInfo ci = mClients.get(msg.replyTo); 204 if (ci == null) { 205 loge("Could not find client info for message " + msg.replyTo + ", msg=" + msg); 206 replyFailed(msg, WifiScanner.REASON_INVALID_LISTENER, "Could not find listener"); 207 return; 208 } 209 210 switch (msg.what) { 211 case WifiScanner.CMD_START_BACKGROUND_SCAN: 212 case WifiScanner.CMD_STOP_BACKGROUND_SCAN: 213 mBackgroundScanStateMachine.sendMessage(Message.obtain(msg)); 214 break; 215 case WifiScanner.CMD_START_PNO_SCAN: 216 case WifiScanner.CMD_STOP_PNO_SCAN: 217 mPnoScanStateMachine.sendMessage(Message.obtain(msg)); 218 break; 219 case WifiScanner.CMD_START_SINGLE_SCAN: 220 case WifiScanner.CMD_STOP_SINGLE_SCAN: 221 mSingleScanStateMachine.sendMessage(Message.obtain(msg)); 222 break; 223 case WifiScanner.CMD_REGISTER_SCAN_LISTENER: 224 logScanRequest("registerScanListener", ci, msg.arg2, null, null, null); 225 mSingleScanListeners.addRequest(ci, msg.arg2, null, null); 226 replySucceeded(msg); 227 break; 228 case WifiScanner.CMD_DEREGISTER_SCAN_LISTENER: 229 logScanRequest("deregisterScanListener", ci, msg.arg2, null, null, null); 230 mSingleScanListeners.removeRequest(ci, msg.arg2); 231 break; 232 default: 233 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "Invalid request"); 234 break; 235 } 236 } 237 } 238 239 private static final int BASE = Protocol.BASE_WIFI_SCANNER_SERVICE; 240 241 private static final int CMD_SCAN_RESULTS_AVAILABLE = BASE + 0; 242 private static final int CMD_FULL_SCAN_RESULTS = BASE + 1; 243 private static final int CMD_HOTLIST_AP_FOUND = BASE + 2; 244 private static final int CMD_HOTLIST_AP_LOST = BASE + 3; 245 private static final int CMD_WIFI_CHANGE_DETECTED = BASE + 4; 246 private static final int CMD_WIFI_CHANGE_TIMEOUT = BASE + 5; 247 private static final int CMD_DRIVER_LOADED = BASE + 6; 248 private static final int CMD_DRIVER_UNLOADED = BASE + 7; 249 private static final int CMD_SCAN_PAUSED = BASE + 8; 250 private static final int CMD_SCAN_RESTARTED = BASE + 9; 251 private static final int CMD_SCAN_FAILED = BASE + 10; 252 private static final int CMD_PNO_NETWORK_FOUND = BASE + 11; 253 private static final int CMD_PNO_SCAN_FAILED = BASE + 12; 254 255 private final Context mContext; 256 private final Looper mLooper; 257 private final WifiScannerImpl.WifiScannerImplFactory mScannerImplFactory; 258 private final ArrayMap<Messenger, ClientInfo> mClients; 259 260 private final RequestList<Void> mSingleScanListeners = new RequestList<>(); 261 262 private ChannelHelper mChannelHelper; 263 private BackgroundScanScheduler mBackgroundScheduler; 264 private WifiNative.ScanSettings mPreviousSchedule; 265 266 private WifiBackgroundScanStateMachine mBackgroundScanStateMachine; 267 private WifiSingleScanStateMachine mSingleScanStateMachine; 268 private WifiPnoScanStateMachine mPnoScanStateMachine; 269 private ClientHandler mClientHandler; 270 private final IBatteryStats mBatteryStats; 271 private final AlarmManager mAlarmManager; 272 private final WifiMetrics mWifiMetrics; 273 private final Clock mClock; 274 private final FrameworkFacade mFrameworkFacade; 275 276 WifiScanningServiceImpl(Context context, Looper looper, 277 WifiScannerImpl.WifiScannerImplFactory scannerImplFactory, IBatteryStats batteryStats, 278 WifiInjector wifiInjector) { 279 mContext = context; 280 mLooper = looper; 281 mScannerImplFactory = scannerImplFactory; 282 mBatteryStats = batteryStats; 283 mClients = new ArrayMap<>(); 284 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 285 mWifiMetrics = wifiInjector.getWifiMetrics(); 286 mClock = wifiInjector.getClock(); 287 mLog = wifiInjector.makeLog(TAG); 288 mFrameworkFacade = wifiInjector.getFrameworkFacade(); 289 mPreviousSchedule = null; 290 } 291 292 public void startService() { 293 mClientHandler = new ClientHandler(TAG, mLooper); 294 mBackgroundScanStateMachine = new WifiBackgroundScanStateMachine(mLooper); 295 mSingleScanStateMachine = new WifiSingleScanStateMachine(mLooper); 296 mPnoScanStateMachine = new WifiPnoScanStateMachine(mLooper); 297 298 mContext.registerReceiver( 299 new BroadcastReceiver() { 300 @Override 301 public void onReceive(Context context, Intent intent) { 302 int state = intent.getIntExtra( 303 WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_DISABLED); 304 if (DBG) localLog("SCAN_AVAILABLE : " + state); 305 if (state == WifiManager.WIFI_STATE_ENABLED) { 306 mBackgroundScanStateMachine.sendMessage(CMD_DRIVER_LOADED); 307 mSingleScanStateMachine.sendMessage(CMD_DRIVER_LOADED); 308 mPnoScanStateMachine.sendMessage(CMD_DRIVER_LOADED); 309 } else if (state == WifiManager.WIFI_STATE_DISABLED) { 310 mBackgroundScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED); 311 mSingleScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED); 312 mPnoScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED); 313 } 314 } 315 }, new IntentFilter(WifiManager.WIFI_SCAN_AVAILABLE)); 316 317 mBackgroundScanStateMachine.start(); 318 mSingleScanStateMachine.start(); 319 mPnoScanStateMachine.start(); 320 } 321 322 /** 323 * Provide a way for unit tests to set valid log object in the WifiHandler 324 * @param log WifiLog object to assign to the clientHandler 325 */ 326 @VisibleForTesting 327 public void setWifiHandlerLogForTest(WifiLog log) { 328 mClientHandler.setWifiLog(log); 329 } 330 331 private static boolean isWorkSourceValid(WorkSource workSource) { 332 return workSource != null && workSource.size() > 0 && workSource.get(0) >= 0; 333 } 334 335 private WorkSource computeWorkSource(ClientInfo ci, WorkSource requestedWorkSource) { 336 if (requestedWorkSource != null) { 337 if (isWorkSourceValid(requestedWorkSource)) { 338 // Wifi currently doesn't use names, so need to clear names out of the 339 // supplied WorkSource to allow future WorkSource combining. 340 requestedWorkSource.clearNames(); 341 return requestedWorkSource; 342 } else { 343 loge("Got invalid work source request: " + requestedWorkSource.toString() + 344 " from " + ci); 345 } 346 } 347 WorkSource callingWorkSource = new WorkSource(ci.getUid()); 348 if (isWorkSourceValid(callingWorkSource)) { 349 return callingWorkSource; 350 } else { 351 loge("Client has invalid work source: " + callingWorkSource); 352 return new WorkSource(); 353 } 354 } 355 356 private class RequestInfo<T> { 357 final ClientInfo clientInfo; 358 final int handlerId; 359 final WorkSource workSource; 360 final T settings; 361 362 RequestInfo(ClientInfo clientInfo, int handlerId, WorkSource requestedWorkSource, 363 T settings) { 364 this.clientInfo = clientInfo; 365 this.handlerId = handlerId; 366 this.settings = settings; 367 this.workSource = computeWorkSource(clientInfo, requestedWorkSource); 368 } 369 370 void reportEvent(int what, int arg1, Object obj) { 371 clientInfo.reportEvent(what, arg1, handlerId, obj); 372 } 373 } 374 375 private class RequestList<T> extends ArrayList<RequestInfo<T>> { 376 void addRequest(ClientInfo ci, int handler, WorkSource reqworkSource, T settings) { 377 add(new RequestInfo<T>(ci, handler, reqworkSource, settings)); 378 } 379 380 T removeRequest(ClientInfo ci, int handlerId) { 381 T removed = null; 382 Iterator<RequestInfo<T>> iter = iterator(); 383 while (iter.hasNext()) { 384 RequestInfo<T> entry = iter.next(); 385 if (entry.clientInfo == ci && entry.handlerId == handlerId) { 386 removed = entry.settings; 387 iter.remove(); 388 } 389 } 390 return removed; 391 } 392 393 Collection<T> getAllSettings() { 394 ArrayList<T> settingsList = new ArrayList<>(); 395 Iterator<RequestInfo<T>> iter = iterator(); 396 while (iter.hasNext()) { 397 RequestInfo<T> entry = iter.next(); 398 settingsList.add(entry.settings); 399 } 400 return settingsList; 401 } 402 403 Collection<T> getAllSettingsForClient(ClientInfo ci) { 404 ArrayList<T> settingsList = new ArrayList<>(); 405 Iterator<RequestInfo<T>> iter = iterator(); 406 while (iter.hasNext()) { 407 RequestInfo<T> entry = iter.next(); 408 if (entry.clientInfo == ci) { 409 settingsList.add(entry.settings); 410 } 411 } 412 return settingsList; 413 } 414 415 void removeAllForClient(ClientInfo ci) { 416 Iterator<RequestInfo<T>> iter = iterator(); 417 while (iter.hasNext()) { 418 RequestInfo<T> entry = iter.next(); 419 if (entry.clientInfo == ci) { 420 iter.remove(); 421 } 422 } 423 } 424 425 WorkSource createMergedWorkSource() { 426 WorkSource mergedSource = new WorkSource(); 427 for (RequestInfo<T> entry : this) { 428 mergedSource.add(entry.workSource); 429 } 430 return mergedSource; 431 } 432 } 433 434 /** 435 * State machine that holds the state of single scans. Scans should only be active in the 436 * ScanningState. The pending scans and active scans maps are swaped when entering 437 * ScanningState. Any requests queued while scanning will be placed in the pending queue and 438 * executed after transitioning back to IdleState. 439 */ 440 class WifiSingleScanStateMachine extends StateMachine implements WifiNative.ScanEventHandler { 441 /** 442 * Maximum age of results that we return from our cache via 443 * {@link WifiScanner#getScanResults()}. 444 * This is currently set to 3 minutes to restore parity with the wpa_supplicant's scan 445 * result cache expiration policy. (See b/62253332 for details) 446 */ 447 @VisibleForTesting 448 public static final int CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS = 180 * 1000; 449 450 private final DefaultState mDefaultState = new DefaultState(); 451 private final DriverStartedState mDriverStartedState = new DriverStartedState(); 452 private final IdleState mIdleState = new IdleState(); 453 private final ScanningState mScanningState = new ScanningState(); 454 455 private WifiNative.ScanSettings mActiveScanSettings = null; 456 private RequestList<ScanSettings> mActiveScans = new RequestList<>(); 457 private RequestList<ScanSettings> mPendingScans = new RequestList<>(); 458 459 // Scan results cached from the last full single scan request. 460 private final List<ScanResult> mCachedScanResults = new ArrayList<>(); 461 462 WifiSingleScanStateMachine(Looper looper) { 463 super("WifiSingleScanStateMachine", looper); 464 465 setLogRecSize(128); 466 setLogOnlyTransitions(false); 467 468 // CHECKSTYLE:OFF IndentationCheck 469 addState(mDefaultState); 470 addState(mDriverStartedState, mDefaultState); 471 addState(mIdleState, mDriverStartedState); 472 addState(mScanningState, mDriverStartedState); 473 // CHECKSTYLE:ON IndentationCheck 474 475 setInitialState(mDefaultState); 476 } 477 478 /** 479 * Called to indicate a change in state for the current scan. 480 * Will dispatch a coresponding event to the state machine 481 */ 482 @Override 483 public void onScanStatus(int event) { 484 if (DBG) localLog("onScanStatus event received, event=" + event); 485 switch(event) { 486 case WifiNative.WIFI_SCAN_RESULTS_AVAILABLE: 487 case WifiNative.WIFI_SCAN_THRESHOLD_NUM_SCANS: 488 case WifiNative.WIFI_SCAN_THRESHOLD_PERCENT: 489 sendMessage(CMD_SCAN_RESULTS_AVAILABLE); 490 break; 491 case WifiNative.WIFI_SCAN_FAILED: 492 sendMessage(CMD_SCAN_FAILED); 493 break; 494 default: 495 Log.e(TAG, "Unknown scan status event: " + event); 496 break; 497 } 498 } 499 500 /** 501 * Called for each full scan result if requested 502 */ 503 @Override 504 public void onFullScanResult(ScanResult fullScanResult, int bucketsScanned) { 505 if (DBG) localLog("onFullScanResult received"); 506 sendMessage(CMD_FULL_SCAN_RESULTS, 0, bucketsScanned, fullScanResult); 507 } 508 509 @Override 510 public void onScanPaused(ScanData[] scanData) { 511 // should not happen for single scan 512 Log.e(TAG, "Got scan paused for single scan"); 513 } 514 515 @Override 516 public void onScanRestarted() { 517 // should not happen for single scan 518 Log.e(TAG, "Got scan restarted for single scan"); 519 } 520 521 class DefaultState extends State { 522 @Override 523 public void enter() { 524 mActiveScans.clear(); 525 mPendingScans.clear(); 526 } 527 @Override 528 public boolean processMessage(Message msg) { 529 switch (msg.what) { 530 case CMD_DRIVER_LOADED: 531 transitionTo(mIdleState); 532 return HANDLED; 533 case CMD_DRIVER_UNLOADED: 534 transitionTo(mDefaultState); 535 return HANDLED; 536 case WifiScanner.CMD_START_SINGLE_SCAN: 537 case WifiScanner.CMD_STOP_SINGLE_SCAN: 538 replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "not available"); 539 return HANDLED; 540 case CMD_SCAN_RESULTS_AVAILABLE: 541 if (DBG) localLog("ignored scan results available event"); 542 return HANDLED; 543 case CMD_FULL_SCAN_RESULTS: 544 if (DBG) localLog("ignored full scan result event"); 545 return HANDLED; 546 case WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS: 547 msg.obj = new WifiScanner.ParcelableScanResults( 548 filterCachedScanResultsByAge()); 549 replySucceeded(msg); 550 return HANDLED; 551 default: 552 return NOT_HANDLED; 553 } 554 } 555 556 /** 557 * Filter out any scan results that are older than 558 * {@link #CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS}. 559 * 560 * @return Filtered list of scan results. 561 */ 562 private ScanResult[] filterCachedScanResultsByAge() { 563 // Using ScanResult.timestamp here to ensure that we use the same fields as 564 // WificondScannerImpl for filtering stale results. 565 long currentTimeInMillis = mClock.getElapsedSinceBootMillis(); 566 return mCachedScanResults.stream() 567 .filter(scanResult 568 -> ((currentTimeInMillis - (scanResult.timestamp / 1000)) 569 < CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS)) 570 .toArray(ScanResult[]::new); 571 } 572 } 573 574 /** 575 * State representing when the driver is running. This state is not meant to be transitioned 576 * directly, but is instead indented as a parent state of ScanningState and IdleState 577 * to hold common functionality and handle cleaning up scans when the driver is shut down. 578 */ 579 class DriverStartedState extends State { 580 @Override 581 public void exit() { 582 // clear scan results when scan mode is not active 583 mCachedScanResults.clear(); 584 585 mWifiMetrics.incrementScanReturnEntry( 586 WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED, 587 mPendingScans.size()); 588 sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED, 589 "Scan was interrupted"); 590 } 591 592 @Override 593 public boolean processMessage(Message msg) { 594 ClientInfo ci = mClients.get(msg.replyTo); 595 596 switch (msg.what) { 597 case WifiScanner.CMD_START_SINGLE_SCAN: 598 mWifiMetrics.incrementOneshotScanCount(); 599 int handler = msg.arg2; 600 Bundle scanParams = (Bundle) msg.obj; 601 if (scanParams == null) { 602 logCallback("singleScanInvalidRequest", ci, handler, "null params"); 603 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null"); 604 return HANDLED; 605 } 606 scanParams.setDefusable(true); 607 ScanSettings scanSettings = 608 scanParams.getParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY); 609 WorkSource workSource = 610 scanParams.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY); 611 if (validateScanRequest(ci, handler, scanSettings, workSource)) { 612 logScanRequest("addSingleScanRequest", ci, handler, workSource, 613 scanSettings, null); 614 replySucceeded(msg); 615 616 // If there is an active scan that will fulfill the scan request then 617 // mark this request as an active scan, otherwise mark it pending. 618 // If were not currently scanning then try to start a scan. Otherwise 619 // this scan will be scheduled when transitioning back to IdleState 620 // after finishing the current scan. 621 if (getCurrentState() == mScanningState) { 622 if (activeScanSatisfies(scanSettings)) { 623 mActiveScans.addRequest(ci, handler, workSource, scanSettings); 624 } else { 625 mPendingScans.addRequest(ci, handler, workSource, scanSettings); 626 } 627 } else { 628 mPendingScans.addRequest(ci, handler, workSource, scanSettings); 629 tryToStartNewScan(); 630 } 631 } else { 632 logCallback("singleScanInvalidRequest", ci, handler, "bad request"); 633 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request"); 634 mWifiMetrics.incrementScanReturnEntry( 635 WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION, 1); 636 } 637 return HANDLED; 638 case WifiScanner.CMD_STOP_SINGLE_SCAN: 639 removeSingleScanRequest(ci, msg.arg2); 640 return HANDLED; 641 default: 642 return NOT_HANDLED; 643 } 644 } 645 } 646 647 class IdleState extends State { 648 @Override 649 public void enter() { 650 tryToStartNewScan(); 651 } 652 653 @Override 654 public boolean processMessage(Message msg) { 655 return NOT_HANDLED; 656 } 657 } 658 659 class ScanningState extends State { 660 private WorkSource mScanWorkSource; 661 662 @Override 663 public void enter() { 664 mScanWorkSource = mActiveScans.createMergedWorkSource(); 665 try { 666 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource); 667 } catch (RemoteException e) { 668 loge(e.toString()); 669 } 670 } 671 672 @Override 673 public void exit() { 674 mActiveScanSettings = null; 675 try { 676 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource); 677 } catch (RemoteException e) { 678 loge(e.toString()); 679 } 680 681 // if any scans are still active (never got results available then indicate failure) 682 mWifiMetrics.incrementScanReturnEntry( 683 WifiMetricsProto.WifiLog.SCAN_UNKNOWN, 684 mActiveScans.size()); 685 sendOpFailedToAllAndClear(mActiveScans, WifiScanner.REASON_UNSPECIFIED, 686 "Scan was interrupted"); 687 } 688 689 @Override 690 public boolean processMessage(Message msg) { 691 switch (msg.what) { 692 case CMD_SCAN_RESULTS_AVAILABLE: 693 mWifiMetrics.incrementScanReturnEntry( 694 WifiMetricsProto.WifiLog.SCAN_SUCCESS, 695 mActiveScans.size()); 696 reportScanResults(mScannerImpl.getLatestSingleScanResults()); 697 mActiveScans.clear(); 698 transitionTo(mIdleState); 699 return HANDLED; 700 case CMD_FULL_SCAN_RESULTS: 701 reportFullScanResult((ScanResult) msg.obj, /* bucketsScanned */ msg.arg2); 702 return HANDLED; 703 case CMD_SCAN_FAILED: 704 mWifiMetrics.incrementScanReturnEntry( 705 WifiMetricsProto.WifiLog.SCAN_UNKNOWN, mActiveScans.size()); 706 sendScanResultBroadcast(false); 707 sendOpFailedToAllAndClear(mActiveScans, WifiScanner.REASON_UNSPECIFIED, 708 "Scan failed"); 709 transitionTo(mIdleState); 710 return HANDLED; 711 default: 712 return NOT_HANDLED; 713 } 714 } 715 } 716 717 boolean validateScanRequest(ClientInfo ci, int handler, ScanSettings settings, 718 WorkSource workSource) { 719 if (ci == null) { 720 Log.d(TAG, "Failing single scan request ClientInfo not found " + handler); 721 return false; 722 } 723 if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { 724 if (settings.channels == null || settings.channels.length == 0) { 725 Log.d(TAG, "Failing single scan because channel list was empty"); 726 return false; 727 } 728 } 729 return true; 730 } 731 732 boolean activeScanSatisfies(ScanSettings settings) { 733 if (mActiveScanSettings == null) { 734 return false; 735 } 736 737 // there is always one bucket for a single scan 738 WifiNative.BucketSettings activeBucket = mActiveScanSettings.buckets[0]; 739 740 // validate that all requested channels are being scanned 741 ChannelCollection activeChannels = mChannelHelper.createChannelCollection(); 742 activeChannels.addChannels(activeBucket); 743 if (!activeChannels.containsSettings(settings)) { 744 return false; 745 } 746 747 // if the request is for a full scan, but there is no ongoing full scan 748 if ((settings.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0 749 && (activeBucket.report_events & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) 750 == 0) { 751 return false; 752 } 753 754 if (!ArrayUtils.isEmpty(settings.hiddenNetworks)) { 755 if (ArrayUtils.isEmpty(mActiveScanSettings.hiddenNetworks)) { 756 return false; 757 } 758 List<WifiNative.HiddenNetwork> activeHiddenNetworks = new ArrayList<>(); 759 for (WifiNative.HiddenNetwork hiddenNetwork : mActiveScanSettings.hiddenNetworks) { 760 activeHiddenNetworks.add(hiddenNetwork); 761 } 762 for (ScanSettings.HiddenNetwork hiddenNetwork : settings.hiddenNetworks) { 763 WifiNative.HiddenNetwork nativeHiddenNetwork = new WifiNative.HiddenNetwork(); 764 nativeHiddenNetwork.ssid = hiddenNetwork.ssid; 765 if (!activeHiddenNetworks.contains(nativeHiddenNetwork)) { 766 return false; 767 } 768 } 769 } 770 771 return true; 772 } 773 774 void removeSingleScanRequest(ClientInfo ci, int handler) { 775 if (ci != null) { 776 logScanRequest("removeSingleScanRequest", ci, handler, null, null, null); 777 mPendingScans.removeRequest(ci, handler); 778 mActiveScans.removeRequest(ci, handler); 779 } 780 } 781 782 void removeSingleScanRequests(ClientInfo ci) { 783 if (ci != null) { 784 logScanRequest("removeSingleScanRequests", ci, -1, null, null, null); 785 mPendingScans.removeAllForClient(ci); 786 mActiveScans.removeAllForClient(ci); 787 } 788 } 789 790 void tryToStartNewScan() { 791 if (mPendingScans.size() == 0) { // no pending requests 792 return; 793 } 794 mChannelHelper.updateChannels(); 795 // TODO move merging logic to a scheduler 796 WifiNative.ScanSettings settings = new WifiNative.ScanSettings(); 797 settings.num_buckets = 1; 798 WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings(); 799 bucketSettings.bucket = 0; 800 bucketSettings.period_ms = 0; 801 bucketSettings.report_events = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN; 802 803 ChannelCollection channels = mChannelHelper.createChannelCollection(); 804 List<WifiNative.HiddenNetwork> hiddenNetworkList = new ArrayList<>(); 805 for (RequestInfo<ScanSettings> entry : mPendingScans) { 806 channels.addChannels(entry.settings); 807 if (entry.settings.hiddenNetworks != null) { 808 for (int i = 0; i < entry.settings.hiddenNetworks.length; i++) { 809 WifiNative.HiddenNetwork hiddenNetwork = new WifiNative.HiddenNetwork(); 810 hiddenNetwork.ssid = entry.settings.hiddenNetworks[i].ssid; 811 hiddenNetworkList.add(hiddenNetwork); 812 } 813 } 814 if ((entry.settings.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) 815 != 0) { 816 bucketSettings.report_events |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT; 817 } 818 } 819 if (hiddenNetworkList.size() > 0) { 820 settings.hiddenNetworks = new WifiNative.HiddenNetwork[hiddenNetworkList.size()]; 821 int numHiddenNetworks = 0; 822 for (WifiNative.HiddenNetwork hiddenNetwork : hiddenNetworkList) { 823 settings.hiddenNetworks[numHiddenNetworks++] = hiddenNetwork; 824 } 825 } 826 827 channels.fillBucketSettings(bucketSettings, Integer.MAX_VALUE); 828 829 settings.buckets = new WifiNative.BucketSettings[] {bucketSettings}; 830 if (mScannerImpl.startSingleScan(settings, this)) { 831 // store the active scan settings 832 mActiveScanSettings = settings; 833 // swap pending and active scan requests 834 RequestList<ScanSettings> tmp = mActiveScans; 835 mActiveScans = mPendingScans; 836 mPendingScans = tmp; 837 // make sure that the pending list is clear 838 mPendingScans.clear(); 839 transitionTo(mScanningState); 840 } else { 841 mWifiMetrics.incrementScanReturnEntry( 842 WifiMetricsProto.WifiLog.SCAN_UNKNOWN, mPendingScans.size()); 843 // notify and cancel failed scans 844 sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED, 845 "Failed to start single scan"); 846 } 847 } 848 849 void sendOpFailedToAllAndClear(RequestList<?> clientHandlers, int reason, 850 String description) { 851 for (RequestInfo<?> entry : clientHandlers) { 852 logCallback("singleScanFailed", entry.clientInfo, entry.handlerId, 853 "reason=" + reason + ", " + description); 854 entry.reportEvent(WifiScanner.CMD_OP_FAILED, 0, 855 new WifiScanner.OperationResult(reason, description)); 856 } 857 clientHandlers.clear(); 858 } 859 860 void reportFullScanResult(ScanResult result, int bucketsScanned) { 861 for (RequestInfo<ScanSettings> entry : mActiveScans) { 862 if (ScanScheduleUtil.shouldReportFullScanResultForSettings(mChannelHelper, 863 result, bucketsScanned, entry.settings, -1)) { 864 entry.reportEvent(WifiScanner.CMD_FULL_SCAN_RESULT, 0, result); 865 } 866 } 867 868 for (RequestInfo<Void> entry : mSingleScanListeners) { 869 entry.reportEvent(WifiScanner.CMD_FULL_SCAN_RESULT, 0, result); 870 } 871 } 872 873 private void sendScanResultBroadcast(boolean scanSucceeded) { 874 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 875 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 876 intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, scanSucceeded); 877 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 878 } 879 880 void reportScanResults(ScanData results) { 881 if (results != null && results.getResults() != null) { 882 if (results.getResults().length > 0) { 883 mWifiMetrics.incrementNonEmptyScanResultCount(); 884 } else { 885 mWifiMetrics.incrementEmptyScanResultCount(); 886 } 887 } 888 ScanData[] allResults = new ScanData[] {results}; 889 for (RequestInfo<ScanSettings> entry : mActiveScans) { 890 ScanData[] resultsToDeliver = ScanScheduleUtil.filterResultsForSettings( 891 mChannelHelper, allResults, entry.settings, -1); 892 WifiScanner.ParcelableScanData parcelableResultsToDeliver = 893 new WifiScanner.ParcelableScanData(resultsToDeliver); 894 logCallback("singleScanResults", entry.clientInfo, entry.handlerId, 895 describeForLog(resultsToDeliver)); 896 entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableResultsToDeliver); 897 // make sure the handler is removed 898 entry.reportEvent(WifiScanner.CMD_SINGLE_SCAN_COMPLETED, 0, null); 899 } 900 901 WifiScanner.ParcelableScanData parcelableAllResults = 902 new WifiScanner.ParcelableScanData(allResults); 903 for (RequestInfo<Void> entry : mSingleScanListeners) { 904 logCallback("singleScanResults", entry.clientInfo, entry.handlerId, 905 describeForLog(allResults)); 906 entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableAllResults); 907 } 908 909 if (results.isAllChannelsScanned()) { 910 mCachedScanResults.clear(); 911 mCachedScanResults.addAll(Arrays.asList(results.getResults())); 912 sendScanResultBroadcast(true); 913 } 914 } 915 916 List<ScanResult> getCachedScanResultsAsList() { 917 return mCachedScanResults; 918 } 919 } 920 921 class WifiBackgroundScanStateMachine extends StateMachine 922 implements WifiNative.ScanEventHandler { 923 924 private final DefaultState mDefaultState = new DefaultState(); 925 private final StartedState mStartedState = new StartedState(); 926 private final PausedState mPausedState = new PausedState(); 927 928 private final RequestList<ScanSettings> mActiveBackgroundScans = new RequestList<>(); 929 930 WifiBackgroundScanStateMachine(Looper looper) { 931 super("WifiBackgroundScanStateMachine", looper); 932 933 setLogRecSize(512); 934 setLogOnlyTransitions(false); 935 936 // CHECKSTYLE:OFF IndentationCheck 937 addState(mDefaultState); 938 addState(mStartedState, mDefaultState); 939 addState(mPausedState, mDefaultState); 940 // CHECKSTYLE:ON IndentationCheck 941 942 setInitialState(mDefaultState); 943 } 944 945 public Collection<ScanSettings> getBackgroundScanSettings(ClientInfo ci) { 946 return mActiveBackgroundScans.getAllSettingsForClient(ci); 947 } 948 949 public void removeBackgroundScanSettings(ClientInfo ci) { 950 mActiveBackgroundScans.removeAllForClient(ci); 951 updateSchedule(); 952 } 953 954 @Override 955 public void onScanStatus(int event) { 956 if (DBG) localLog("onScanStatus event received, event=" + event); 957 switch(event) { 958 case WifiNative.WIFI_SCAN_RESULTS_AVAILABLE: 959 case WifiNative.WIFI_SCAN_THRESHOLD_NUM_SCANS: 960 case WifiNative.WIFI_SCAN_THRESHOLD_PERCENT: 961 sendMessage(CMD_SCAN_RESULTS_AVAILABLE); 962 break; 963 case WifiNative.WIFI_SCAN_FAILED: 964 sendMessage(CMD_SCAN_FAILED); 965 break; 966 default: 967 Log.e(TAG, "Unknown scan status event: " + event); 968 break; 969 } 970 } 971 972 @Override 973 public void onFullScanResult(ScanResult fullScanResult, int bucketsScanned) { 974 if (DBG) localLog("onFullScanResult received"); 975 sendMessage(CMD_FULL_SCAN_RESULTS, 0, bucketsScanned, fullScanResult); 976 } 977 978 @Override 979 public void onScanPaused(ScanData scanData[]) { 980 if (DBG) localLog("onScanPaused received"); 981 sendMessage(CMD_SCAN_PAUSED, scanData); 982 } 983 984 @Override 985 public void onScanRestarted() { 986 if (DBG) localLog("onScanRestarted received"); 987 sendMessage(CMD_SCAN_RESTARTED); 988 } 989 990 class DefaultState extends State { 991 @Override 992 public void enter() { 993 if (DBG) localLog("DefaultState"); 994 mActiveBackgroundScans.clear(); 995 } 996 997 @Override 998 public boolean processMessage(Message msg) { 999 switch (msg.what) { 1000 case CMD_DRIVER_LOADED: 1001 // TODO this should be moved to a common location since it is used outside 1002 // of this state machine. It is ok right now because the driver loaded event 1003 // is sent to this state machine first. 1004 if (mScannerImpl == null) { 1005 mScannerImpl = mScannerImplFactory.create(mContext, mLooper, mClock); 1006 mChannelHelper = mScannerImpl.getChannelHelper(); 1007 } 1008 1009 mBackgroundScheduler = new BackgroundScanScheduler(mChannelHelper); 1010 1011 WifiNative.ScanCapabilities capabilities = 1012 new WifiNative.ScanCapabilities(); 1013 if (!mScannerImpl.getScanCapabilities(capabilities)) { 1014 loge("could not get scan capabilities"); 1015 return HANDLED; 1016 } 1017 if (capabilities.max_scan_buckets <= 0) { 1018 loge("invalid max buckets in scan capabilities " 1019 + capabilities.max_scan_buckets); 1020 return HANDLED; 1021 } 1022 mBackgroundScheduler.setMaxBuckets(capabilities.max_scan_buckets); 1023 mBackgroundScheduler.setMaxApPerScan(capabilities.max_ap_cache_per_scan); 1024 1025 Log.i(TAG, "wifi driver loaded with scan capabilities: " 1026 + "max buckets=" + capabilities.max_scan_buckets); 1027 1028 transitionTo(mStartedState); 1029 return HANDLED; 1030 case CMD_DRIVER_UNLOADED: 1031 Log.i(TAG, "wifi driver unloaded"); 1032 transitionTo(mDefaultState); 1033 break; 1034 case WifiScanner.CMD_START_BACKGROUND_SCAN: 1035 case WifiScanner.CMD_STOP_BACKGROUND_SCAN: 1036 case WifiScanner.CMD_START_SINGLE_SCAN: 1037 case WifiScanner.CMD_STOP_SINGLE_SCAN: 1038 case WifiScanner.CMD_GET_SCAN_RESULTS: 1039 replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "not available"); 1040 break; 1041 1042 case CMD_SCAN_RESULTS_AVAILABLE: 1043 if (DBG) localLog("ignored scan results available event"); 1044 break; 1045 1046 case CMD_FULL_SCAN_RESULTS: 1047 if (DBG) localLog("ignored full scan result event"); 1048 break; 1049 1050 default: 1051 break; 1052 } 1053 1054 return HANDLED; 1055 } 1056 } 1057 1058 class StartedState extends State { 1059 1060 @Override 1061 public void enter() { 1062 if (DBG) localLog("StartedState"); 1063 } 1064 1065 @Override 1066 public void exit() { 1067 sendBackgroundScanFailedToAllAndClear( 1068 WifiScanner.REASON_UNSPECIFIED, "Scan was interrupted"); 1069 mScannerImpl.cleanup(); 1070 } 1071 1072 @Override 1073 public boolean processMessage(Message msg) { 1074 ClientInfo ci = mClients.get(msg.replyTo); 1075 1076 switch (msg.what) { 1077 case CMD_DRIVER_LOADED: 1078 return NOT_HANDLED; 1079 case CMD_DRIVER_UNLOADED: 1080 return NOT_HANDLED; 1081 case WifiScanner.CMD_START_BACKGROUND_SCAN: { 1082 mWifiMetrics.incrementBackgroundScanCount(); 1083 Bundle scanParams = (Bundle) msg.obj; 1084 if (scanParams == null) { 1085 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null"); 1086 return HANDLED; 1087 } 1088 scanParams.setDefusable(true); 1089 ScanSettings scanSettings = 1090 scanParams.getParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY); 1091 WorkSource workSource = 1092 scanParams.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY); 1093 if (addBackgroundScanRequest(ci, msg.arg2, scanSettings, workSource)) { 1094 replySucceeded(msg); 1095 } else { 1096 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request"); 1097 } 1098 break; 1099 } 1100 case WifiScanner.CMD_STOP_BACKGROUND_SCAN: 1101 removeBackgroundScanRequest(ci, msg.arg2); 1102 break; 1103 case WifiScanner.CMD_GET_SCAN_RESULTS: 1104 reportScanResults(mScannerImpl.getLatestBatchedScanResults(true)); 1105 replySucceeded(msg); 1106 break; 1107 case CMD_SCAN_RESULTS_AVAILABLE: 1108 reportScanResults(mScannerImpl.getLatestBatchedScanResults(true)); 1109 break; 1110 case CMD_FULL_SCAN_RESULTS: 1111 reportFullScanResult((ScanResult) msg.obj, /* bucketsScanned */ msg.arg2); 1112 break; 1113 case CMD_SCAN_PAUSED: 1114 reportScanResults((ScanData[]) msg.obj); 1115 transitionTo(mPausedState); 1116 break; 1117 case CMD_SCAN_FAILED: 1118 Log.e(TAG, "WifiScanner background scan gave CMD_SCAN_FAILED"); 1119 sendBackgroundScanFailedToAllAndClear( 1120 WifiScanner.REASON_UNSPECIFIED, "Background Scan failed"); 1121 break; 1122 default: 1123 return NOT_HANDLED; 1124 } 1125 1126 return HANDLED; 1127 } 1128 } 1129 1130 class PausedState extends State { 1131 @Override 1132 public void enter() { 1133 if (DBG) localLog("PausedState"); 1134 } 1135 1136 @Override 1137 public boolean processMessage(Message msg) { 1138 switch (msg.what) { 1139 case CMD_SCAN_RESTARTED: 1140 transitionTo(mStartedState); 1141 break; 1142 default: 1143 deferMessage(msg); 1144 break; 1145 } 1146 return HANDLED; 1147 } 1148 } 1149 1150 private boolean addBackgroundScanRequest(ClientInfo ci, int handler, 1151 ScanSettings settings, WorkSource workSource) { 1152 // sanity check the input 1153 if (ci == null) { 1154 Log.d(TAG, "Failing scan request ClientInfo not found " + handler); 1155 return false; 1156 } 1157 if (settings.periodInMs < WifiScanner.MIN_SCAN_PERIOD_MS) { 1158 loge("Failing scan request because periodInMs is " + settings.periodInMs 1159 + ", min scan period is: " + WifiScanner.MIN_SCAN_PERIOD_MS); 1160 return false; 1161 } 1162 1163 if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED && settings.channels == null) { 1164 loge("Channels was null with unspecified band"); 1165 return false; 1166 } 1167 1168 if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED 1169 && settings.channels.length == 0) { 1170 loge("No channels specified"); 1171 return false; 1172 } 1173 1174 int minSupportedPeriodMs = mChannelHelper.estimateScanDuration(settings); 1175 if (settings.periodInMs < minSupportedPeriodMs) { 1176 loge("Failing scan request because minSupportedPeriodMs is " 1177 + minSupportedPeriodMs + " but the request wants " + settings.periodInMs); 1178 return false; 1179 } 1180 1181 // check truncated binary exponential back off scan settings 1182 if (settings.maxPeriodInMs != 0 && settings.maxPeriodInMs != settings.periodInMs) { 1183 if (settings.maxPeriodInMs < settings.periodInMs) { 1184 loge("Failing scan request because maxPeriodInMs is " + settings.maxPeriodInMs 1185 + " but less than periodInMs " + settings.periodInMs); 1186 return false; 1187 } 1188 if (settings.maxPeriodInMs > WifiScanner.MAX_SCAN_PERIOD_MS) { 1189 loge("Failing scan request because maxSupportedPeriodMs is " 1190 + WifiScanner.MAX_SCAN_PERIOD_MS + " but the request wants " 1191 + settings.maxPeriodInMs); 1192 return false; 1193 } 1194 if (settings.stepCount < 1) { 1195 loge("Failing scan request because stepCount is " + settings.stepCount 1196 + " which is less than 1"); 1197 return false; 1198 } 1199 } 1200 1201 logScanRequest("addBackgroundScanRequest", ci, handler, null, settings, null); 1202 mActiveBackgroundScans.addRequest(ci, handler, workSource, settings); 1203 1204 if (updateSchedule()) { 1205 return true; 1206 } else { 1207 mActiveBackgroundScans.removeRequest(ci, handler); 1208 localLog("Failing scan request because failed to reset scan"); 1209 return false; 1210 } 1211 } 1212 1213 private boolean updateSchedule() { 1214 if (mChannelHelper == null || mBackgroundScheduler == null || mScannerImpl == null) { 1215 loge("Failed to update schedule because WifiScanningService is not initialized"); 1216 return false; 1217 } 1218 mChannelHelper.updateChannels(); 1219 Collection<ScanSettings> settings = mActiveBackgroundScans.getAllSettings(); 1220 1221 mBackgroundScheduler.updateSchedule(settings); 1222 WifiNative.ScanSettings schedule = mBackgroundScheduler.getSchedule(); 1223 1224 if (ScanScheduleUtil.scheduleEquals(mPreviousSchedule, schedule)) { 1225 if (DBG) Log.d(TAG, "schedule updated with no change"); 1226 return true; 1227 } 1228 1229 mPreviousSchedule = schedule; 1230 1231 if (schedule.num_buckets == 0) { 1232 mScannerImpl.stopBatchedScan(); 1233 if (DBG) Log.d(TAG, "scan stopped"); 1234 return true; 1235 } else { 1236 localLog("starting scan: " 1237 + "base period=" + schedule.base_period_ms 1238 + ", max ap per scan=" + schedule.max_ap_per_scan 1239 + ", batched scans=" + schedule.report_threshold_num_scans); 1240 for (int b = 0; b < schedule.num_buckets; b++) { 1241 WifiNative.BucketSettings bucket = schedule.buckets[b]; 1242 localLog("bucket " + bucket.bucket + " (" + bucket.period_ms + "ms)" 1243 + "[" + bucket.report_events + "]: " 1244 + ChannelHelper.toString(bucket)); 1245 } 1246 1247 if (mScannerImpl.startBatchedScan(schedule, this)) { 1248 if (DBG) { 1249 Log.d(TAG, "scan restarted with " + schedule.num_buckets 1250 + " bucket(s) and base period: " + schedule.base_period_ms); 1251 } 1252 return true; 1253 } else { 1254 mPreviousSchedule = null; 1255 loge("error starting scan: " 1256 + "base period=" + schedule.base_period_ms 1257 + ", max ap per scan=" + schedule.max_ap_per_scan 1258 + ", batched scans=" + schedule.report_threshold_num_scans); 1259 for (int b = 0; b < schedule.num_buckets; b++) { 1260 WifiNative.BucketSettings bucket = schedule.buckets[b]; 1261 loge("bucket " + bucket.bucket + " (" + bucket.period_ms + "ms)" 1262 + "[" + bucket.report_events + "]: " 1263 + ChannelHelper.toString(bucket)); 1264 } 1265 return false; 1266 } 1267 } 1268 } 1269 1270 private void removeBackgroundScanRequest(ClientInfo ci, int handler) { 1271 if (ci != null) { 1272 ScanSettings settings = mActiveBackgroundScans.removeRequest(ci, handler); 1273 logScanRequest("removeBackgroundScanRequest", ci, handler, null, settings, null); 1274 updateSchedule(); 1275 } 1276 } 1277 1278 private void reportFullScanResult(ScanResult result, int bucketsScanned) { 1279 for (RequestInfo<ScanSettings> entry : mActiveBackgroundScans) { 1280 ClientInfo ci = entry.clientInfo; 1281 int handler = entry.handlerId; 1282 ScanSettings settings = entry.settings; 1283 if (mBackgroundScheduler.shouldReportFullScanResultForSettings( 1284 result, bucketsScanned, settings)) { 1285 ScanResult newResult = new ScanResult(result); 1286 if (result.informationElements != null) { 1287 newResult.informationElements = result.informationElements.clone(); 1288 } 1289 else { 1290 newResult.informationElements = null; 1291 } 1292 ci.reportEvent(WifiScanner.CMD_FULL_SCAN_RESULT, 0, handler, newResult); 1293 } 1294 } 1295 } 1296 1297 private void reportScanResults(ScanData[] results) { 1298 if (results == null) { 1299 Log.d(TAG,"The results is null, nothing to report."); 1300 return; 1301 } 1302 for (ScanData result : results) { 1303 if (result != null && result.getResults() != null) { 1304 if (result.getResults().length > 0) { 1305 mWifiMetrics.incrementNonEmptyScanResultCount(); 1306 } else { 1307 mWifiMetrics.incrementEmptyScanResultCount(); 1308 } 1309 } 1310 } 1311 for (RequestInfo<ScanSettings> entry : mActiveBackgroundScans) { 1312 ClientInfo ci = entry.clientInfo; 1313 int handler = entry.handlerId; 1314 ScanSettings settings = entry.settings; 1315 ScanData[] resultsToDeliver = 1316 mBackgroundScheduler.filterResultsForSettings(results, settings); 1317 if (resultsToDeliver != null) { 1318 logCallback("backgroundScanResults", ci, handler, 1319 describeForLog(resultsToDeliver)); 1320 WifiScanner.ParcelableScanData parcelableScanData = 1321 new WifiScanner.ParcelableScanData(resultsToDeliver); 1322 ci.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, handler, parcelableScanData); 1323 } 1324 } 1325 } 1326 1327 private void sendBackgroundScanFailedToAllAndClear(int reason, String description) { 1328 for (RequestInfo<ScanSettings> entry : mActiveBackgroundScans) { 1329 ClientInfo ci = entry.clientInfo; 1330 int handler = entry.handlerId; 1331 ci.reportEvent(WifiScanner.CMD_OP_FAILED, 0, handler, 1332 new WifiScanner.OperationResult(reason, description)); 1333 } 1334 mActiveBackgroundScans.clear(); 1335 } 1336 } 1337 1338 /** 1339 * PNO scan state machine has 5 states: 1340 * -Default State 1341 * -Started State 1342 * -Hw Pno Scan state 1343 * -Single Scan state 1344 * -Sw Pno Scan state 1345 * 1346 * These are the main state transitions: 1347 * 1. Start at |Default State| 1348 * 2. Move to |Started State| when we get the |WIFI_SCAN_AVAILABLE| broadcast from WifiManager. 1349 * 3. When a new PNO scan request comes in: 1350 * a.1. Switch to |Hw Pno Scan state| when the device supports HW PNO 1351 * (This could either be HAL based ePNO or wificond based PNO). 1352 * a.2. In |Hw Pno Scan state| when PNO scan results are received, check if the result 1353 * contains IE (information elements). If yes, send the results to the client, else 1354 * switch to |Single Scan state| and send the result to the client when the scan result 1355 * is obtained. 1356 * b.1. Switch to |Sw Pno Scan state| when the device does not supports HW PNO 1357 * (This is for older devices which do not support HW PNO and for connected PNO on 1358 * devices which support wificond based PNO) 1359 * b.2. In |Sw Pno Scan state| send the result to the client when the background scan result 1360 * is obtained 1361 * 1362 * Note: PNO scans only work for a single client today. We don't have support in HW to support 1363 * multiple requests at the same time, so will need non-trivial changes to support (if at all 1364 * possible) in WifiScanningService. 1365 */ 1366 class WifiPnoScanStateMachine extends StateMachine implements WifiNative.PnoEventHandler { 1367 1368 private final DefaultState mDefaultState = new DefaultState(); 1369 private final StartedState mStartedState = new StartedState(); 1370 private final HwPnoScanState mHwPnoScanState = new HwPnoScanState(); 1371 private final SwPnoScanState mSwPnoScanState = new SwPnoScanState(); 1372 private final SingleScanState mSingleScanState = new SingleScanState(); 1373 private InternalClientInfo mInternalClientInfo; 1374 1375 private final RequestList<Pair<PnoSettings, ScanSettings>> mActivePnoScans = 1376 new RequestList<>(); 1377 1378 WifiPnoScanStateMachine(Looper looper) { 1379 super("WifiPnoScanStateMachine", looper); 1380 1381 setLogRecSize(256); 1382 setLogOnlyTransitions(false); 1383 1384 // CHECKSTYLE:OFF IndentationCheck 1385 addState(mDefaultState); 1386 addState(mStartedState, mDefaultState); 1387 addState(mHwPnoScanState, mStartedState); 1388 addState(mSingleScanState, mHwPnoScanState); 1389 addState(mSwPnoScanState, mStartedState); 1390 // CHECKSTYLE:ON IndentationCheck 1391 1392 setInitialState(mDefaultState); 1393 } 1394 1395 public void removePnoSettings(ClientInfo ci) { 1396 mActivePnoScans.removeAllForClient(ci); 1397 transitionTo(mStartedState); 1398 } 1399 1400 @Override 1401 public void onPnoNetworkFound(ScanResult[] results) { 1402 if (DBG) localLog("onWifiPnoNetworkFound event received"); 1403 sendMessage(CMD_PNO_NETWORK_FOUND, 0, 0, results); 1404 } 1405 1406 @Override 1407 public void onPnoScanFailed() { 1408 if (DBG) localLog("onWifiPnoScanFailed event received"); 1409 sendMessage(CMD_PNO_SCAN_FAILED, 0, 0, null); 1410 } 1411 1412 class DefaultState extends State { 1413 @Override 1414 public void enter() { 1415 if (DBG) localLog("DefaultState"); 1416 } 1417 1418 @Override 1419 public boolean processMessage(Message msg) { 1420 switch (msg.what) { 1421 case CMD_DRIVER_LOADED: 1422 transitionTo(mStartedState); 1423 break; 1424 case CMD_DRIVER_UNLOADED: 1425 transitionTo(mDefaultState); 1426 break; 1427 case WifiScanner.CMD_START_PNO_SCAN: 1428 case WifiScanner.CMD_STOP_PNO_SCAN: 1429 replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "not available"); 1430 break; 1431 case CMD_PNO_NETWORK_FOUND: 1432 case CMD_PNO_SCAN_FAILED: 1433 case WifiScanner.CMD_SCAN_RESULT: 1434 case WifiScanner.CMD_OP_FAILED: 1435 loge("Unexpected message " + msg.what); 1436 break; 1437 default: 1438 return NOT_HANDLED; 1439 } 1440 return HANDLED; 1441 } 1442 } 1443 1444 class StartedState extends State { 1445 @Override 1446 public void enter() { 1447 if (DBG) localLog("StartedState"); 1448 } 1449 1450 @Override 1451 public void exit() { 1452 sendPnoScanFailedToAllAndClear( 1453 WifiScanner.REASON_UNSPECIFIED, "Scan was interrupted"); 1454 } 1455 1456 @Override 1457 public boolean processMessage(Message msg) { 1458 ClientInfo ci = mClients.get(msg.replyTo); 1459 switch (msg.what) { 1460 case WifiScanner.CMD_START_PNO_SCAN: 1461 Bundle pnoParams = (Bundle) msg.obj; 1462 if (pnoParams == null) { 1463 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null"); 1464 return HANDLED; 1465 } 1466 pnoParams.setDefusable(true); 1467 PnoSettings pnoSettings = 1468 pnoParams.getParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY); 1469 // This message is handled after the transition to SwPnoScan/HwPnoScan state 1470 deferMessage(msg); 1471 if (mScannerImpl.isHwPnoSupported(pnoSettings.isConnected)) { 1472 transitionTo(mHwPnoScanState); 1473 } else { 1474 transitionTo(mSwPnoScanState); 1475 } 1476 break; 1477 case WifiScanner.CMD_STOP_PNO_SCAN: 1478 replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "no scan running"); 1479 break; 1480 default: 1481 return NOT_HANDLED; 1482 } 1483 return HANDLED; 1484 } 1485 } 1486 1487 class HwPnoScanState extends State { 1488 @Override 1489 public void enter() { 1490 if (DBG) localLog("HwPnoScanState"); 1491 } 1492 1493 @Override 1494 public void exit() { 1495 // Reset PNO scan in ScannerImpl before we exit. 1496 mScannerImpl.resetHwPnoList(); 1497 removeInternalClient(); 1498 } 1499 1500 @Override 1501 public boolean processMessage(Message msg) { 1502 ClientInfo ci = mClients.get(msg.replyTo); 1503 switch (msg.what) { 1504 case WifiScanner.CMD_START_PNO_SCAN: 1505 Bundle pnoParams = (Bundle) msg.obj; 1506 if (pnoParams == null) { 1507 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null"); 1508 return HANDLED; 1509 } 1510 pnoParams.setDefusable(true); 1511 PnoSettings pnoSettings = 1512 pnoParams.getParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY); 1513 ScanSettings scanSettings = 1514 pnoParams.getParcelable(WifiScanner.PNO_PARAMS_SCAN_SETTINGS_KEY); 1515 if (addHwPnoScanRequest(ci, msg.arg2, scanSettings, pnoSettings)) { 1516 replySucceeded(msg); 1517 } else { 1518 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request"); 1519 transitionTo(mStartedState); 1520 } 1521 break; 1522 case WifiScanner.CMD_STOP_PNO_SCAN: 1523 removeHwPnoScanRequest(ci, msg.arg2); 1524 transitionTo(mStartedState); 1525 break; 1526 case CMD_PNO_NETWORK_FOUND: 1527 ScanResult[] scanResults = ((ScanResult[]) msg.obj); 1528 if (isSingleScanNeeded(scanResults)) { 1529 ScanSettings activeScanSettings = getScanSettings(); 1530 if (activeScanSettings == null) { 1531 sendPnoScanFailedToAllAndClear( 1532 WifiScanner.REASON_UNSPECIFIED, 1533 "couldn't retrieve setting"); 1534 transitionTo(mStartedState); 1535 } else { 1536 addSingleScanRequest(activeScanSettings); 1537 transitionTo(mSingleScanState); 1538 } 1539 } else { 1540 reportPnoNetworkFound((ScanResult[]) msg.obj); 1541 } 1542 break; 1543 case CMD_PNO_SCAN_FAILED: 1544 sendPnoScanFailedToAllAndClear( 1545 WifiScanner.REASON_UNSPECIFIED, "pno scan failed"); 1546 transitionTo(mStartedState); 1547 break; 1548 default: 1549 return NOT_HANDLED; 1550 } 1551 return HANDLED; 1552 } 1553 } 1554 1555 class SingleScanState extends State { 1556 @Override 1557 public void enter() { 1558 if (DBG) localLog("SingleScanState"); 1559 } 1560 1561 @Override 1562 public boolean processMessage(Message msg) { 1563 ClientInfo ci = mClients.get(msg.replyTo); 1564 switch (msg.what) { 1565 case WifiScanner.CMD_SCAN_RESULT: 1566 WifiScanner.ParcelableScanData parcelableScanData = 1567 (WifiScanner.ParcelableScanData) msg.obj; 1568 ScanData[] scanDatas = parcelableScanData.getResults(); 1569 ScanData lastScanData = scanDatas[scanDatas.length - 1]; 1570 reportPnoNetworkFound(lastScanData.getResults()); 1571 transitionTo(mHwPnoScanState); 1572 break; 1573 case WifiScanner.CMD_OP_FAILED: 1574 sendPnoScanFailedToAllAndClear( 1575 WifiScanner.REASON_UNSPECIFIED, "single scan failed"); 1576 transitionTo(mStartedState); 1577 break; 1578 default: 1579 return NOT_HANDLED; 1580 } 1581 return HANDLED; 1582 } 1583 } 1584 1585 class SwPnoScanState extends State { 1586 private final ArrayList<ScanResult> mSwPnoFullScanResults = new ArrayList<>(); 1587 1588 @Override 1589 public void enter() { 1590 if (DBG) localLog("SwPnoScanState"); 1591 mSwPnoFullScanResults.clear(); 1592 } 1593 1594 @Override 1595 public void exit() { 1596 removeInternalClient(); 1597 } 1598 1599 @Override 1600 public boolean processMessage(Message msg) { 1601 ClientInfo ci = mClients.get(msg.replyTo); 1602 switch (msg.what) { 1603 case WifiScanner.CMD_START_PNO_SCAN: 1604 Bundle pnoParams = (Bundle) msg.obj; 1605 if (pnoParams == null) { 1606 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null"); 1607 return HANDLED; 1608 } 1609 pnoParams.setDefusable(true); 1610 PnoSettings pnoSettings = 1611 pnoParams.getParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY); 1612 ScanSettings scanSettings = 1613 pnoParams.getParcelable(WifiScanner.PNO_PARAMS_SCAN_SETTINGS_KEY); 1614 if (addSwPnoScanRequest(ci, msg.arg2, scanSettings, pnoSettings)) { 1615 replySucceeded(msg); 1616 } else { 1617 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request"); 1618 transitionTo(mStartedState); 1619 } 1620 break; 1621 case WifiScanner.CMD_STOP_PNO_SCAN: 1622 removeSwPnoScanRequest(ci, msg.arg2); 1623 transitionTo(mStartedState); 1624 break; 1625 case WifiScanner.CMD_FULL_SCAN_RESULT: 1626 // Aggregate full scan results until we get the |CMD_SCAN_RESULT| message 1627 mSwPnoFullScanResults.add((ScanResult) msg.obj); 1628 break; 1629 case WifiScanner.CMD_SCAN_RESULT: 1630 ScanResult[] scanResults = mSwPnoFullScanResults.toArray( 1631 new ScanResult[mSwPnoFullScanResults.size()]); 1632 reportPnoNetworkFound(scanResults); 1633 mSwPnoFullScanResults.clear(); 1634 break; 1635 case WifiScanner.CMD_OP_FAILED: 1636 sendPnoScanFailedToAllAndClear( 1637 WifiScanner.REASON_UNSPECIFIED, "background scan failed"); 1638 transitionTo(mStartedState); 1639 break; 1640 default: 1641 return NOT_HANDLED; 1642 } 1643 return HANDLED; 1644 } 1645 } 1646 1647 private WifiNative.PnoSettings convertSettingsToPnoNative(ScanSettings scanSettings, 1648 PnoSettings pnoSettings) { 1649 WifiNative.PnoSettings nativePnoSetting = new WifiNative.PnoSettings(); 1650 nativePnoSetting.periodInMs = scanSettings.periodInMs; 1651 nativePnoSetting.min5GHzRssi = pnoSettings.min5GHzRssi; 1652 nativePnoSetting.min24GHzRssi = pnoSettings.min24GHzRssi; 1653 nativePnoSetting.initialScoreMax = pnoSettings.initialScoreMax; 1654 nativePnoSetting.currentConnectionBonus = pnoSettings.currentConnectionBonus; 1655 nativePnoSetting.sameNetworkBonus = pnoSettings.sameNetworkBonus; 1656 nativePnoSetting.secureBonus = pnoSettings.secureBonus; 1657 nativePnoSetting.band5GHzBonus = pnoSettings.band5GHzBonus; 1658 nativePnoSetting.isConnected = pnoSettings.isConnected; 1659 nativePnoSetting.networkList = 1660 new WifiNative.PnoNetwork[pnoSettings.networkList.length]; 1661 for (int i = 0; i < pnoSettings.networkList.length; i++) { 1662 nativePnoSetting.networkList[i] = new WifiNative.PnoNetwork(); 1663 nativePnoSetting.networkList[i].ssid = pnoSettings.networkList[i].ssid; 1664 nativePnoSetting.networkList[i].flags = pnoSettings.networkList[i].flags; 1665 nativePnoSetting.networkList[i].auth_bit_field = 1666 pnoSettings.networkList[i].authBitField; 1667 } 1668 return nativePnoSetting; 1669 } 1670 1671 // Retrieve the only active scan settings. 1672 private ScanSettings getScanSettings() { 1673 for (Pair<PnoSettings, ScanSettings> settingsPair : mActivePnoScans.getAllSettings()) { 1674 return settingsPair.second; 1675 } 1676 return null; 1677 } 1678 1679 private void removeInternalClient() { 1680 if (mInternalClientInfo != null) { 1681 mInternalClientInfo.cleanup(); 1682 mInternalClientInfo = null; 1683 } else { 1684 Log.w(TAG, "No Internal client for PNO"); 1685 } 1686 } 1687 1688 private void addInternalClient(ClientInfo ci) { 1689 if (mInternalClientInfo == null) { 1690 mInternalClientInfo = 1691 new InternalClientInfo(ci.getUid(), new Messenger(this.getHandler())); 1692 mInternalClientInfo.register(); 1693 } else { 1694 Log.w(TAG, "Internal client for PNO already exists"); 1695 } 1696 } 1697 1698 private void addPnoScanRequest(ClientInfo ci, int handler, ScanSettings scanSettings, 1699 PnoSettings pnoSettings) { 1700 mActivePnoScans.addRequest(ci, handler, WifiStateMachine.WIFI_WORK_SOURCE, 1701 Pair.create(pnoSettings, scanSettings)); 1702 addInternalClient(ci); 1703 } 1704 1705 private Pair<PnoSettings, ScanSettings> removePnoScanRequest(ClientInfo ci, int handler) { 1706 Pair<PnoSettings, ScanSettings> settings = mActivePnoScans.removeRequest(ci, handler); 1707 return settings; 1708 } 1709 1710 private boolean addHwPnoScanRequest(ClientInfo ci, int handler, ScanSettings scanSettings, 1711 PnoSettings pnoSettings) { 1712 if (ci == null) { 1713 Log.d(TAG, "Failing scan request ClientInfo not found " + handler); 1714 return false; 1715 } 1716 if (!mActivePnoScans.isEmpty()) { 1717 loge("Failing scan request because there is already an active scan"); 1718 return false; 1719 } 1720 WifiNative.PnoSettings nativePnoSettings = 1721 convertSettingsToPnoNative(scanSettings, pnoSettings); 1722 if (!mScannerImpl.setHwPnoList(nativePnoSettings, mPnoScanStateMachine)) { 1723 return false; 1724 } 1725 logScanRequest("addHwPnoScanRequest", ci, handler, null, scanSettings, pnoSettings); 1726 addPnoScanRequest(ci, handler, scanSettings, pnoSettings); 1727 // HW PNO is supported, check if we need a background scan running for this. 1728 if (mScannerImpl.shouldScheduleBackgroundScanForHwPno()) { 1729 addBackgroundScanRequest(scanSettings); 1730 } 1731 return true; 1732 } 1733 1734 private void removeHwPnoScanRequest(ClientInfo ci, int handler) { 1735 if (ci != null) { 1736 Pair<PnoSettings, ScanSettings> settings = removePnoScanRequest(ci, handler); 1737 logScanRequest("removeHwPnoScanRequest", ci, handler, null, 1738 settings.second, settings.first); 1739 } 1740 } 1741 1742 private boolean addSwPnoScanRequest(ClientInfo ci, int handler, ScanSettings scanSettings, 1743 PnoSettings pnoSettings) { 1744 if (ci == null) { 1745 Log.d(TAG, "Failing scan request ClientInfo not found " + handler); 1746 return false; 1747 } 1748 if (!mActivePnoScans.isEmpty()) { 1749 loge("Failing scan request because there is already an active scan"); 1750 return false; 1751 } 1752 logScanRequest("addSwPnoScanRequest", ci, handler, null, scanSettings, pnoSettings); 1753 addPnoScanRequest(ci, handler, scanSettings, pnoSettings); 1754 // HW PNO is not supported, we need to revert to normal background scans and 1755 // report events after each scan and we need full scan results to get the IE information 1756 scanSettings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN 1757 | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT; 1758 addBackgroundScanRequest(scanSettings); 1759 return true; 1760 } 1761 1762 private void removeSwPnoScanRequest(ClientInfo ci, int handler) { 1763 if (ci != null) { 1764 Pair<PnoSettings, ScanSettings> settings = removePnoScanRequest(ci, handler); 1765 logScanRequest("removeSwPnoScanRequest", ci, handler, null, 1766 settings.second, settings.first); 1767 } 1768 } 1769 1770 private void reportPnoNetworkFound(ScanResult[] results) { 1771 WifiScanner.ParcelableScanResults parcelableScanResults = 1772 new WifiScanner.ParcelableScanResults(results); 1773 for (RequestInfo<Pair<PnoSettings, ScanSettings>> entry : mActivePnoScans) { 1774 ClientInfo ci = entry.clientInfo; 1775 int handler = entry.handlerId; 1776 logCallback("pnoNetworkFound", ci, handler, describeForLog(results)); 1777 ci.reportEvent( 1778 WifiScanner.CMD_PNO_NETWORK_FOUND, 0, handler, parcelableScanResults); 1779 } 1780 } 1781 1782 private void sendPnoScanFailedToAllAndClear(int reason, String description) { 1783 for (RequestInfo<Pair<PnoSettings, ScanSettings>> entry : mActivePnoScans) { 1784 ClientInfo ci = entry.clientInfo; 1785 int handler = entry.handlerId; 1786 ci.reportEvent(WifiScanner.CMD_OP_FAILED, 0, handler, 1787 new WifiScanner.OperationResult(reason, description)); 1788 } 1789 mActivePnoScans.clear(); 1790 } 1791 1792 private void addBackgroundScanRequest(ScanSettings settings) { 1793 if (DBG) localLog("Starting background scan"); 1794 if (mInternalClientInfo != null) { 1795 mInternalClientInfo.sendRequestToClientHandler( 1796 WifiScanner.CMD_START_BACKGROUND_SCAN, settings, 1797 WifiStateMachine.WIFI_WORK_SOURCE); 1798 } 1799 } 1800 1801 private void addSingleScanRequest(ScanSettings settings) { 1802 if (DBG) localLog("Starting single scan"); 1803 if (mInternalClientInfo != null) { 1804 mInternalClientInfo.sendRequestToClientHandler( 1805 WifiScanner.CMD_START_SINGLE_SCAN, settings, 1806 WifiStateMachine.WIFI_WORK_SOURCE); 1807 } 1808 } 1809 1810 /** 1811 * Checks if IE are present in scan data, if no single scan is needed to report event to 1812 * client 1813 */ 1814 private boolean isSingleScanNeeded(ScanResult[] scanResults) { 1815 for (ScanResult scanResult : scanResults) { 1816 if (scanResult.informationElements != null 1817 && scanResult.informationElements.length > 0) { 1818 return false; 1819 } 1820 } 1821 return true; 1822 } 1823 } 1824 1825 private abstract class ClientInfo { 1826 private final int mUid; 1827 private final WorkSource mWorkSource; 1828 private boolean mScanWorkReported = false; 1829 protected final Messenger mMessenger; 1830 1831 ClientInfo(int uid, Messenger messenger) { 1832 mUid = uid; 1833 mMessenger = messenger; 1834 mWorkSource = new WorkSource(uid); 1835 } 1836 1837 /** 1838 * Register this client to main client map. 1839 */ 1840 public void register() { 1841 mClients.put(mMessenger, this); 1842 } 1843 1844 /** 1845 * Unregister this client from main client map. 1846 */ 1847 private void unregister() { 1848 mClients.remove(mMessenger); 1849 } 1850 1851 public void cleanup() { 1852 mSingleScanListeners.removeAllForClient(this); 1853 mSingleScanStateMachine.removeSingleScanRequests(this); 1854 mBackgroundScanStateMachine.removeBackgroundScanSettings(this); 1855 unregister(); 1856 localLog("Successfully stopped all requests for client " + this); 1857 } 1858 1859 public int getUid() { 1860 return mUid; 1861 } 1862 1863 public void reportEvent(int what, int arg1, int arg2) { 1864 reportEvent(what, arg1, arg2, null); 1865 } 1866 1867 // This has to be implemented by subclasses to report events back to clients. 1868 public abstract void reportEvent(int what, int arg1, int arg2, Object obj); 1869 1870 // TODO(b/27903217): Blame scan on provided work source 1871 private void reportBatchedScanStart() { 1872 if (mUid == 0) 1873 return; 1874 1875 int csph = getCsph(); 1876 1877 try { 1878 mBatteryStats.noteWifiBatchedScanStartedFromSource(mWorkSource, csph); 1879 } catch (RemoteException e) { 1880 logw("failed to report scan work: " + e.toString()); 1881 } 1882 } 1883 1884 private void reportBatchedScanStop() { 1885 if (mUid == 0) 1886 return; 1887 1888 try { 1889 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mWorkSource); 1890 } catch (RemoteException e) { 1891 logw("failed to cleanup scan work: " + e.toString()); 1892 } 1893 } 1894 1895 // TODO migrate batterystats to accept scan duration per hour instead of csph 1896 private int getCsph() { 1897 int totalScanDurationPerHour = 0; 1898 Collection<ScanSettings> settingsList = 1899 mBackgroundScanStateMachine.getBackgroundScanSettings(this); 1900 for (ScanSettings settings : settingsList) { 1901 int scanDurationMs = mChannelHelper.estimateScanDuration(settings); 1902 int scans_per_Hour = settings.periodInMs == 0 ? 1 : (3600 * 1000) / 1903 settings.periodInMs; 1904 totalScanDurationPerHour += scanDurationMs * scans_per_Hour; 1905 } 1906 1907 return totalScanDurationPerHour / ChannelHelper.SCAN_PERIOD_PER_CHANNEL_MS; 1908 } 1909 1910 public void reportScanWorkUpdate() { 1911 if (mScanWorkReported) { 1912 reportBatchedScanStop(); 1913 mScanWorkReported = false; 1914 } 1915 if (mBackgroundScanStateMachine.getBackgroundScanSettings(this).isEmpty()) { 1916 reportBatchedScanStart(); 1917 mScanWorkReported = true; 1918 } 1919 } 1920 1921 @Override 1922 public String toString() { 1923 return "ClientInfo[uid=" + mUid + "," + mMessenger + "]"; 1924 } 1925 } 1926 1927 /** 1928 * This class is used to represent external clients to the WifiScanning Service. 1929 */ 1930 private class ExternalClientInfo extends ClientInfo { 1931 private final AsyncChannel mChannel; 1932 /** 1933 * Indicates if the client is still connected 1934 * If the client is no longer connected then messages to it will be silently dropped 1935 */ 1936 private boolean mDisconnected = false; 1937 1938 ExternalClientInfo(int uid, Messenger messenger, AsyncChannel c) { 1939 super(uid, messenger); 1940 mChannel = c; 1941 if (DBG) localLog("New client, channel: " + c); 1942 } 1943 1944 @Override 1945 public void reportEvent(int what, int arg1, int arg2, Object obj) { 1946 if (!mDisconnected) { 1947 mChannel.sendMessage(what, arg1, arg2, obj); 1948 } 1949 } 1950 1951 @Override 1952 public void cleanup() { 1953 mDisconnected = true; 1954 mPnoScanStateMachine.removePnoSettings(this); 1955 super.cleanup(); 1956 } 1957 } 1958 1959 /** 1960 * This class is used to represent internal clients to the WifiScanning Service. This is needed 1961 * for communicating between State Machines. 1962 * This leaves the onReportEvent method unimplemented, so that the clients have the freedom 1963 * to handle the events as they need. 1964 */ 1965 private class InternalClientInfo extends ClientInfo { 1966 private static final int INTERNAL_CLIENT_HANDLER = 0; 1967 1968 /** 1969 * The UID here is used to proxy the original external requester UID. 1970 */ 1971 InternalClientInfo(int requesterUid, Messenger messenger) { 1972 super(requesterUid, messenger); 1973 } 1974 1975 @Override 1976 public void reportEvent(int what, int arg1, int arg2, Object obj) { 1977 Message message = Message.obtain(); 1978 message.what = what; 1979 message.arg1 = arg1; 1980 message.arg2 = arg2; 1981 message.obj = obj; 1982 try { 1983 mMessenger.send(message); 1984 } catch (RemoteException e) { 1985 loge("Failed to send message: " + what); 1986 } 1987 } 1988 1989 /** 1990 * Send a message to the client handler which should reroute the message to the appropriate 1991 * state machine. 1992 */ 1993 public void sendRequestToClientHandler(int what, ScanSettings settings, 1994 WorkSource workSource) { 1995 Message msg = Message.obtain(); 1996 msg.what = what; 1997 msg.arg2 = INTERNAL_CLIENT_HANDLER; 1998 if (settings != null) { 1999 Bundle bundle = new Bundle(); 2000 bundle.putParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY, settings); 2001 bundle.putParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY, workSource); 2002 msg.obj = bundle; 2003 } 2004 msg.replyTo = mMessenger; 2005 msg.sendingUid = getUid(); 2006 mClientHandler.sendMessage(msg); 2007 } 2008 2009 /** 2010 * Send a message to the client handler which should reroute the message to the appropriate 2011 * state machine. 2012 */ 2013 public void sendRequestToClientHandler(int what) { 2014 sendRequestToClientHandler(what, null, null); 2015 } 2016 2017 @Override 2018 public String toString() { 2019 return "InternalClientInfo[]"; 2020 } 2021 } 2022 2023 void replySucceeded(Message msg) { 2024 if (msg.replyTo != null) { 2025 Message reply = Message.obtain(); 2026 reply.what = WifiScanner.CMD_OP_SUCCEEDED; 2027 reply.arg2 = msg.arg2; 2028 if (msg.obj != null) { 2029 reply.obj = msg.obj; 2030 } 2031 try { 2032 msg.replyTo.send(reply); 2033 mLog.trace("replySucceeded recvdMessage=%").c(msg.what).flush(); 2034 } catch (RemoteException e) { 2035 // There's not much we can do if reply can't be sent! 2036 } 2037 } else { 2038 // locally generated message; doesn't need a reply! 2039 } 2040 } 2041 2042 void replyFailed(Message msg, int reason, String description) { 2043 if (msg.replyTo != null) { 2044 Message reply = Message.obtain(); 2045 reply.what = WifiScanner.CMD_OP_FAILED; 2046 reply.arg2 = msg.arg2; 2047 reply.obj = new WifiScanner.OperationResult(reason, description); 2048 try { 2049 msg.replyTo.send(reply); 2050 mLog.trace("replyFailed recvdMessage=% reason=%") 2051 .c(msg.what) 2052 .c(reason) 2053 .flush(); 2054 } catch (RemoteException e) { 2055 // There's not much we can do if reply can't be sent! 2056 } 2057 } else { 2058 // locally generated message; doesn't need a reply! 2059 } 2060 } 2061 2062 private static String toString(int uid, ScanSettings settings) { 2063 StringBuilder sb = new StringBuilder(); 2064 sb.append("ScanSettings[uid=").append(uid); 2065 sb.append(", period=").append(settings.periodInMs); 2066 sb.append(", report=").append(settings.reportEvents); 2067 if (settings.reportEvents == WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL 2068 && settings.numBssidsPerScan > 0 2069 && settings.maxScansToCache > 1) { 2070 sb.append(", batch=").append(settings.maxScansToCache); 2071 sb.append(", numAP=").append(settings.numBssidsPerScan); 2072 } 2073 sb.append(", ").append(ChannelHelper.toString(settings)); 2074 sb.append("]"); 2075 2076 return sb.toString(); 2077 } 2078 2079 @Override 2080 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2081 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 2082 != PackageManager.PERMISSION_GRANTED) { 2083 pw.println("Permission Denial: can't dump WifiScanner from from pid=" 2084 + Binder.getCallingPid() 2085 + ", uid=" + Binder.getCallingUid() 2086 + " without permission " 2087 + android.Manifest.permission.DUMP); 2088 return; 2089 } 2090 pw.println("WifiScanningService - Log Begin ----"); 2091 mLocalLog.dump(fd, pw, args); 2092 pw.println("WifiScanningService - Log End ----"); 2093 pw.println(); 2094 pw.println("clients:"); 2095 for (ClientInfo client : mClients.values()) { 2096 pw.println(" " + client); 2097 } 2098 pw.println("listeners:"); 2099 for (ClientInfo client : mClients.values()) { 2100 Collection<ScanSettings> settingsList = 2101 mBackgroundScanStateMachine.getBackgroundScanSettings(client); 2102 for (ScanSettings settings : settingsList) { 2103 pw.println(" " + toString(client.mUid, settings)); 2104 } 2105 } 2106 if (mBackgroundScheduler != null) { 2107 WifiNative.ScanSettings schedule = mBackgroundScheduler.getSchedule(); 2108 if (schedule != null) { 2109 pw.println("schedule:"); 2110 pw.println(" base period: " + schedule.base_period_ms); 2111 pw.println(" max ap per scan: " + schedule.max_ap_per_scan); 2112 pw.println(" batched scans: " + schedule.report_threshold_num_scans); 2113 pw.println(" buckets:"); 2114 for (int b = 0; b < schedule.num_buckets; b++) { 2115 WifiNative.BucketSettings bucket = schedule.buckets[b]; 2116 pw.println(" bucket " + bucket.bucket + " (" + bucket.period_ms + "ms)[" 2117 + bucket.report_events + "]: " 2118 + ChannelHelper.toString(bucket)); 2119 } 2120 } 2121 } 2122 if (mPnoScanStateMachine != null) { 2123 mPnoScanStateMachine.dump(fd, pw, args); 2124 } 2125 pw.println(); 2126 2127 if (mSingleScanStateMachine != null) { 2128 mSingleScanStateMachine.dump(fd, pw, args); 2129 pw.println(); 2130 pw.println("Latest scan results:"); 2131 List<ScanResult> scanResults = mSingleScanStateMachine.getCachedScanResultsAsList(); 2132 long nowMs = System.currentTimeMillis(); 2133 if (scanResults != null && scanResults.size() != 0) { 2134 pw.println(" BSSID Frequency RSSI Age(sec) SSID " 2135 + " Flags"); 2136 for (ScanResult r : scanResults) { 2137 String age; 2138 if (r.seen <= 0) { 2139 age = "___?___"; 2140 } else if (nowMs < r.seen) { 2141 age = " 0.000"; 2142 } else if (r.seen < nowMs - 1000000) { 2143 age = ">1000.0"; 2144 } else { 2145 age = String.format("%3.3f", (nowMs - r.seen) / 1000.0); 2146 } 2147 String ssid = r.SSID == null ? "" : r.SSID; 2148 pw.printf(" %17s %9d %5d %7s %-32s %s\n", 2149 r.BSSID, 2150 r.frequency, 2151 r.level, 2152 age, 2153 String.format("%1.32s", ssid), 2154 r.capabilities); 2155 } 2156 } 2157 pw.println(); 2158 } 2159 } 2160 2161 void logScanRequest(String request, ClientInfo ci, int id, WorkSource workSource, 2162 ScanSettings settings, PnoSettings pnoSettings) { 2163 StringBuilder sb = new StringBuilder(); 2164 sb.append(request) 2165 .append(": ") 2166 .append((ci == null) ? "ClientInfo[unknown]" : ci.toString()) 2167 .append(",Id=") 2168 .append(id); 2169 if (workSource != null) { 2170 sb.append(",").append(workSource); 2171 } 2172 if (settings != null) { 2173 sb.append(", "); 2174 describeTo(sb, settings); 2175 } 2176 if (pnoSettings != null) { 2177 sb.append(", "); 2178 describeTo(sb, pnoSettings); 2179 } 2180 localLog(sb.toString()); 2181 } 2182 2183 void logCallback(String callback, ClientInfo ci, int id, String extra) { 2184 StringBuilder sb = new StringBuilder(); 2185 sb.append(callback) 2186 .append(": ") 2187 .append((ci == null) ? "ClientInfo[unknown]" : ci.toString()) 2188 .append(",Id=") 2189 .append(id); 2190 if (extra != null) { 2191 sb.append(",").append(extra); 2192 } 2193 localLog(sb.toString()); 2194 } 2195 2196 static String describeForLog(ScanData[] results) { 2197 StringBuilder sb = new StringBuilder(); 2198 sb.append("results="); 2199 for (int i = 0; i < results.length; ++i) { 2200 if (i > 0) sb.append(";"); 2201 sb.append(results[i].getResults().length); 2202 } 2203 return sb.toString(); 2204 } 2205 2206 static String describeForLog(ScanResult[] results) { 2207 return "results=" + results.length; 2208 } 2209 2210 static String describeTo(StringBuilder sb, ScanSettings scanSettings) { 2211 sb.append("ScanSettings { ") 2212 .append(" band:").append(scanSettings.band) 2213 .append(" period:").append(scanSettings.periodInMs) 2214 .append(" reportEvents:").append(scanSettings.reportEvents) 2215 .append(" numBssidsPerScan:").append(scanSettings.numBssidsPerScan) 2216 .append(" maxScansToCache:").append(scanSettings.maxScansToCache) 2217 .append(" channels:[ "); 2218 if (scanSettings.channels != null) { 2219 for (int i = 0; i < scanSettings.channels.length; i++) { 2220 sb.append(scanSettings.channels[i].frequency) 2221 .append(" "); 2222 } 2223 } 2224 sb.append(" ] ") 2225 .append(" } "); 2226 return sb.toString(); 2227 } 2228 2229 static String describeTo(StringBuilder sb, PnoSettings pnoSettings) { 2230 sb.append("PnoSettings { ") 2231 .append(" min5GhzRssi:").append(pnoSettings.min5GHzRssi) 2232 .append(" min24GhzRssi:").append(pnoSettings.min24GHzRssi) 2233 .append(" initialScoreMax:").append(pnoSettings.initialScoreMax) 2234 .append(" currentConnectionBonus:").append(pnoSettings.currentConnectionBonus) 2235 .append(" sameNetworkBonus:").append(pnoSettings.sameNetworkBonus) 2236 .append(" secureBonus:").append(pnoSettings.secureBonus) 2237 .append(" band5GhzBonus:").append(pnoSettings.band5GHzBonus) 2238 .append(" isConnected:").append(pnoSettings.isConnected) 2239 .append(" networks:[ "); 2240 if (pnoSettings.networkList != null) { 2241 for (int i = 0; i < pnoSettings.networkList.length; i++) { 2242 sb.append(pnoSettings.networkList[i].ssid).append(","); 2243 } 2244 } 2245 sb.append(" ] ") 2246 .append(" } "); 2247 return sb.toString(); 2248 } 2249 } 2250