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