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