1 /* 2 * Copyright (C) 2014 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.bluetooth.le_scan; 18 19 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_CACHED; 20 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE; 21 import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; 22 import static android.bluetooth.BluetoothProfile.STATE_CONNECTING; 23 import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; 24 import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTING; 25 import static android.bluetooth.le.ScanSettings.getScanModeString; 26 27 import android.app.ActivityManager; 28 import android.app.AlarmManager; 29 import android.app.PendingIntent; 30 import android.bluetooth.BluetoothDevice; 31 import android.bluetooth.BluetoothProfile; 32 import android.bluetooth.le.ScanCallback; 33 import android.bluetooth.le.ScanFilter; 34 import android.bluetooth.le.ScanSettings; 35 import android.content.BroadcastReceiver; 36 import android.content.ContentResolver; 37 import android.content.Context; 38 import android.content.Intent; 39 import android.content.IntentFilter; 40 import android.content.pm.PackageManager; 41 import android.hardware.display.DisplayManager; 42 import android.location.LocationManager; 43 import android.os.Handler; 44 import android.os.Looper; 45 import android.os.Message; 46 import android.os.RemoteException; 47 import android.provider.Settings; 48 import android.util.Log; 49 import android.util.SparseBooleanArray; 50 import android.util.SparseIntArray; 51 import android.view.Display; 52 53 import androidx.annotation.Nullable; 54 55 import com.android.bluetooth.Utils; 56 import com.android.bluetooth.Utils.TimeProvider; 57 import com.android.bluetooth.btservice.AdapterService; 58 import com.android.bluetooth.btservice.BluetoothAdapterProxy; 59 import com.android.bluetooth.flags.Flags; 60 import com.android.bluetooth.gatt.FilterParams; 61 import com.android.bluetooth.util.SystemProperties; 62 import com.android.internal.annotations.GuardedBy; 63 import com.android.internal.annotations.VisibleForTesting; 64 65 import java.util.ArrayDeque; 66 import java.util.Collections; 67 import java.util.Deque; 68 import java.util.HashMap; 69 import java.util.HashSet; 70 import java.util.Iterator; 71 import java.util.Map; 72 import java.util.Objects; 73 import java.util.Set; 74 import java.util.UUID; 75 import java.util.concurrent.ConcurrentHashMap; 76 import java.util.concurrent.atomic.AtomicReference; 77 import java.util.stream.Collectors; 78 79 /** Class that handles Bluetooth LE scan related operations. */ 80 public class ScanManager { 81 private static final String TAG = ScanManager.class.getSimpleName(); 82 83 public static final int SCAN_MODE_SCREEN_OFF_LOW_POWER_WINDOW_MS = 512; 84 public static final int SCAN_MODE_SCREEN_OFF_LOW_POWER_INTERVAL_MS = 10240; 85 public static final int SCAN_MODE_SCREEN_OFF_BALANCED_WINDOW_MS = 183; 86 public static final int SCAN_MODE_SCREEN_OFF_BALANCED_INTERVAL_MS = 730; 87 88 /** Scan params corresponding to regular scan setting */ 89 @VisibleForTesting static final int SCAN_MODE_LOW_POWER_WINDOW_MS = 140; 90 91 @VisibleForTesting static final int SCAN_MODE_LOW_POWER_INTERVAL_MS = 1400; 92 @VisibleForTesting static final int SCAN_MODE_BALANCED_WINDOW_MS = 183; 93 @VisibleForTesting static final int SCAN_MODE_BALANCED_INTERVAL_MS = 730; 94 @VisibleForTesting static final int SCAN_MODE_LOW_LATENCY_WINDOW_MS = 100; 95 @VisibleForTesting static final int SCAN_MODE_LOW_LATENCY_INTERVAL_MS = 100; 96 97 // Result type defined in bt stack. Need to be accessed by ScanController. 98 static final int SCAN_RESULT_TYPE_TRUNCATED = 1; 99 static final int SCAN_RESULT_TYPE_FULL = 2; 100 static final int SCAN_RESULT_TYPE_BOTH = 3; 101 102 // Messages for handling BLE scan operations. 103 @VisibleForTesting static final int MSG_START_BLE_SCAN = 0; 104 static final int MSG_STOP_BLE_SCAN = 1; 105 static final int MSG_FLUSH_BATCH_RESULTS = 2; 106 static final int MSG_SCAN_TIMEOUT = 3; 107 static final int MSG_SUSPEND_SCANS = 4; 108 static final int MSG_RESUME_SCANS = 5; 109 static final int MSG_IMPORTANCE_CHANGE = 6; 110 static final int MSG_SCREEN_ON = 7; 111 static final int MSG_SCREEN_OFF = 8; 112 static final int MSG_REVERT_SCAN_MODE_UPGRADE = 9; 113 static final int MSG_START_CONNECTING = 10; 114 static final int MSG_STOP_CONNECTING = 11; 115 private static final String ACTION_REFRESH_BATCHED_SCAN = 116 "com.android.bluetooth.gatt.REFRESH_BATCHED_SCAN"; 117 118 private static final int FOREGROUND_IMPORTANCE_CUTOFF = IMPORTANCE_FOREGROUND_SERVICE; 119 private static final boolean DEFAULT_UID_IS_FOREGROUND = true; 120 private static final int SCAN_MODE_APP_IN_BACKGROUND = ScanSettings.SCAN_MODE_LOW_POWER; 121 private static final int SCAN_MODE_FORCE_DOWNGRADED = ScanSettings.SCAN_MODE_LOW_POWER; 122 private static final int SCAN_MODE_MAX_IN_CONCURRENCY = ScanSettings.SCAN_MODE_BALANCED; 123 124 // Timeout for each controller operation. 125 private static final int OPERATION_TIME_OUT_MILLIS = 500; 126 private static final int MAX_IS_UID_FOREGROUND_MAP_SIZE = 500; 127 128 @VisibleForTesting final ScanNative mScanNative; 129 @VisibleForTesting final ClientHandler mHandler; 130 131 private final Object mCurUsedTrackableAdvertisementsLock = new Object(); 132 private final Set<ScanClient> mRegularScanClients = 133 Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>()); 134 private final Set<ScanClient> mBatchClients = 135 Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>()); 136 private final Set<ScanClient> mSuspendedScanClients = 137 Collections.newSetFromMap(new ConcurrentHashMap<ScanClient, Boolean>()); 138 private final SparseIntArray mPriorityMap = new SparseIntArray(); 139 private final SparseBooleanArray mIsUidForegroundMap = new SparseBooleanArray(); 140 private final AdapterService mAdapterService; 141 private final ScanController mScanController; 142 private final TimeProvider mTimeProvider; 143 private final BluetoothAdapterProxy mBluetoothAdapterProxy; 144 private final DisplayManager mDisplayManager; 145 private final ActivityManager mActivityManager; 146 private final LocationManager mLocationManager; 147 private final BatchScanThrottler mBatchScanThrottler; 148 149 @VisibleForTesting boolean mIsConnecting; 150 @VisibleForTesting int mProfilesConnecting; 151 152 private int mLastConfiguredScanSetting1m = Integer.MIN_VALUE; 153 private int mLastConfiguredScanSettingCoded = Integer.MIN_VALUE; 154 // Scan parameters for batch scan. 155 private BatchScanParams mBatchScanParams; 156 157 @GuardedBy("mCurUsedTrackableAdvertisementsLock") 158 private int mCurUsedTrackableAdvertisements = 0; 159 160 private boolean mScreenOn = false; 161 private int mProfilesConnected, mProfilesDisconnecting; 162 163 @VisibleForTesting UidImportance(int uid, int importance)164 record UidImportance(int uid, int importance) {} 165 ScanManager( AdapterService adapterService, ScanController scanController, BluetoothAdapterProxy bluetoothAdapterProxy, Looper looper, TimeProvider timeProvider)166 ScanManager( 167 AdapterService adapterService, 168 ScanController scanController, 169 BluetoothAdapterProxy bluetoothAdapterProxy, 170 Looper looper, 171 TimeProvider timeProvider) { 172 mScanController = scanController; 173 mAdapterService = adapterService; 174 mTimeProvider = timeProvider; 175 mScanNative = new ScanNative(scanController); 176 mDisplayManager = mAdapterService.getSystemService(DisplayManager.class); 177 mActivityManager = mAdapterService.getSystemService(ActivityManager.class); 178 mLocationManager = mAdapterService.getSystemService(LocationManager.class); 179 mBluetoothAdapterProxy = bluetoothAdapterProxy; 180 mIsConnecting = false; 181 mPriorityMap.put(ScanSettings.SCAN_MODE_OPPORTUNISTIC, 0); 182 mPriorityMap.put(ScanSettings.SCAN_MODE_SCREEN_OFF, 1); 183 mPriorityMap.put(ScanSettings.SCAN_MODE_LOW_POWER, 2); 184 mPriorityMap.put(ScanSettings.SCAN_MODE_SCREEN_OFF_BALANCED, 3); 185 // BALANCED and AMBIENT_DISCOVERY now have the same settings and priority. 186 mPriorityMap.put(ScanSettings.SCAN_MODE_BALANCED, 4); 187 mPriorityMap.put(ScanSettings.SCAN_MODE_AMBIENT_DISCOVERY, 4); 188 mPriorityMap.put(ScanSettings.SCAN_MODE_LOW_LATENCY, 5); 189 mHandler = new ClientHandler(looper); 190 if (mDisplayManager != null) { 191 mDisplayManager.registerDisplayListener(mDisplayListener, null); 192 } 193 mScreenOn = isScreenOn(); 194 AppScanStats.initScanRadioState(); 195 AppScanStats.setScreenState(mScreenOn, mTimeProvider); 196 if (mActivityManager != null) { 197 mActivityManager.addOnUidImportanceListener( 198 mUidImportanceListener, FOREGROUND_IMPORTANCE_CUTOFF); 199 } 200 IntentFilter locationIntentFilter = new IntentFilter(LocationManager.MODE_CHANGED_ACTION); 201 locationIntentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 202 mAdapterService.registerReceiver(mLocationReceiver, locationIntentFilter); 203 mBatchScanThrottler = new BatchScanThrottler(timeProvider, mScreenOn); 204 } 205 cleanup()206 void cleanup() { 207 mRegularScanClients.clear(); 208 mBatchClients.clear(); 209 mSuspendedScanClients.clear(); 210 211 if (mActivityManager != null) { 212 try { 213 mActivityManager.removeOnUidImportanceListener(mUidImportanceListener); 214 } catch (IllegalArgumentException e) { 215 Log.w(TAG, "exception when invoking removeOnUidImportanceListener", e); 216 } 217 } 218 219 if (mDisplayManager != null) { 220 mDisplayManager.unregisterDisplayListener(mDisplayListener); 221 } 222 223 // Shut down the thread 224 mHandler.removeCallbacksAndMessages(null); 225 226 mScanNative.cleanup(); 227 228 try { 229 mAdapterService.unregisterReceiver(mLocationReceiver); 230 } catch (IllegalArgumentException e) { 231 Log.w(TAG, "exception when invoking unregisterReceiver(mLocationReceiver)", e); 232 } 233 } 234 registerScanner(UUID uuid)235 void registerScanner(UUID uuid) { 236 mScanNative.registerScanner(uuid.getLeastSignificantBits(), uuid.getMostSignificantBits()); 237 } 238 unregisterScanner(int scannerId)239 void unregisterScanner(int scannerId) { 240 mScanNative.unregisterScanner(scannerId); 241 } 242 243 /** Returns the regular scan queue. */ getRegularScanQueue()244 Set<ScanClient> getRegularScanQueue() { 245 return mRegularScanClients; 246 } 247 248 /** Returns the suspended scan queue. */ getSuspendedScanQueue()249 Set<ScanClient> getSuspendedScanQueue() { 250 return mSuspendedScanClients; 251 } 252 253 /** Returns batch scan queue. */ getBatchScanQueue()254 Set<ScanClient> getBatchScanQueue() { 255 return mBatchClients; 256 } 257 258 /** Returns a set of full batch scan clients. */ getFullBatchScanQueue()259 Set<ScanClient> getFullBatchScanQueue() { 260 // TODO: split full batch scan clients and truncated batch clients so we don't need to 261 // construct this every time. 262 return mBatchClients.stream() 263 .filter(c -> c.mSettings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_FULL) 264 .collect(Collectors.toSet()); 265 } 266 startScan(ScanClient client)267 void startScan(ScanClient client) { 268 Log.d(TAG, "startScan() " + client); 269 sendMessage(MSG_START_BLE_SCAN, client); 270 } 271 stopScan(int scannerId)272 void stopScan(int scannerId) { 273 ScanClient client = mScanNative.getBatchScanClient(scannerId); 274 if (client == null) { 275 client = mScanNative.getRegularScanClient(scannerId); 276 } 277 if (client == null) { 278 client = mScanNative.getSuspendedScanClient(scannerId); 279 } 280 sendMessage(MSG_STOP_BLE_SCAN, client); 281 } 282 flushBatchScanResults(ScanClient client)283 void flushBatchScanResults(ScanClient client) { 284 sendMessage(MSG_FLUSH_BATCH_RESULTS, client); 285 } 286 callbackDone(int scannerId, int status)287 void callbackDone(int scannerId, int status) { 288 mScanNative.callbackDone(scannerId, status); 289 } 290 batchScanResultDelivered()291 void batchScanResultDelivered() { 292 mBatchScanThrottler.resetBackoff(); 293 } 294 sendMessage(int what, ScanClient client)295 private void sendMessage(int what, ScanClient client) { 296 mHandler.obtainMessage(what, client).sendToTarget(); 297 } 298 isFilteringSupported()299 private boolean isFilteringSupported() { 300 if (mBluetoothAdapterProxy == null) { 301 Log.e(TAG, "mBluetoothAdapterProxy is null"); 302 return false; 303 } 304 return mBluetoothAdapterProxy.isOffloadedScanFilteringSupported(); 305 } 306 isAutoBatchScanClientEnabled(ScanClient client)307 boolean isAutoBatchScanClientEnabled(ScanClient client) { 308 return mScanNative.isAutoBatchScanClientEnabled(client); 309 } 310 getCurrentUsedTrackingAdvertisement()311 int getCurrentUsedTrackingAdvertisement() { 312 synchronized (mCurUsedTrackableAdvertisementsLock) { 313 return mCurUsedTrackableAdvertisements; 314 } 315 } 316 fetchAppForegroundState(ScanClient client)317 void fetchAppForegroundState(ScanClient client) { 318 PackageManager packageManager = mAdapterService.getPackageManager(); 319 if (mActivityManager == null || packageManager == null) { 320 return; 321 } 322 String[] packages = packageManager.getPackagesForUid(client.mAppUid); 323 if (packages == null || packages.length == 0) { 324 return; 325 } 326 int importance = IMPORTANCE_CACHED; 327 for (String packageName : packages) { 328 importance = Math.min(importance, mActivityManager.getPackageImportance(packageName)); 329 } 330 boolean isForeground = importance <= IMPORTANCE_FOREGROUND_SERVICE; 331 mIsUidForegroundMap.put(client.mAppUid, isForeground); 332 if (client.mStats != null) { 333 client.mStats.setAppImportance(importance); 334 } 335 } 336 337 // Handler class that handles BLE scan operations. 338 @VisibleForTesting 339 class ClientHandler extends Handler { 340 ClientHandler(Looper looper)341 ClientHandler(Looper looper) { 342 super(looper); 343 } 344 345 @Override handleMessage(Message msg)346 public void handleMessage(Message msg) { 347 switch (msg.what) { 348 case MSG_START_BLE_SCAN: 349 handleStartScan((ScanClient) msg.obj); 350 break; 351 case MSG_STOP_BLE_SCAN: 352 handleStopScan((ScanClient) msg.obj); 353 break; 354 case MSG_FLUSH_BATCH_RESULTS: 355 handleFlushBatchResults((ScanClient) msg.obj); 356 break; 357 case MSG_SCAN_TIMEOUT: 358 mScanNative.regularScanTimeout((ScanClient) msg.obj); 359 break; 360 case MSG_SUSPEND_SCANS: 361 handleSuspendScans(); 362 break; 363 case MSG_RESUME_SCANS: 364 handleResumeScans(); 365 break; 366 case MSG_SCREEN_OFF: 367 handleScreenOff(); 368 break; 369 case MSG_SCREEN_ON: 370 handleScreenOn(); 371 break; 372 case MSG_REVERT_SCAN_MODE_UPGRADE: 373 handleRevertScanModeUpgrade((ScanClient) msg.obj); 374 break; 375 case MSG_IMPORTANCE_CHANGE: 376 handleImportanceChange((UidImportance) msg.obj); 377 break; 378 case MSG_START_CONNECTING: 379 handleConnectingState(); 380 break; 381 case MSG_STOP_CONNECTING: 382 handleClearConnectingState(); 383 break; 384 default: 385 // Shouldn't happen. 386 Log.e(TAG, "received an unknown message : " + msg.what); 387 } 388 } 389 handleStartScan(ScanClient client)390 private void handleStartScan(ScanClient client) { 391 Log.d(TAG, "handling starting scan"); 392 fetchAppForegroundState(client); 393 394 if (!isScanSupported(client)) { 395 Log.e(TAG, "Scan settings not supported"); 396 return; 397 } 398 399 if (mRegularScanClients.contains(client) || mBatchClients.contains(client)) { 400 Log.e(TAG, "Scan already started for scanner id: " + client.mScannerId); 401 return; 402 } 403 404 if (requiresScreenOn(client) && !mScreenOn) { 405 Log.w( 406 TAG, 407 "Cannot start unfiltered scan in screen-off. This scan will be resumed " 408 + "later: " 409 + client.mScannerId); 410 mSuspendedScanClients.add(client); 411 if (client.mStats != null) { 412 client.mStats.recordScanSuspend(client.mScannerId); 413 } 414 return; 415 } 416 417 final boolean locationEnabled = mLocationManager.isLocationEnabled(); 418 if (requiresLocationOn(client) && !locationEnabled) { 419 Log.i( 420 TAG, 421 "Cannot start unfiltered scan in location-off. This scan will be" 422 + " resumed when location is on: " 423 + client.mScannerId); 424 mSuspendedScanClients.add(client); 425 if (client.mStats != null) { 426 client.mStats.recordScanSuspend(client.mScannerId); 427 } 428 return; 429 } 430 431 if (!mScanNative.isExemptFromAutoBatchScanUpdate(client)) { 432 if (mScreenOn) { 433 clearAutoBatchScanClient(client); 434 } else { 435 setAutoBatchScanClient(client); 436 } 437 } 438 439 // Begin scan operations. 440 if (isBatchClient(client) || isAutoBatchScanClientEnabled(client)) { 441 mBatchClients.add(client); 442 mScanNative.startBatchScan(client); 443 } else { 444 updateScanModeBeforeStart(client); 445 updateScanModeConcurrency(client); 446 mRegularScanClients.add(client); 447 mScanNative.startRegularScan(client); 448 if (!mScanNative.isOpportunisticScanClient(client)) { 449 mScanNative.configureRegularScanParams(); 450 451 if (!mScanNative.isExemptFromScanTimeout(client)) { 452 Message msg = obtainMessage(MSG_SCAN_TIMEOUT); 453 msg.obj = client; 454 // Only one timeout message should exist at any time 455 removeMessages(MSG_SCAN_TIMEOUT, client); 456 sendMessageDelayed(msg, mAdapterService.getScanTimeoutMillis()); 457 Log.d( 458 TAG, 459 "apply scan timeout (" 460 + mAdapterService.getScanTimeoutMillis() 461 + ")" 462 + "to scannerId " 463 + client.mScannerId); 464 } 465 } 466 } 467 client.mStarted = true; 468 } 469 requiresScreenOn(ScanClient client)470 private boolean requiresScreenOn(ScanClient client) { 471 boolean isFiltered = isFilteredScan(client); 472 return !mScanNative.isOpportunisticScanClient(client) && !isFiltered; 473 } 474 requiresLocationOn(ScanClient client)475 private static boolean requiresLocationOn(ScanClient client) { 476 boolean isFiltered = isFilteredScan(client); 477 return !client.mHasDisavowedLocation && !isFiltered; 478 } 479 isFilteredScan(ScanClient client)480 private static boolean isFilteredScan(ScanClient client) { 481 if ((client.mFilters == null) || client.mFilters.isEmpty()) { 482 return false; 483 } 484 485 boolean atLeastOneValidFilter = false; 486 for (ScanFilter filter : client.mFilters) { 487 // A valid filter need at least one field not empty 488 if (!filter.isAllFieldsEmpty()) { 489 atLeastOneValidFilter = true; 490 break; 491 } 492 } 493 return atLeastOneValidFilter; 494 } 495 handleStopScan(ScanClient client)496 private void handleStopScan(ScanClient client) { 497 if (client == null) { 498 return; 499 } 500 Log.d(TAG, "handling stopping scan " + client); 501 502 if (mSuspendedScanClients.contains(client)) { 503 mSuspendedScanClients.remove(client); 504 } 505 removeMessages(MSG_REVERT_SCAN_MODE_UPGRADE, client); 506 removeMessages(MSG_SCAN_TIMEOUT, client); 507 if (mRegularScanClients.contains(client)) { 508 mScanNative.stopRegularScan(client); 509 510 if (!mScanNative.isOpportunisticScanClient(client)) { 511 mScanNative.configureRegularScanParams(); 512 } 513 } else { 514 if (isAutoBatchScanClientEnabled(client)) { 515 handleFlushBatchResults(client); 516 } 517 mScanNative.stopBatchScan(client); 518 } 519 if (client.mAppDied) { 520 Log.d(TAG, "app died, unregister scanner - " + client.mScannerId); 521 mScanController.unregisterScannerInternal(client.mScannerId); 522 } 523 } 524 handleFlushBatchResults(ScanClient client)525 private void handleFlushBatchResults(ScanClient client) { 526 Log.d(TAG, "handleFlushBatchResults() " + client); 527 if (!mBatchClients.contains(client)) { 528 Log.d(TAG, "There is no batch scan client to flush " + client); 529 return; 530 } 531 mScanNative.flushBatchResults(client.mScannerId); 532 } 533 isBatchClient(ScanClient client)534 private static boolean isBatchClient(ScanClient client) { 535 if (client == null || client.mSettings == null) { 536 return false; 537 } 538 ScanSettings settings = client.mSettings; 539 return settings.getCallbackType() == ScanSettings.CALLBACK_TYPE_ALL_MATCHES 540 && settings.getReportDelayMillis() != 0; 541 } 542 isScanSupported(ScanClient client)543 private boolean isScanSupported(ScanClient client) { 544 if (client == null || client.mSettings == null) { 545 return true; 546 } 547 ScanSettings settings = client.mSettings; 548 if (isFilteringSupported()) { 549 return true; 550 } 551 return settings.getCallbackType() == ScanSettings.CALLBACK_TYPE_ALL_MATCHES 552 && settings.getReportDelayMillis() == 0; 553 } 554 handleScreenOff()555 private void handleScreenOff() { 556 AppScanStats.setScreenState(false, mTimeProvider); 557 if (!mScreenOn) { 558 return; 559 } 560 mScreenOn = false; 561 Log.d(TAG, "handleScreenOff()"); 562 mBatchScanThrottler.onScreenOn(false); 563 handleSuspendScans(); 564 updateRegularScanClientsScreenOff(); 565 updateRegularScanToBatchScanClients(); 566 } 567 handleConnectingState()568 private void handleConnectingState() { 569 if (mAdapterService.getScanDowngradeDurationMillis() == 0) { 570 return; 571 } 572 boolean updatedScanParams = false; 573 mIsConnecting = true; 574 Log.d(TAG, "handleConnectingState()"); 575 for (ScanClient client : mRegularScanClients) { 576 if (downgradeScanModeFromMaxDuty(client)) { 577 updatedScanParams = true; 578 Log.d(TAG, "scanMode is downgraded by connecting for " + client); 579 } 580 } 581 if (updatedScanParams) { 582 mScanNative.configureRegularScanParams(); 583 } 584 removeMessages(MSG_STOP_CONNECTING); 585 Message msg = obtainMessage(MSG_STOP_CONNECTING); 586 sendMessageDelayed(msg, mAdapterService.getScanDowngradeDurationMillis()); 587 } 588 handleClearConnectingState()589 private void handleClearConnectingState() { 590 if (!mIsConnecting) { 591 Log.e(TAG, "handleClearConnectingState() - not connecting state"); 592 return; 593 } 594 Log.d(TAG, "handleClearConnectingState()"); 595 boolean updatedScanParams = false; 596 for (ScanClient client : mRegularScanClients) { 597 if (revertDowngradeScanModeFromMaxDuty(client)) { 598 updatedScanParams = true; 599 Log.d(TAG, "downgraded scanMode is reverted for " + client); 600 } 601 } 602 if (updatedScanParams) { 603 mScanNative.configureRegularScanParams(); 604 } 605 removeMessages(MSG_STOP_CONNECTING); 606 mIsConnecting = false; 607 } 608 handleSuspendScans()609 private void handleSuspendScans() { 610 for (ScanClient client : mRegularScanClients) { 611 if ((requiresScreenOn(client) && !mScreenOn) 612 || (requiresLocationOn(client) && !mLocationManager.isLocationEnabled())) { 613 /*Suspend unfiltered scans*/ 614 if (client.mStats != null) { 615 client.mStats.recordScanSuspend(client.mScannerId); 616 } 617 Log.d(TAG, "suspend scan " + client); 618 handleStopScan(client); 619 mSuspendedScanClients.add(client); 620 } 621 } 622 } 623 updateRegularScanToBatchScanClients()624 private void updateRegularScanToBatchScanClients() { 625 boolean updatedScanParams = false; 626 for (ScanClient client : mRegularScanClients) { 627 if (!mScanNative.isExemptFromAutoBatchScanUpdate(client)) { 628 Log.d(TAG, "Updating regular scan to batch scan" + client); 629 handleStopScan(client); 630 setAutoBatchScanClient(client); 631 handleStartScan(client); 632 updatedScanParams = true; 633 } 634 } 635 if (updatedScanParams) { 636 mScanNative.configureRegularScanParams(); 637 } 638 } 639 updateBatchScanToRegularScanClients()640 private void updateBatchScanToRegularScanClients() { 641 boolean updatedScanParams = false; 642 for (ScanClient client : mBatchClients) { 643 if (!mScanNative.isExemptFromAutoBatchScanUpdate(client)) { 644 Log.d(TAG, "Updating batch scan to regular scan" + client); 645 handleStopScan(client); 646 clearAutoBatchScanClient(client); 647 handleStartScan(client); 648 updatedScanParams = true; 649 } 650 } 651 if (updatedScanParams) { 652 mScanNative.configureRegularScanParams(); 653 } 654 } 655 setAutoBatchScanClient(ScanClient client)656 private void setAutoBatchScanClient(ScanClient client) { 657 if (isAutoBatchScanClientEnabled(client)) { 658 return; 659 } 660 client.updateScanMode(ScanSettings.SCAN_MODE_SCREEN_OFF); 661 Log.d( 662 TAG, 663 "Scan mode update during setAutoBatchScanClient() to " 664 + getScanModeString(ScanSettings.SCAN_MODE_SCREEN_OFF)); 665 if (client.mStats != null) { 666 client.mStats.setAutoBatchScan(client.mScannerId, true); 667 } 668 } 669 clearAutoBatchScanClient(ScanClient client)670 private void clearAutoBatchScanClient(ScanClient client) { 671 if (!isAutoBatchScanClientEnabled(client)) { 672 return; 673 } 674 client.updateScanMode(client.mScanModeApp); 675 Log.d( 676 TAG, 677 "Scan mode update during clearAutoBatchScanClient() to " 678 + getScanModeString(client.mScanModeApp)); 679 if (client.mStats != null) { 680 client.mStats.setAutoBatchScan(client.mScannerId, false); 681 } 682 } 683 updateRegularScanClientsScreenOff()684 private void updateRegularScanClientsScreenOff() { 685 boolean updatedScanParams = false; 686 for (ScanClient client : mRegularScanClients) { 687 if (updateScanModeScreenOff(client)) { 688 updatedScanParams = true; 689 } 690 } 691 if (updatedScanParams) { 692 mScanNative.configureRegularScanParams(); 693 } 694 } 695 updateScanModeScreenOff(ScanClient client)696 private boolean updateScanModeScreenOff(ScanClient client) { 697 if (mScanNative.isOpportunisticScanClient(client)) { 698 return false; 699 } 700 int updatedScanMode = client.mScanModeApp; 701 if (!isAppForeground(client) || mScanNative.isForceDowngradedScanClient(client)) { 702 updatedScanMode = ScanSettings.SCAN_MODE_SCREEN_OFF; 703 } else { 704 // The following codes are effectively only for services 705 // Apps are either already or will be soon handled by handleImportanceChange(). 706 switch (client.mScanModeApp) { 707 case ScanSettings.SCAN_MODE_LOW_POWER: 708 updatedScanMode = ScanSettings.SCAN_MODE_SCREEN_OFF; 709 break; 710 case ScanSettings.SCAN_MODE_BALANCED: 711 case ScanSettings.SCAN_MODE_AMBIENT_DISCOVERY: 712 updatedScanMode = ScanSettings.SCAN_MODE_SCREEN_OFF_BALANCED; 713 break; 714 case ScanSettings.SCAN_MODE_LOW_LATENCY: 715 updatedScanMode = ScanSettings.SCAN_MODE_LOW_LATENCY; 716 break; 717 case ScanSettings.SCAN_MODE_OPPORTUNISTIC: 718 default: 719 return false; 720 } 721 } 722 Log.d( 723 TAG, 724 "Scan mode update during screen off from " 725 + getScanModeString(client.mScanModeApp) 726 + " to " 727 + getScanModeString(updatedScanMode)); 728 return client.updateScanMode(updatedScanMode); 729 } 730 731 /** 732 * Services and Apps are assumed to be in the foreground by default unless it changes to the 733 * background triggering onUidImportance(). 734 */ isAppForeground(ScanClient client)735 private boolean isAppForeground(ScanClient client) { 736 return mIsUidForegroundMap.get(client.mAppUid, DEFAULT_UID_IS_FOREGROUND); 737 } 738 updateScanModeBeforeStart(ScanClient client)739 private boolean updateScanModeBeforeStart(ScanClient client) { 740 if (upgradeScanModeBeforeStart(client)) { 741 return true; 742 } 743 if (mScreenOn) { 744 return updateScanModeScreenOn(client); 745 } else { 746 return updateScanModeScreenOff(client); 747 } 748 } 749 updateScanModeConcurrency(ScanClient client)750 private boolean updateScanModeConcurrency(ScanClient client) { 751 if (mIsConnecting) { 752 return downgradeScanModeFromMaxDuty(client); 753 } 754 return false; 755 } 756 upgradeScanModeBeforeStart(ScanClient client)757 private boolean upgradeScanModeBeforeStart(ScanClient client) { 758 if (client.mStarted || mAdapterService.getScanUpgradeDurationMillis() == 0) { 759 return false; 760 } 761 if (client.mStats == null || client.mStats.hasRecentScan()) { 762 return false; 763 } 764 if (!isAppForeground(client) || isBatchClient(client)) { 765 return false; 766 } 767 768 if (upgradeScanModeByOneLevel(client)) { 769 Message msg = obtainMessage(MSG_REVERT_SCAN_MODE_UPGRADE); 770 msg.obj = client; 771 Log.d( 772 TAG, 773 "scanMode is upgraded to " 774 + getScanModeString(client.mSettings.getScanMode()) 775 + " for " 776 + client); 777 sendMessageDelayed(msg, mAdapterService.getScanUpgradeDurationMillis()); 778 return true; 779 } 780 return false; 781 } 782 upgradeScanModeByOneLevel(ScanClient client)783 private static boolean upgradeScanModeByOneLevel(ScanClient client) { 784 switch (client.mScanModeApp) { 785 case ScanSettings.SCAN_MODE_LOW_POWER: 786 return client.updateScanMode(ScanSettings.SCAN_MODE_BALANCED); 787 case ScanSettings.SCAN_MODE_BALANCED: 788 case ScanSettings.SCAN_MODE_AMBIENT_DISCOVERY: 789 return client.updateScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY); 790 case ScanSettings.SCAN_MODE_OPPORTUNISTIC: 791 case ScanSettings.SCAN_MODE_LOW_LATENCY: 792 default: 793 return false; 794 } 795 } 796 handleRevertScanModeUpgrade(ScanClient client)797 private void handleRevertScanModeUpgrade(ScanClient client) { 798 if (mPriorityMap.get(client.mSettings.getScanMode()) 799 <= mPriorityMap.get(client.mScanModeApp)) { 800 return; 801 } 802 if (client.updateScanMode(client.mScanModeApp)) { 803 Log.d( 804 TAG, 805 "scanMode upgrade is reverted to " 806 + getScanModeString(client.mScanModeApp) 807 + " for " 808 + client); 809 mScanNative.configureRegularScanParams(); 810 } 811 } 812 handleImportanceChange(UidImportance imp)813 private void handleImportanceChange(UidImportance imp) { 814 if (imp == null) { 815 return; 816 } 817 int uid = imp.uid; 818 int importance = imp.importance; 819 boolean updatedScanParams = false; 820 boolean isForeground = importance <= IMPORTANCE_FOREGROUND_SERVICE; 821 822 if (mIsUidForegroundMap.size() < MAX_IS_UID_FOREGROUND_MAP_SIZE) { 823 mIsUidForegroundMap.put(uid, isForeground); 824 } 825 826 for (ScanClient client : mRegularScanClients) { 827 if (client.mAppUid != uid || mScanNative.isOpportunisticScanClient(client)) { 828 continue; 829 } 830 if (client.mStats != null) { 831 client.mStats.setAppImportance(importance); 832 } 833 if (isForeground) { 834 int scanMode = client.mScanModeApp; 835 int maxScanMode = 836 mScanNative.isForceDowngradedScanClient(client) 837 ? SCAN_MODE_FORCE_DOWNGRADED 838 : scanMode; 839 if (client.updateScanMode(getMinScanMode(scanMode, maxScanMode))) { 840 updatedScanParams = true; 841 } 842 } else { 843 int scanMode = client.mSettings.getScanMode(); 844 int maxScanMode = 845 mScreenOn 846 ? SCAN_MODE_APP_IN_BACKGROUND 847 : ScanSettings.SCAN_MODE_SCREEN_OFF; 848 if (client.updateScanMode(getMinScanMode(scanMode, maxScanMode))) { 849 updatedScanParams = true; 850 } 851 } 852 Log.d( 853 TAG, 854 ("uid " + uid) 855 + (" isForeground " + isForeground) 856 + (" scanMode " 857 + getScanModeString(client.mSettings.getScanMode()))); 858 } 859 860 if (updatedScanParams) { 861 mScanNative.configureRegularScanParams(); 862 } 863 } 864 updateScanModeScreenOn(ScanClient client)865 private boolean updateScanModeScreenOn(ScanClient client) { 866 if (mScanNative.isOpportunisticScanClient(client)) { 867 return false; 868 } 869 int scanMode = 870 isAppForeground(client) ? client.mScanModeApp : SCAN_MODE_APP_IN_BACKGROUND; 871 int maxScanMode = 872 mScanNative.isForceDowngradedScanClient(client) 873 ? SCAN_MODE_FORCE_DOWNGRADED 874 : scanMode; 875 Log.d( 876 TAG, 877 "Scan mode update during screen on from " 878 + getScanModeString(client.mScanModeApp) 879 + " to " 880 + getScanModeString(getMinScanMode(scanMode, maxScanMode))); 881 return client.updateScanMode(getMinScanMode(scanMode, maxScanMode)); 882 } 883 downgradeScanModeFromMaxDuty(ScanClient client)884 private boolean downgradeScanModeFromMaxDuty(ScanClient client) { 885 if ((client.mStats == null) || mAdapterService.getScanDowngradeDurationMillis() == 0) { 886 return false; 887 } 888 int updatedScanMode = 889 getMinScanMode(client.mSettings.getScanMode(), SCAN_MODE_MAX_IN_CONCURRENCY); 890 if (client.updateScanMode(updatedScanMode)) { 891 client.mStats.setScanDowngrade(client.mScannerId, true); 892 Log.d( 893 TAG, 894 "downgradeScanModeFromMaxDuty() to " 895 + getScanModeString(updatedScanMode) 896 + " for " 897 + client); 898 return true; 899 } 900 return false; 901 } 902 revertDowngradeScanModeFromMaxDuty(ScanClient client)903 private boolean revertDowngradeScanModeFromMaxDuty(ScanClient client) { 904 if (!mScanNative.isDowngradedScanClient(client)) { 905 return false; 906 } 907 if (client.mStats != null) { 908 client.mStats.setScanDowngrade(client.mScannerId, false); 909 } 910 Log.d(TAG, "revertDowngradeScanModeFromMaxDuty() for " + client); 911 if (mScreenOn) { 912 return updateScanModeScreenOn(client); 913 } else { 914 return updateScanModeScreenOff(client); 915 } 916 } 917 handleScreenOn()918 private void handleScreenOn() { 919 AppScanStats.setScreenState(true, mTimeProvider); 920 if (mScreenOn) { 921 return; 922 } 923 mScreenOn = true; 924 Log.d(TAG, "handleScreenOn()"); 925 mBatchScanThrottler.onScreenOn(true); 926 updateBatchScanToRegularScanClients(); 927 handleResumeScans(); 928 updateRegularScanClientsScreenOn(); 929 } 930 handleResumeScans()931 private void handleResumeScans() { 932 Iterator<ScanClient> iterator = mSuspendedScanClients.iterator(); 933 while (iterator.hasNext()) { 934 ScanClient client = iterator.next(); 935 if ((!requiresScreenOn(client) || mScreenOn) 936 && (!requiresLocationOn(client) || mLocationManager.isLocationEnabled())) { 937 if (client.mStats != null) { 938 client.mStats.recordScanResume(client.mScannerId); 939 } 940 Log.d(TAG, "resume scan " + client); 941 handleStartScan(client); 942 iterator.remove(); 943 } 944 } 945 } 946 updateRegularScanClientsScreenOn()947 private void updateRegularScanClientsScreenOn() { 948 boolean updatedScanParams = false; 949 for (ScanClient client : mRegularScanClients) { 950 if (updateScanModeScreenOn(client)) { 951 updatedScanParams = true; 952 } 953 } 954 if (updatedScanParams) { 955 mScanNative.configureRegularScanParams(); 956 } 957 } 958 handleProfileConnectionStateChanged(int profile, int fromState, int toState)959 private void handleProfileConnectionStateChanged(int profile, int fromState, int toState) { 960 boolean updatedConnectingState = 961 updateCountersAndCheckForConnectingState(toState, fromState); 962 Log.d( 963 TAG, 964 "PROFILE_CONNECTION_STATE_CHANGE:" 965 + (" profile=" + BluetoothProfile.getProfileName(profile)) 966 + (" prevState=" + fromState) 967 + (" state=" + toState) 968 + (" updatedConnectingState = " + updatedConnectingState)); 969 if (updatedConnectingState) { 970 if (!mIsConnecting) { 971 handleConnectingState(); 972 } 973 } else { 974 if (mIsConnecting) { 975 handleClearConnectingState(); 976 } 977 } 978 } 979 } 980 981 /** Parameters for batch scans. */ 982 static class BatchScanParams { 983 @VisibleForTesting int mScanMode; 984 private int mFullScanScannerId; 985 private int mTruncatedScanScannerId; 986 BatchScanParams()987 BatchScanParams() { 988 mScanMode = -1; 989 mFullScanScannerId = -1; 990 mTruncatedScanScannerId = -1; 991 } 992 993 @Override equals(Object obj)994 public boolean equals(Object obj) { 995 if (this == obj) { 996 return true; 997 } 998 if (!(obj instanceof BatchScanParams other)) { 999 return false; 1000 } 1001 return mScanMode == other.mScanMode 1002 && mFullScanScannerId == other.mFullScanScannerId 1003 && mTruncatedScanScannerId == other.mTruncatedScanScannerId; 1004 } 1005 1006 @Override hashCode()1007 public int hashCode() { 1008 return Objects.hash(mScanMode, mFullScanScannerId, mTruncatedScanScannerId); 1009 } 1010 } 1011 1012 @VisibleForTesting 1013 class ScanNative { 1014 1015 // Delivery mode defined in bt stack. 1016 private static final int DELIVERY_MODE_IMMEDIATE = 0; 1017 private static final int DELIVERY_MODE_ON_FOUND_LOST = 1; 1018 private static final int DELIVERY_MODE_BATCH = 2; 1019 1020 private static final int ONFOUND_SIGHTINGS_AGGRESSIVE = 1; 1021 private static final int ONFOUND_SIGHTINGS_STICKY = 4; 1022 1023 private static final int ALL_PASS_FILTER_INDEX_REGULAR_SCAN = 1; 1024 private static final int ALL_PASS_FILTER_INDEX_BATCH_SCAN = 2; 1025 private static final int ALL_PASS_FILTER_SELECTION = 0; 1026 1027 private static final int DISCARD_OLDEST_WHEN_BUFFER_FULL = 0; 1028 1029 /** Onfound/onlost for scan settings */ 1030 private static final int MATCH_MODE_AGGRESSIVE_TIMEOUT_FACTOR = (1); 1031 1032 private static final int MATCH_MODE_STICKY_TIMEOUT_FACTOR = (3); 1033 private static final int ONLOST_FACTOR = 2; 1034 private static final int ONLOST_ONFOUND_BASE_TIMEOUT_MS = 500; 1035 1036 // The logic is AND for each filter field. 1037 private static final int LIST_LOGIC_TYPE = 0x1111111; 1038 private static final int FILTER_LOGIC_TYPE = 1; 1039 1040 // MSFT-based hardware scan offload sysprop 1041 private static final String MSFT_HCI_EXT_ENABLED = "bluetooth.core.le.use_msft_hci_ext"; 1042 // Hardcoded min number of hardware adv monitor slots for MSFT-enabled controllers 1043 private static final int MIN_NUM_MSFT_MONITOR_SLOTS = 20; 1044 1045 // Filter indices that are available to user. It's sad we need to maintain filter index. 1046 private final Deque<Integer> mFilterIndexStack; 1047 // Map of scannerId and Filter indices used by client. 1048 private final Map<Integer, Deque<Integer>> mClientFilterIndexMap; 1049 // Keep track of the clients that uses ALL_PASS filters. 1050 private final Set<Integer> mAllPassRegularClients = new HashSet<>(); 1051 private final Set<Integer> mAllPassBatchClients = new HashSet<>(); 1052 1053 private final AtomicReference<BroadcastReceiver> mBatchAlarmReceiver = 1054 new AtomicReference<>(); 1055 1056 private final AlarmManager mAlarmManager; 1057 private final PendingIntent mBatchScanIntervalIntent; 1058 private final ScanNativeInterface mNativeInterface; 1059 1060 // Whether or not MSFT-based scanning hardware offload is available on this device 1061 private final boolean mIsMsftSupported; 1062 // Whether or not MSFT-based scanning is currently enabled in the controller 1063 private boolean scanEnabledMsft = false; 1064 // List of merged MSFT patterns 1065 private final MsftAdvMonitorMergedPatternList mMsftAdvMonitorMergedPatternList = 1066 new MsftAdvMonitorMergedPatternList(); 1067 ScanNative(ScanController scanController)1068 private ScanNative(ScanController scanController) { 1069 mNativeInterface = ScanObjectsFactory.getInstance().getScanNativeInterface(); 1070 mNativeInterface.init(scanController); 1071 mFilterIndexStack = new ArrayDeque<Integer>(); 1072 mClientFilterIndexMap = new HashMap<Integer, Deque<Integer>>(); 1073 1074 mAlarmManager = mAdapterService.getSystemService(AlarmManager.class); 1075 Intent batchIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null); 1076 mBatchScanIntervalIntent = 1077 PendingIntent.getBroadcast( 1078 mAdapterService, 0, batchIntent, PendingIntent.FLAG_IMMUTABLE); 1079 IntentFilter filter = new IntentFilter(); 1080 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 1081 filter.addAction(ACTION_REFRESH_BATCHED_SCAN); 1082 mBatchAlarmReceiver.set( 1083 new BroadcastReceiver() { 1084 @Override 1085 public void onReceive(Context context, Intent intent) { 1086 Log.d(TAG, "awakened up at time " + mTimeProvider.elapsedRealtime()); 1087 String action = intent.getAction(); 1088 1089 if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) { 1090 if (mBatchClients.isEmpty()) { 1091 return; 1092 } 1093 // Note this actually flushes all pending batch data. 1094 if (mBatchClients.iterator().hasNext()) { 1095 flushBatchScanResults(mBatchClients.iterator().next()); 1096 } 1097 } 1098 } 1099 }); 1100 mAdapterService.registerReceiver(mBatchAlarmReceiver.get(), filter); 1101 1102 mIsMsftSupported = 1103 Flags.leScanMsftSupport() 1104 && SystemProperties.getBoolean(MSFT_HCI_EXT_ENABLED, false) 1105 && mNativeInterface.gattClientIsMsftSupported(); 1106 } 1107 callbackDone(int scannerId, int status)1108 private void callbackDone(int scannerId, int status) { 1109 Log.d(TAG, "callback done for scannerId - " + scannerId + " status - " + status); 1110 if (status == 0) { 1111 mNativeInterface.callbackDone(); 1112 } 1113 // TODO: add a callback for scan failure. 1114 } 1115 resetCountDownLatch()1116 private void resetCountDownLatch() { 1117 mNativeInterface.resetCountDownLatch(); 1118 } 1119 waitForCallback()1120 private boolean waitForCallback() { 1121 return mNativeInterface.waitForCallback(OPERATION_TIME_OUT_MILLIS); 1122 } 1123 configureRegularScanParams()1124 void configureRegularScanParams() { 1125 Log.d(TAG, "configureRegularScanParams() - queue=" + mRegularScanClients.size()); 1126 int newScanSetting1m = Integer.MIN_VALUE; 1127 int newScanSettingCoded = Integer.MIN_VALUE; 1128 ScanClient client1m = getAggressiveClient(mRegularScanClients, true, false); 1129 ScanClient clientCoded = getAggressiveClient(mRegularScanClients, false, false); 1130 if (client1m != null) { 1131 newScanSetting1m = client1m.mSettings.getScanMode(); 1132 } 1133 if (clientCoded != null) { 1134 newScanSettingCoded = clientCoded.mSettings.getScanMode(); 1135 } 1136 1137 int curPhyMask = 1138 getScanPhyMask( 1139 mLastConfiguredScanSetting1m != Integer.MIN_VALUE, 1140 mLastConfiguredScanSettingCoded != Integer.MIN_VALUE); 1141 int scanPhyMask = getScanPhyMask(client1m != null, clientCoded != null); 1142 1143 // Only update scan parameters if at least one of the following is true: 1144 // 1. The 1M PHY mode has changed and is a valid value 1145 // 2. The coded PHY mode has changed and is a valid value 1146 // 3. The PHYs to scan on have changed and the new setting is valid (not 0) 1147 if (shouldUpdateScan(newScanSetting1m, mLastConfiguredScanSetting1m) 1148 || shouldUpdateScan(newScanSettingCoded, mLastConfiguredScanSettingCoded) 1149 || (scanPhyMask != 0 && curPhyMask != scanPhyMask)) { 1150 int scanWindow1m = getScanWindow(client1m); 1151 int scanInterval1m = getScanInterval(client1m); 1152 int scanWindowCoded = getScanWindow(clientCoded); 1153 int scanIntervalCoded = getScanInterval(clientCoded); 1154 mNativeInterface.gattClientScan(false); 1155 if (!AppScanStats.recordScanRadioStop(mTimeProvider)) { 1156 Log.w(TAG, "There is no scan radio to stop"); 1157 } 1158 Log.d( 1159 TAG, 1160 "Start gattClientScanNative with" 1161 + " old 1M scanMode " 1162 + mLastConfiguredScanSetting1m 1163 + " new 1M scanMode " 1164 + newScanSetting1m 1165 + " ( in scan unit: " 1166 + scanInterval1m 1167 + " / " 1168 + scanWindow1m 1169 + ", " 1170 + " old coded scanMode " 1171 + mLastConfiguredScanSettingCoded 1172 + " new coded scanMode " 1173 + newScanSettingCoded 1174 + " ( in scan unit: " 1175 + scanIntervalCoded 1176 + " / " 1177 + scanWindowCoded 1178 + ", " 1179 + "scanPhyMask: " 1180 + scanPhyMask 1181 + " ) " 1182 + client1m 1183 + " / " 1184 + clientCoded); 1185 mNativeInterface.gattSetScanParameters( 1186 client1m == null ? 0 : client1m.mScannerId, 1187 scanInterval1m, 1188 scanWindow1m, 1189 clientCoded == null ? 0 : clientCoded.mScannerId, 1190 scanIntervalCoded, 1191 scanWindowCoded, 1192 scanPhyMask); 1193 mNativeInterface.gattClientScan(true); 1194 recordScanRadioStart(client1m, clientCoded, newScanSetting1m, newScanSettingCoded); 1195 } else { 1196 Log.d(TAG, "configureRegularScanParams() - queue empty, scan stopped"); 1197 } 1198 mLastConfiguredScanSetting1m = newScanSetting1m; 1199 mLastConfiguredScanSettingCoded = newScanSettingCoded; 1200 } 1201 getAggressiveClient( Set<ScanClient> cList, boolean use1mPhy, boolean isBatch)1202 private ScanClient getAggressiveClient( 1203 Set<ScanClient> cList, boolean use1mPhy, boolean isBatch) { 1204 ScanClient result = null; 1205 int currentScanModePriority = Integer.MIN_VALUE; 1206 for (ScanClient client : cList) { 1207 // Batch is only done on the 1M PHY and the client PHY setting is ignored 1208 if (!isBatch && !isPhyConfigured(client, use1mPhy)) { 1209 continue; 1210 } 1211 int priority = mPriorityMap.get(client.mSettings.getScanMode()); 1212 if (priority > currentScanModePriority) { 1213 result = client; 1214 currentScanModePriority = priority; 1215 } 1216 } 1217 return result; 1218 } 1219 isPhyConfigured(ScanClient client, boolean use1mPhy)1220 private static boolean isPhyConfigured(ScanClient client, boolean use1mPhy) { 1221 if (!Flags.phyToNative()) { 1222 // When the flag is off the PHY setting is ignored and all clients scan on 1m 1223 return use1mPhy; 1224 } 1225 if (client.mSettings.getPhy() == ScanSettings.PHY_LE_ALL_SUPPORTED) { 1226 return true; 1227 } 1228 return use1mPhy 1229 ? client.mSettings.getPhy() == BluetoothDevice.PHY_LE_1M 1230 : client.mSettings.getPhy() == BluetoothDevice.PHY_LE_CODED; 1231 } 1232 shouldUpdateScan(int newScanSetting, int oldScanSetting)1233 private static boolean shouldUpdateScan(int newScanSetting, int oldScanSetting) { 1234 return newScanSetting != Integer.MIN_VALUE 1235 && newScanSetting != ScanSettings.SCAN_MODE_OPPORTUNISTIC 1236 && newScanSetting != oldScanSetting; 1237 } 1238 getScanWindow(@ullable ScanClient client)1239 private int getScanWindow(@Nullable ScanClient client) { 1240 return client == null ? 0 : Utils.millsToUnit(getScanWindowMillis(client.mSettings)); 1241 } 1242 getScanInterval(@ullable ScanClient client)1243 private int getScanInterval(@Nullable ScanClient client) { 1244 // convert scanWindow and scanInterval from ms to LE scan units(0.625ms) 1245 return client == null ? 0 : Utils.millsToUnit(getScanIntervalMillis(client.mSettings)); 1246 } 1247 recordScanRadioStart( @ullable ScanClient client1m, @Nullable ScanClient clientCoded, int setting1m, int settingCoded)1248 private void recordScanRadioStart( 1249 @Nullable ScanClient client1m, 1250 @Nullable ScanClient clientCoded, 1251 int setting1m, 1252 int settingCoded) { 1253 ScanClient chosenClient; 1254 if (client1m == null) { 1255 chosenClient = clientCoded; 1256 } else if (clientCoded == null) { 1257 chosenClient = client1m; 1258 } else { 1259 chosenClient = 1260 mPriorityMap.get(setting1m) >= mPriorityMap.get(settingCoded) 1261 ? client1m 1262 : clientCoded; 1263 } 1264 if (chosenClient != null 1265 && chosenClient.mStats != null 1266 && !AppScanStats.recordScanRadioStart( 1267 chosenClient.mScanModeApp, 1268 chosenClient.mScannerId, 1269 chosenClient.mStats, 1270 getScanWindowMillis(chosenClient.mSettings), 1271 getScanIntervalMillis(chosenClient.mSettings), 1272 mTimeProvider)) { 1273 Log.w(TAG, "Scan radio already started"); 1274 } 1275 } 1276 startRegularScan(ScanClient client)1277 void startRegularScan(ScanClient client) { 1278 if ((isFilteringSupported() || mIsMsftSupported) 1279 && mFilterIndexStack.isEmpty() 1280 && mClientFilterIndexMap.isEmpty()) { 1281 initFilterIndexStack(); 1282 } 1283 if (isFilteringSupported()) { 1284 configureScanFilters(client); 1285 } else if (mIsMsftSupported) { 1286 addFiltersMsft(client); 1287 } 1288 1289 // Start scan native only for the first client. 1290 if (numRegularScanClients() == 1 1291 && client.mSettings != null 1292 && client.mSettings.getScanMode() != ScanSettings.SCAN_MODE_OPPORTUNISTIC) { 1293 Log.d(TAG, "start gattClientScanNative from startRegularScan()"); 1294 mNativeInterface.gattClientScan(true); 1295 } 1296 } 1297 numRegularScanClients()1298 private int numRegularScanClients() { 1299 int num = 0; 1300 for (ScanClient client : mRegularScanClients) { 1301 if (client.mSettings.getScanMode() != ScanSettings.SCAN_MODE_OPPORTUNISTIC) { 1302 num++; 1303 } 1304 } 1305 return num; 1306 } 1307 startBatchScan(ScanClient client)1308 void startBatchScan(ScanClient client) { 1309 if (mFilterIndexStack.isEmpty() && isFilteringSupported()) { 1310 initFilterIndexStack(); 1311 } 1312 configureScanFilters(client); 1313 if (!isOpportunisticScanClient(client)) { 1314 // Reset batch scan. May need to stop the existing batch scan and update scan 1315 // params. 1316 resetBatchScan(client); 1317 } 1318 } 1319 isExemptFromScanTimeout(ScanClient client)1320 private static boolean isExemptFromScanTimeout(ScanClient client) { 1321 return isOpportunisticScanClient(client) || isFirstMatchScanClient(client); 1322 } 1323 isExemptFromAutoBatchScanUpdate(ScanClient client)1324 private static boolean isExemptFromAutoBatchScanUpdate(ScanClient client) { 1325 return isOpportunisticScanClient(client) || !isAllMatchesAutoBatchScanClient(client); 1326 } 1327 isAutoBatchScanClientEnabled(ScanClient client)1328 private static boolean isAutoBatchScanClientEnabled(ScanClient client) { 1329 return client.mStats != null && client.mStats.isAutoBatchScan(client.mScannerId); 1330 } 1331 isAllMatchesAutoBatchScanClient(ScanClient client)1332 private static boolean isAllMatchesAutoBatchScanClient(ScanClient client) { 1333 return client.mSettings.getCallbackType() 1334 == ScanSettings.CALLBACK_TYPE_ALL_MATCHES_AUTO_BATCH; 1335 } 1336 isOpportunisticScanClient(ScanClient client)1337 private static boolean isOpportunisticScanClient(ScanClient client) { 1338 return client.mSettings.getScanMode() == ScanSettings.SCAN_MODE_OPPORTUNISTIC; 1339 } 1340 isTimeoutScanClient(ScanClient client)1341 private static boolean isTimeoutScanClient(ScanClient client) { 1342 return (client.mStats != null) && client.mStats.isScanTimeout(client.mScannerId); 1343 } 1344 isDowngradedScanClient(ScanClient client)1345 private static boolean isDowngradedScanClient(ScanClient client) { 1346 return (client.mStats != null) && client.mStats.isScanDowngraded(client.mScannerId); 1347 } 1348 isForceDowngradedScanClient(ScanClient client)1349 private static boolean isForceDowngradedScanClient(ScanClient client) { 1350 return isTimeoutScanClient(client) || isDowngradedScanClient(client); 1351 } 1352 isFirstMatchScanClient(ScanClient client)1353 private static boolean isFirstMatchScanClient(ScanClient client) { 1354 return (client.mSettings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) 1355 != 0; 1356 } 1357 resetBatchScan(ScanClient client)1358 private void resetBatchScan(ScanClient client) { 1359 int scannerId = client.mScannerId; 1360 BatchScanParams batchScanParams = getBatchScanParams(); 1361 // Stop batch if batch scan params changed and previous params is not null. 1362 if (mBatchScanParams != null && (!mBatchScanParams.equals(batchScanParams))) { 1363 Log.d(TAG, "stopping BLe Batch"); 1364 resetCountDownLatch(); 1365 mNativeInterface.gattClientStopBatchScan(scannerId); 1366 waitForCallback(); 1367 // Clear pending results as it's illegal to config storage if there are still 1368 // pending results. 1369 flushBatchResults(scannerId); 1370 } 1371 // Start batch if batchScanParams changed and current params is not null. 1372 if (batchScanParams != null && (!batchScanParams.equals(mBatchScanParams))) { 1373 int notifyThreshold = 95; 1374 Log.d(TAG, "Starting BLE batch scan"); 1375 int resultType = getResultType(batchScanParams); 1376 int fullScanPercent = getFullScanStoragePercent(resultType); 1377 resetCountDownLatch(); 1378 Log.d(TAG, "configuring batch scan storage, appIf " + client.mScannerId); 1379 mNativeInterface.gattClientConfigBatchScanStorage( 1380 client.mScannerId, fullScanPercent, 100 - fullScanPercent, notifyThreshold); 1381 waitForCallback(); 1382 resetCountDownLatch(); 1383 int scanInterval = 1384 Utils.millsToUnit(getBatchScanIntervalMillis(batchScanParams.mScanMode)); 1385 int scanWindow = 1386 Utils.millsToUnit(getBatchScanWindowMillis(batchScanParams.mScanMode)); 1387 mNativeInterface.gattClientStartBatchScan( 1388 scannerId, 1389 resultType, 1390 scanInterval, 1391 scanWindow, 1392 0, 1393 DISCARD_OLDEST_WHEN_BUFFER_FULL); 1394 waitForCallback(); 1395 } 1396 mBatchScanParams = batchScanParams; 1397 setBatchAlarm(); 1398 } 1399 getFullScanStoragePercent(int resultType)1400 private static int getFullScanStoragePercent(int resultType) { 1401 switch (resultType) { 1402 case SCAN_RESULT_TYPE_FULL: 1403 return 100; 1404 case SCAN_RESULT_TYPE_TRUNCATED: 1405 return 0; 1406 case SCAN_RESULT_TYPE_BOTH: 1407 return 50; 1408 default: 1409 return 50; 1410 } 1411 } 1412 getBatchScanParams()1413 private BatchScanParams getBatchScanParams() { 1414 if (mBatchClients.isEmpty()) { 1415 return null; 1416 } 1417 BatchScanParams params = new BatchScanParams(); 1418 ScanClient winner = getAggressiveClient(mBatchClients, true, true); 1419 if (winner != null) { 1420 params.mScanMode = winner.mSettings.getScanMode(); 1421 } 1422 // TODO: split full batch scan results and truncated batch scan results to different 1423 // collections. 1424 for (ScanClient client : mBatchClients) { 1425 if (client.mSettings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_FULL) { 1426 params.mFullScanScannerId = client.mScannerId; 1427 } else { 1428 params.mTruncatedScanScannerId = client.mScannerId; 1429 } 1430 } 1431 return params; 1432 } 1433 1434 // Batched scan doesn't require high duty cycle scan because scan result is reported 1435 // infrequently anyway. To avoid redefining parameter sets, map to the low duty cycle 1436 // parameter set as follows. getBatchScanWindowMillis(int scanMode)1437 private int getBatchScanWindowMillis(int scanMode) { 1438 ContentResolver resolver = mAdapterService.getContentResolver(); 1439 switch (scanMode) { 1440 case ScanSettings.SCAN_MODE_LOW_LATENCY: 1441 return Settings.Global.getInt( 1442 resolver, 1443 Settings.Global.BLE_SCAN_BALANCED_WINDOW_MS, 1444 SCAN_MODE_BALANCED_WINDOW_MS); 1445 case ScanSettings.SCAN_MODE_SCREEN_OFF: 1446 return mAdapterService.getScreenOffLowPowerWindowMillis(); 1447 default: 1448 return Settings.Global.getInt( 1449 resolver, 1450 Settings.Global.BLE_SCAN_LOW_POWER_WINDOW_MS, 1451 SCAN_MODE_LOW_POWER_WINDOW_MS); 1452 } 1453 } 1454 getBatchScanIntervalMillis(int scanMode)1455 private int getBatchScanIntervalMillis(int scanMode) { 1456 ContentResolver resolver = mAdapterService.getContentResolver(); 1457 switch (scanMode) { 1458 case ScanSettings.SCAN_MODE_LOW_LATENCY: 1459 return Settings.Global.getInt( 1460 resolver, 1461 Settings.Global.BLE_SCAN_BALANCED_INTERVAL_MS, 1462 SCAN_MODE_BALANCED_INTERVAL_MS); 1463 case ScanSettings.SCAN_MODE_SCREEN_OFF: 1464 return mAdapterService.getScreenOffLowPowerIntervalMillis(); 1465 default: 1466 return Settings.Global.getInt( 1467 resolver, 1468 Settings.Global.BLE_SCAN_LOW_POWER_INTERVAL_MS, 1469 SCAN_MODE_LOW_POWER_INTERVAL_MS); 1470 } 1471 } 1472 1473 // Set the batch alarm to be triggered within a short window after batch interval. This 1474 // allows system to optimize wake up time while still allows a degree of precise control. setBatchAlarm()1475 private void setBatchAlarm() { 1476 // Cancel any pending alarm just in case. 1477 mAlarmManager.cancel(mBatchScanIntervalIntent); 1478 if (mBatchClients.isEmpty()) { 1479 return; 1480 } 1481 long batchTriggerIntervalMillis = 1482 Flags.batchScanOptimization() 1483 ? mBatchScanThrottler.getBatchTriggerIntervalMillis(mBatchClients) 1484 : getBatchTriggerIntervalMillis(); 1485 // Allows the alarm to be triggered within 1486 // [batchTriggerIntervalMillis, 1.1 * batchTriggerIntervalMillis] 1487 long windowLengthMillis = batchTriggerIntervalMillis / 10; 1488 long windowStartMillis = mTimeProvider.elapsedRealtime() + batchTriggerIntervalMillis; 1489 mAlarmManager.setWindow( 1490 AlarmManager.ELAPSED_REALTIME_WAKEUP, 1491 windowStartMillis, 1492 windowLengthMillis, 1493 mBatchScanIntervalIntent); 1494 } 1495 stopRegularScan(ScanClient client)1496 void stopRegularScan(ScanClient client) { 1497 // Remove scan filters and recycle filter indices. 1498 if (client == null) { 1499 return; 1500 } 1501 int deliveryMode = getDeliveryMode(client); 1502 if (deliveryMode == DELIVERY_MODE_ON_FOUND_LOST) { 1503 // Decrement the count of trackable advertisements in use 1504 int entriesToFreePerFilter = getNumOfTrackingAdvertisements(client.mSettings); 1505 for (int i = 0; i < client.mFilters.size(); i++) { 1506 if (!manageAllocationOfTrackingAdvertisement(entriesToFreePerFilter, false)) { 1507 Log.e( 1508 TAG, 1509 "Error freeing for onfound/onlost filter resources " 1510 + entriesToFreePerFilter); 1511 try { 1512 mScanController.onScanManagerErrorCallback( 1513 client.mScannerId, ScanCallback.SCAN_FAILED_INTERNAL_ERROR); 1514 } catch (RemoteException e) { 1515 Log.e(TAG, "failed on onScanManagerCallback at freeing", e); 1516 } 1517 } 1518 } 1519 } 1520 mRegularScanClients.remove(client); 1521 if (numRegularScanClients() == 0) { 1522 Log.d(TAG, "stop gattClientScanNative"); 1523 mNativeInterface.gattClientScan(false); 1524 if (!AppScanStats.recordScanRadioStop(mTimeProvider)) { 1525 Log.w(TAG, "There is no scan radio to stop"); 1526 } 1527 } 1528 1529 if (!mIsMsftSupported) { 1530 removeScanFilters(client.mScannerId); 1531 } else { 1532 removeFiltersMsft(client); 1533 } 1534 } 1535 regularScanTimeout(ScanClient client)1536 void regularScanTimeout(ScanClient client) { 1537 if (!isExemptFromScanTimeout(client) 1538 && (client.mStats == null || client.mStats.isScanningTooLong())) { 1539 Log.d(TAG, "regularScanTimeout - client scan time was too long"); 1540 if (client.mFilters == null || client.mFilters.isEmpty()) { 1541 Log.w( 1542 TAG, 1543 "Moving unfiltered scan client to opportunistic scan (scannerId " 1544 + client.mScannerId 1545 + ")"); 1546 setOpportunisticScanClient(client); 1547 removeScanFilters(client.mScannerId); 1548 1549 } else { 1550 Log.w( 1551 TAG, 1552 "Moving filtered scan client to downgraded scan (scannerId " 1553 + client.mScannerId 1554 + ")"); 1555 int scanMode = client.mSettings.getScanMode(); 1556 int maxScanMode = SCAN_MODE_FORCE_DOWNGRADED; 1557 client.updateScanMode(getMinScanMode(scanMode, maxScanMode)); 1558 } 1559 if (client.mStats != null) { 1560 client.mStats.setScanTimeout(client.mScannerId); 1561 client.mStats.recordScanTimeoutCountMetrics( 1562 client.mScannerId, mAdapterService.getScanTimeoutMillis()); 1563 } 1564 } 1565 1566 // The scan should continue for background scans 1567 configureRegularScanParams(); 1568 if (numRegularScanClients() == 0) { 1569 Log.d(TAG, "stop gattClientScanNative"); 1570 mNativeInterface.gattClientScan(false); 1571 if (!AppScanStats.recordScanRadioStop(mTimeProvider)) { 1572 Log.w(TAG, "There is no scan radio to stop"); 1573 } 1574 } 1575 } 1576 setOpportunisticScanClient(ScanClient client)1577 void setOpportunisticScanClient(ScanClient client) { 1578 // TODO: Add constructor to ScanSettings.Builder 1579 // that can copy values from an existing ScanSettings object 1580 ScanSettings.Builder builder = new ScanSettings.Builder(); 1581 ScanSettings settings = client.mSettings; 1582 builder.setScanMode(ScanSettings.SCAN_MODE_OPPORTUNISTIC); 1583 builder.setCallbackType(settings.getCallbackType()); 1584 builder.setScanResultType(settings.getScanResultType()); 1585 builder.setReportDelay(settings.getReportDelayMillis()); 1586 builder.setNumOfMatches(settings.getNumOfMatches()); 1587 client.mSettings = builder.build(); 1588 } 1589 1590 // Find the regular scan client information. getRegularScanClient(int scannerId)1591 ScanClient getRegularScanClient(int scannerId) { 1592 for (ScanClient client : mRegularScanClients) { 1593 if (client.mScannerId == scannerId) { 1594 return client; 1595 } 1596 } 1597 return null; 1598 } 1599 getSuspendedScanClient(int scannerId)1600 ScanClient getSuspendedScanClient(int scannerId) { 1601 for (ScanClient client : mSuspendedScanClients) { 1602 if (client.mScannerId == scannerId) { 1603 return client; 1604 } 1605 } 1606 return null; 1607 } 1608 stopBatchScan(ScanClient client)1609 void stopBatchScan(ScanClient client) { 1610 mBatchClients.remove(client); 1611 removeScanFilters(client.mScannerId); 1612 if (!isOpportunisticScanClient(client)) { 1613 resetBatchScan(client); 1614 } 1615 } 1616 flushBatchResults(int scannerId)1617 void flushBatchResults(int scannerId) { 1618 Log.d(TAG, "flushBatchResults - scannerId = " + scannerId); 1619 if (mBatchScanParams.mFullScanScannerId != -1) { 1620 resetCountDownLatch(); 1621 mNativeInterface.gattClientReadScanReports( 1622 mBatchScanParams.mFullScanScannerId, SCAN_RESULT_TYPE_FULL); 1623 waitForCallback(); 1624 } 1625 if (mBatchScanParams.mTruncatedScanScannerId != -1) { 1626 resetCountDownLatch(); 1627 mNativeInterface.gattClientReadScanReports( 1628 mBatchScanParams.mTruncatedScanScannerId, SCAN_RESULT_TYPE_TRUNCATED); 1629 waitForCallback(); 1630 } 1631 setBatchAlarm(); 1632 } 1633 cleanup()1634 void cleanup() { 1635 mAlarmManager.cancel(mBatchScanIntervalIntent); 1636 // Protect against multiple calls of cleanup. 1637 BroadcastReceiver receiver = mBatchAlarmReceiver.getAndSet(null); 1638 if (receiver != null) { 1639 mAdapterService.unregisterReceiver(receiver); 1640 } 1641 mNativeInterface.cleanup(); 1642 } 1643 getBatchTriggerIntervalMillis()1644 private long getBatchTriggerIntervalMillis() { 1645 long intervalMillis = Long.MAX_VALUE; 1646 for (ScanClient client : mBatchClients) { 1647 if (client.mSettings != null && client.mSettings.getReportDelayMillis() > 0) { 1648 intervalMillis = 1649 Math.min(intervalMillis, client.mSettings.getReportDelayMillis()); 1650 } 1651 } 1652 return intervalMillis; 1653 } 1654 1655 // Add scan filters. The logic is: 1656 // If no offload filter can/needs to be set, set ALL_PASS filter. 1657 // Otherwise offload all filters to hardware and enable all filters. configureScanFilters(ScanClient client)1658 private void configureScanFilters(ScanClient client) { 1659 int scannerId = client.mScannerId; 1660 int deliveryMode = getDeliveryMode(client); 1661 int trackEntries = 0; 1662 1663 // Do not add any filters set by opportunistic scan clients 1664 if (isOpportunisticScanClient(client)) { 1665 return; 1666 } 1667 1668 if (!shouldAddAllPassFilterToController(client, deliveryMode)) { 1669 return; 1670 } 1671 1672 resetCountDownLatch(); 1673 mNativeInterface.gattClientScanFilterEnable(scannerId, true); 1674 waitForCallback(); 1675 1676 if (shouldUseAllPassFilter(client)) { 1677 int filterIndex = 1678 (deliveryMode == DELIVERY_MODE_BATCH) 1679 ? ALL_PASS_FILTER_INDEX_BATCH_SCAN 1680 : ALL_PASS_FILTER_INDEX_REGULAR_SCAN; 1681 resetCountDownLatch(); 1682 // Don't allow Onfound/onlost with all pass 1683 configureFilterParameter( 1684 scannerId, client, ALL_PASS_FILTER_SELECTION, filterIndex, 0); 1685 waitForCallback(); 1686 } else { 1687 Deque<Integer> clientFilterIndices = new ArrayDeque<Integer>(); 1688 for (ScanFilter filter : client.mFilters) { 1689 ScanFilterQueue queue = new ScanFilterQueue(); 1690 queue.addScanFilter(filter); 1691 int featureSelection = queue.getFeatureSelection(); 1692 int filterIndex = mFilterIndexStack.pop(); 1693 1694 resetCountDownLatch(); 1695 mNativeInterface.gattClientScanFilterAdd( 1696 scannerId, queue.toArray(), filterIndex); 1697 waitForCallback(); 1698 1699 resetCountDownLatch(); 1700 if (deliveryMode == DELIVERY_MODE_ON_FOUND_LOST) { 1701 trackEntries = getNumOfTrackingAdvertisements(client.mSettings); 1702 if (!manageAllocationOfTrackingAdvertisement(trackEntries, true)) { 1703 Log.e( 1704 TAG, 1705 "No hardware resources for onfound/onlost filter " 1706 + trackEntries); 1707 if (client.mStats != null) { 1708 client.mStats.recordTrackingHwFilterNotAvailableCountMetrics( 1709 client.mScannerId, 1710 mAdapterService.getTotalNumOfTrackableAdvertisements()); 1711 } 1712 try { 1713 mScanController.onScanManagerErrorCallback( 1714 scannerId, ScanCallback.SCAN_FAILED_INTERNAL_ERROR); 1715 } catch (RemoteException e) { 1716 Log.e(TAG, "failed on onScanManagerCallback", e); 1717 } 1718 } 1719 } 1720 configureFilterParameter( 1721 scannerId, client, featureSelection, filterIndex, trackEntries); 1722 waitForCallback(); 1723 clientFilterIndices.add(filterIndex); 1724 } 1725 mClientFilterIndexMap.put(scannerId, clientFilterIndices); 1726 } 1727 } 1728 1729 // Check whether the filter should be added to controller. 1730 // Note only on ALL_PASS filter should be added. shouldAddAllPassFilterToController(ScanClient client, int deliveryMode)1731 private boolean shouldAddAllPassFilterToController(ScanClient client, int deliveryMode) { 1732 // Not an ALL_PASS client, need to add filter. 1733 if (!shouldUseAllPassFilter(client)) { 1734 return true; 1735 } 1736 1737 if (deliveryMode == DELIVERY_MODE_BATCH) { 1738 mAllPassBatchClients.add(client.mScannerId); 1739 return mAllPassBatchClients.size() == 1; 1740 } else { 1741 mAllPassRegularClients.add(client.mScannerId); 1742 return mAllPassRegularClients.size() == 1; 1743 } 1744 } 1745 removeScanFilters(int scannerId)1746 private void removeScanFilters(int scannerId) { 1747 Deque<Integer> filterIndices = mClientFilterIndexMap.remove(scannerId); 1748 if (filterIndices != null) { 1749 mFilterIndexStack.addAll(filterIndices); 1750 for (Integer filterIndex : filterIndices) { 1751 resetCountDownLatch(); 1752 mNativeInterface.gattClientScanFilterParamDelete(scannerId, filterIndex); 1753 waitForCallback(); 1754 } 1755 } 1756 // Remove if ALL_PASS filters are used. 1757 removeFilterIfExists( 1758 mAllPassRegularClients, scannerId, ALL_PASS_FILTER_INDEX_REGULAR_SCAN); 1759 removeFilterIfExists(mAllPassBatchClients, scannerId, ALL_PASS_FILTER_INDEX_BATCH_SCAN); 1760 } 1761 removeFilterIfExists(Set<Integer> clients, int scannerId, int filterIndex)1762 private void removeFilterIfExists(Set<Integer> clients, int scannerId, int filterIndex) { 1763 if (!clients.contains(scannerId)) { 1764 return; 1765 } 1766 clients.remove(scannerId); 1767 // Remove ALL_PASS filter iff no app is using it. 1768 if (clients.isEmpty()) { 1769 resetCountDownLatch(); 1770 mNativeInterface.gattClientScanFilterParamDelete(scannerId, filterIndex); 1771 waitForCallback(); 1772 } 1773 } 1774 getBatchScanClient(int scannerId)1775 private ScanClient getBatchScanClient(int scannerId) { 1776 for (ScanClient client : mBatchClients) { 1777 if (client.mScannerId == scannerId) { 1778 return client; 1779 } 1780 } 1781 return null; 1782 } 1783 1784 /** Return batch scan result type value defined in bt stack. */ getResultType(BatchScanParams params)1785 private static int getResultType(BatchScanParams params) { 1786 if (params.mFullScanScannerId != -1 && params.mTruncatedScanScannerId != -1) { 1787 return SCAN_RESULT_TYPE_BOTH; 1788 } 1789 if (params.mTruncatedScanScannerId != -1) { 1790 return SCAN_RESULT_TYPE_TRUNCATED; 1791 } 1792 if (params.mFullScanScannerId != -1) { 1793 return SCAN_RESULT_TYPE_FULL; 1794 } 1795 return -1; 1796 } 1797 1798 // Check if ALL_PASS filter should be used for the client. shouldUseAllPassFilter(ScanClient client)1799 private boolean shouldUseAllPassFilter(ScanClient client) { 1800 if (client == null) { 1801 return true; 1802 } 1803 if (client.mFilters == null || client.mFilters.isEmpty()) { 1804 return true; 1805 } 1806 if (client.mFilters.size() > mFilterIndexStack.size()) { 1807 if (client.mStats != null) { 1808 client.mStats.recordHwFilterNotAvailableCountMetrics( 1809 client.mScannerId, 1810 mAdapterService.getNumOfOffloadedScanFilterSupported()); 1811 } 1812 return true; 1813 } 1814 return false; 1815 } 1816 initFilterIndexStack()1817 private void initFilterIndexStack() { 1818 int maxFiltersSupported = mAdapterService.getNumOfOffloadedScanFilterSupported(); 1819 if (!isFilteringSupported() && mIsMsftSupported) { 1820 // Hardcoded minimum number of hardware adv monitor slots, because this value 1821 // cannot be queried from the controller for MSFT enabled devices 1822 maxFiltersSupported = MIN_NUM_MSFT_MONITOR_SLOTS; 1823 } 1824 // Start from index 4 as: 1825 // index 0 is reserved for ALL_PASS filter in Settings app. 1826 // index 1 is reserved for ALL_PASS filter for regular scan apps. 1827 // index 2 is reserved for ALL_PASS filter for batch scan apps. 1828 // index 3 is reserved for BAP/CAP Announcements 1829 for (int i = 4; i < maxFiltersSupported; ++i) { 1830 mFilterIndexStack.add(i); 1831 } 1832 } 1833 1834 // Configure filter parameters. configureFilterParameter( int scannerId, ScanClient client, int featureSelection, int filterIndex, int numOfTrackingEntries)1835 private void configureFilterParameter( 1836 int scannerId, 1837 ScanClient client, 1838 int featureSelection, 1839 int filterIndex, 1840 int numOfTrackingEntries) { 1841 int deliveryMode = getDeliveryMode(client); 1842 int rssiThreshold = Byte.MIN_VALUE; 1843 ScanSettings settings = client.mSettings; 1844 int onFoundTimeout = getOnFoundOnLostTimeoutMillis(settings, true); 1845 int onFoundCount = getOnFoundOnLostSightings(settings); 1846 int onLostTimeout = 10000; 1847 Log.d( 1848 TAG, 1849 "configureFilterParameter " 1850 + onFoundTimeout 1851 + " " 1852 + onLostTimeout 1853 + " " 1854 + onFoundCount 1855 + " " 1856 + numOfTrackingEntries); 1857 FilterParams filtValue = 1858 new FilterParams( 1859 scannerId, 1860 filterIndex, 1861 featureSelection, 1862 LIST_LOGIC_TYPE, 1863 FILTER_LOGIC_TYPE, 1864 rssiThreshold, 1865 rssiThreshold, 1866 deliveryMode, 1867 onFoundTimeout, 1868 onLostTimeout, 1869 onFoundCount, 1870 numOfTrackingEntries); 1871 mNativeInterface.gattClientScanFilterParamAdd(filtValue); 1872 } 1873 1874 // Get delivery mode based on scan settings. getDeliveryMode(ScanClient client)1875 private static int getDeliveryMode(ScanClient client) { 1876 if (client == null) { 1877 return DELIVERY_MODE_IMMEDIATE; 1878 } 1879 ScanSettings settings = client.mSettings; 1880 if (settings == null) { 1881 return DELIVERY_MODE_IMMEDIATE; 1882 } 1883 if ((settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0 1884 || (settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0) { 1885 return DELIVERY_MODE_ON_FOUND_LOST; 1886 } 1887 if (isAllMatchesAutoBatchScanClient(client)) { 1888 return isAutoBatchScanClientEnabled(client) 1889 ? DELIVERY_MODE_BATCH 1890 : DELIVERY_MODE_IMMEDIATE; 1891 } 1892 return settings.getReportDelayMillis() == 0 1893 ? DELIVERY_MODE_IMMEDIATE 1894 : DELIVERY_MODE_BATCH; 1895 } 1896 getScanWindowMillis(ScanSettings settings)1897 private int getScanWindowMillis(ScanSettings settings) { 1898 ContentResolver resolver = mAdapterService.getContentResolver(); 1899 if (settings == null) { 1900 return Settings.Global.getInt( 1901 resolver, 1902 Settings.Global.BLE_SCAN_LOW_POWER_WINDOW_MS, 1903 SCAN_MODE_LOW_POWER_WINDOW_MS); 1904 } 1905 1906 switch (settings.getScanMode()) { 1907 case ScanSettings.SCAN_MODE_LOW_LATENCY: 1908 return Settings.Global.getInt( 1909 resolver, 1910 Settings.Global.BLE_SCAN_LOW_LATENCY_WINDOW_MS, 1911 SCAN_MODE_LOW_LATENCY_WINDOW_MS); 1912 case ScanSettings.SCAN_MODE_BALANCED: 1913 case ScanSettings.SCAN_MODE_AMBIENT_DISCOVERY: 1914 return Settings.Global.getInt( 1915 resolver, 1916 Settings.Global.BLE_SCAN_BALANCED_WINDOW_MS, 1917 SCAN_MODE_BALANCED_WINDOW_MS); 1918 case ScanSettings.SCAN_MODE_LOW_POWER: 1919 return Settings.Global.getInt( 1920 resolver, 1921 Settings.Global.BLE_SCAN_LOW_POWER_WINDOW_MS, 1922 SCAN_MODE_LOW_POWER_WINDOW_MS); 1923 case ScanSettings.SCAN_MODE_SCREEN_OFF: 1924 return mAdapterService.getScreenOffLowPowerWindowMillis(); 1925 case ScanSettings.SCAN_MODE_SCREEN_OFF_BALANCED: 1926 return mAdapterService.getScreenOffBalancedWindowMillis(); 1927 default: 1928 return Settings.Global.getInt( 1929 resolver, 1930 Settings.Global.BLE_SCAN_LOW_POWER_WINDOW_MS, 1931 SCAN_MODE_LOW_POWER_WINDOW_MS); 1932 } 1933 } 1934 getScanIntervalMillis(ScanSettings settings)1935 private int getScanIntervalMillis(ScanSettings settings) { 1936 ContentResolver resolver = mAdapterService.getContentResolver(); 1937 if (settings == null) { 1938 return Settings.Global.getInt( 1939 resolver, 1940 Settings.Global.BLE_SCAN_LOW_POWER_INTERVAL_MS, 1941 SCAN_MODE_LOW_POWER_INTERVAL_MS); 1942 } 1943 switch (settings.getScanMode()) { 1944 case ScanSettings.SCAN_MODE_LOW_LATENCY: 1945 return Settings.Global.getInt( 1946 resolver, 1947 Settings.Global.BLE_SCAN_LOW_LATENCY_INTERVAL_MS, 1948 SCAN_MODE_LOW_LATENCY_INTERVAL_MS); 1949 case ScanSettings.SCAN_MODE_BALANCED: 1950 case ScanSettings.SCAN_MODE_AMBIENT_DISCOVERY: 1951 return Settings.Global.getInt( 1952 resolver, 1953 Settings.Global.BLE_SCAN_BALANCED_INTERVAL_MS, 1954 SCAN_MODE_BALANCED_INTERVAL_MS); 1955 case ScanSettings.SCAN_MODE_LOW_POWER: 1956 return Settings.Global.getInt( 1957 resolver, 1958 Settings.Global.BLE_SCAN_LOW_POWER_INTERVAL_MS, 1959 SCAN_MODE_LOW_POWER_INTERVAL_MS); 1960 case ScanSettings.SCAN_MODE_SCREEN_OFF: 1961 return mAdapterService.getScreenOffLowPowerIntervalMillis(); 1962 case ScanSettings.SCAN_MODE_SCREEN_OFF_BALANCED: 1963 return mAdapterService.getScreenOffBalancedIntervalMillis(); 1964 default: 1965 return Settings.Global.getInt( 1966 resolver, 1967 Settings.Global.BLE_SCAN_LOW_POWER_INTERVAL_MS, 1968 SCAN_MODE_LOW_POWER_INTERVAL_MS); 1969 } 1970 } 1971 getScanPhyMask(boolean usePhy1m, boolean usePhyCoded)1972 private static int getScanPhyMask(boolean usePhy1m, boolean usePhyCoded) { 1973 int phy = 0; 1974 if (usePhy1m) { 1975 phy |= BluetoothDevice.PHY_LE_1M_MASK; 1976 } 1977 if (usePhyCoded) { 1978 phy |= BluetoothDevice.PHY_LE_CODED_MASK; 1979 } 1980 return phy; 1981 } 1982 getOnFoundOnLostTimeoutMillis(ScanSettings settings, boolean onFound)1983 private static int getOnFoundOnLostTimeoutMillis(ScanSettings settings, boolean onFound) { 1984 int factor; 1985 int timeout = ONLOST_ONFOUND_BASE_TIMEOUT_MS; 1986 1987 if (settings.getMatchMode() == ScanSettings.MATCH_MODE_AGGRESSIVE) { 1988 factor = MATCH_MODE_AGGRESSIVE_TIMEOUT_FACTOR; 1989 } else { 1990 factor = MATCH_MODE_STICKY_TIMEOUT_FACTOR; 1991 } 1992 if (!onFound) { 1993 factor = factor * ONLOST_FACTOR; 1994 } 1995 return (timeout * factor); 1996 } 1997 getOnFoundOnLostSightings(ScanSettings settings)1998 private static int getOnFoundOnLostSightings(ScanSettings settings) { 1999 if (settings == null) { 2000 return ONFOUND_SIGHTINGS_AGGRESSIVE; 2001 } 2002 if (settings.getMatchMode() == ScanSettings.MATCH_MODE_AGGRESSIVE) { 2003 return ONFOUND_SIGHTINGS_AGGRESSIVE; 2004 } else { 2005 return ONFOUND_SIGHTINGS_STICKY; 2006 } 2007 } 2008 2009 @VisibleForTesting getNumOfTrackingAdvertisements(ScanSettings settings)2010 int getNumOfTrackingAdvertisements(ScanSettings settings) { 2011 if (settings == null) { 2012 return 0; 2013 } 2014 int val = 0; 2015 int maxTotalTrackableAdvertisements = 2016 mAdapterService.getTotalNumOfTrackableAdvertisements(); 2017 // controller based onfound onlost resources are scarce commodity; the 2018 // assignment of filters to num of beacons to track is configurable based 2019 // on hw capabilities. Apps give an intent and allocation of onfound 2020 // resources or failure there of is done based on availability - FCFS model 2021 switch (settings.getNumOfMatches()) { 2022 case ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT: 2023 val = 1; 2024 break; 2025 case ScanSettings.MATCH_NUM_FEW_ADVERTISEMENT: 2026 val = 2; 2027 break; 2028 case ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT: 2029 val = maxTotalTrackableAdvertisements / 2; 2030 if (Flags.changeDefaultTrackableAdvNumber()) { 2031 val = maxTotalTrackableAdvertisements / 4; 2032 } 2033 break; 2034 default: 2035 val = 1; 2036 Log.d( 2037 TAG, 2038 "Invalid setting for getNumOfMatches() " + settings.getNumOfMatches()); 2039 } 2040 return val; 2041 } 2042 manageAllocationOfTrackingAdvertisement( int numOfTrackableAdvertisement, boolean allocate)2043 private boolean manageAllocationOfTrackingAdvertisement( 2044 int numOfTrackableAdvertisement, boolean allocate) { 2045 int maxTotalTrackableAdvertisements = 2046 mAdapterService.getTotalNumOfTrackableAdvertisements(); 2047 synchronized (mCurUsedTrackableAdvertisementsLock) { 2048 int availableEntries = 2049 maxTotalTrackableAdvertisements - mCurUsedTrackableAdvertisements; 2050 if (allocate) { 2051 if (availableEntries >= numOfTrackableAdvertisement) { 2052 mCurUsedTrackableAdvertisements += numOfTrackableAdvertisement; 2053 return true; 2054 } else { 2055 return false; 2056 } 2057 } else { 2058 if (numOfTrackableAdvertisement > mCurUsedTrackableAdvertisements) { 2059 return false; 2060 } else { 2061 mCurUsedTrackableAdvertisements -= numOfTrackableAdvertisement; 2062 return true; 2063 } 2064 } 2065 } 2066 } 2067 registerScanner(long appUuidLsb, long appUuidMsb)2068 private void registerScanner(long appUuidLsb, long appUuidMsb) { 2069 mNativeInterface.registerScanner(appUuidLsb, appUuidMsb); 2070 } 2071 unregisterScanner(int scannerId)2072 private void unregisterScanner(int scannerId) { 2073 mNativeInterface.unregisterScanner(scannerId); 2074 } 2075 addFiltersMsft(ScanClient client)2076 private void addFiltersMsft(ScanClient client) { 2077 // Do not add any filters set by opportunistic scan clients 2078 if (isOpportunisticScanClient(client)) { 2079 return; 2080 } 2081 2082 if (client == null 2083 || client.mFilters == null 2084 || client.mFilters.isEmpty() 2085 || client.mFilters.size() > mFilterIndexStack.size()) { 2086 // Use all-pass filter 2087 updateScanMsft(); 2088 return; 2089 } 2090 2091 Deque<Integer> clientFilterIndices = new ArrayDeque<>(); 2092 for (ScanFilter filter : client.mFilters) { 2093 MsftAdvMonitor monitor = new MsftAdvMonitor(filter); 2094 2095 if (monitor.getAddress().bd_addr != null) { 2096 int filterIndex = mFilterIndexStack.pop(); 2097 2098 resetCountDownLatch(); 2099 mNativeInterface.gattClientMsftAdvMonitorAdd( 2100 monitor.getMonitor(), 2101 monitor.getPatterns(), 2102 monitor.getAddress(), 2103 filterIndex); 2104 waitForCallback(); 2105 2106 clientFilterIndices.add(filterIndex); 2107 } 2108 2109 if (monitor.getPatterns().length == 0) { 2110 Log.d( 2111 TAG, 2112 "No MSFT pattern or address was translated from client filter: " 2113 + filter); 2114 continue; 2115 } 2116 2117 // Some chipsets don't support multiple monitors with the same pattern. Skip 2118 // creating a new monitor if the pattern has already been registered 2119 int filterIndex = mFilterIndexStack.pop(); 2120 int existingFilterIndex = 2121 mMsftAdvMonitorMergedPatternList.add(filterIndex, monitor.getPatterns()); 2122 if (filterIndex == existingFilterIndex) { 2123 resetCountDownLatch(); 2124 mNativeInterface.gattClientMsftAdvMonitorAdd( 2125 monitor.getMonitor(), 2126 monitor.getPatterns(), 2127 monitor.getAddress(), 2128 filterIndex); 2129 waitForCallback(); 2130 } else { 2131 mFilterIndexStack.add(filterIndex); 2132 } 2133 2134 clientFilterIndices.add(existingFilterIndex); 2135 } 2136 mClientFilterIndexMap.put(client.mScannerId, clientFilterIndices); 2137 2138 updateScanMsft(); 2139 } 2140 removeFiltersMsft(ScanClient client)2141 private void removeFiltersMsft(ScanClient client) { 2142 Deque<Integer> clientFilterIndices = mClientFilterIndexMap.remove(client.mScannerId); 2143 if (clientFilterIndices != null) { 2144 for (int filterIndex : clientFilterIndices) { 2145 if (mMsftAdvMonitorMergedPatternList.remove(filterIndex)) { 2146 resetCountDownLatch(); 2147 mNativeInterface.gattClientMsftAdvMonitorRemove(filterIndex); 2148 waitForCallback(); 2149 mFilterIndexStack.add(filterIndex); 2150 } 2151 } 2152 } 2153 2154 updateScanMsft(); 2155 } 2156 updateScanMsft()2157 private void updateScanMsft() { 2158 boolean shouldEnableScanMsft = 2159 !mRegularScanClients.stream() 2160 .anyMatch( 2161 c -> 2162 c.mSettings != null 2163 && c.mSettings.getScanMode() 2164 != ScanSettings.SCAN_MODE_OPPORTUNISTIC 2165 && !this.mClientFilterIndexMap.containsKey( 2166 c.mScannerId)); 2167 if (scanEnabledMsft != shouldEnableScanMsft) { 2168 resetCountDownLatch(); 2169 mNativeInterface.gattClientMsftAdvMonitorEnable(shouldEnableScanMsft); 2170 waitForCallback(); 2171 scanEnabledMsft = shouldEnableScanMsft; 2172 2173 // Restart scanning, since enabling/disabling may have changed 2174 // the filter policy 2175 Log.d(TAG, "Restarting MSFT scan"); 2176 mNativeInterface.gattClientScan(false); 2177 if (numRegularScanClients() > 0) { 2178 mNativeInterface.gattClientScan(true); 2179 } 2180 } 2181 } 2182 } 2183 2184 @VisibleForTesting getBatchScanParams()2185 BatchScanParams getBatchScanParams() { 2186 return mBatchScanParams; 2187 } 2188 isScreenOn()2189 private boolean isScreenOn() { 2190 Display[] displays = mDisplayManager.getDisplays(); 2191 2192 if (displays == null) { 2193 return false; 2194 } 2195 2196 for (Display display : displays) { 2197 if (display.getState() == Display.STATE_ON) { 2198 return true; 2199 } 2200 } 2201 2202 return false; 2203 } 2204 2205 private final DisplayManager.DisplayListener mDisplayListener = 2206 new DisplayManager.DisplayListener() { 2207 @Override 2208 public void onDisplayAdded(int displayId) {} 2209 2210 @Override 2211 public void onDisplayRemoved(int displayId) {} 2212 2213 @Override 2214 public void onDisplayChanged(int displayId) { 2215 if (isScreenOn()) { 2216 sendMessage(MSG_SCREEN_ON, null); 2217 } else { 2218 sendMessage(MSG_SCREEN_OFF, null); 2219 } 2220 } 2221 }; 2222 2223 private final ActivityManager.OnUidImportanceListener mUidImportanceListener = 2224 new ActivityManager.OnUidImportanceListener() { 2225 @Override 2226 public void onUidImportance(final int uid, final int importance) { 2227 if (mScanController.getScannerMap().getAppScanStatsByUid(uid) != null) { 2228 Message message = new Message(); 2229 message.what = MSG_IMPORTANCE_CHANGE; 2230 message.obj = new UidImportance(uid, importance); 2231 mHandler.sendMessage(message); 2232 } 2233 } 2234 }; 2235 2236 private final BroadcastReceiver mLocationReceiver = 2237 new BroadcastReceiver() { 2238 @Override 2239 public void onReceive(Context context, Intent intent) { 2240 String action = intent.getAction(); 2241 if (LocationManager.MODE_CHANGED_ACTION.equals(action)) { 2242 final boolean locationEnabled = mLocationManager.isLocationEnabled(); 2243 if (locationEnabled) { 2244 sendMessage(MSG_RESUME_SCANS, null); 2245 } else { 2246 sendMessage(MSG_SUSPEND_SCANS, null); 2247 } 2248 } 2249 } 2250 }; 2251 updateCountersAndCheckForConnectingState(int state, int prevState)2252 private boolean updateCountersAndCheckForConnectingState(int state, int prevState) { 2253 switch (prevState) { 2254 case STATE_CONNECTING: 2255 if (mProfilesConnecting > 0) { 2256 mProfilesConnecting--; 2257 } else { 2258 Log.e(TAG, "mProfilesConnecting " + mProfilesConnecting); 2259 throw new IllegalStateException( 2260 "Invalid state transition, " + prevState + " -> " + state); 2261 } 2262 break; 2263 case STATE_CONNECTED: 2264 if (mProfilesConnected > 0) { 2265 mProfilesConnected--; 2266 } else { 2267 Log.e(TAG, "mProfilesConnected " + mProfilesConnected); 2268 throw new IllegalStateException( 2269 "Invalid state transition, " + prevState + " -> " + state); 2270 } 2271 break; 2272 case STATE_DISCONNECTING: 2273 if (mProfilesDisconnecting > 0) { 2274 mProfilesDisconnecting--; 2275 } else { 2276 Log.e(TAG, "mProfilesDisconnecting " + mProfilesDisconnecting); 2277 throw new IllegalStateException( 2278 "Invalid state transition, " + prevState + " -> " + state); 2279 } 2280 break; 2281 } 2282 switch (state) { 2283 case STATE_CONNECTING: 2284 mProfilesConnecting++; 2285 break; 2286 case STATE_CONNECTED: 2287 mProfilesConnected++; 2288 break; 2289 case STATE_DISCONNECTING: 2290 mProfilesDisconnecting++; 2291 break; 2292 case STATE_DISCONNECTED: 2293 break; 2294 default: 2295 } 2296 Log.d( 2297 TAG, 2298 ("mProfilesConnecting " + mProfilesConnecting) 2299 + (", mProfilesConnected " + mProfilesConnected) 2300 + (", mProfilesDisconnecting " + mProfilesDisconnecting)); 2301 return (mProfilesConnecting > 0); 2302 } 2303 getMinScanMode(int oldScanMode, int newScanMode)2304 private int getMinScanMode(int oldScanMode, int newScanMode) { 2305 return mPriorityMap.get(oldScanMode) <= mPriorityMap.get(newScanMode) 2306 ? oldScanMode 2307 : newScanMode; 2308 } 2309 2310 /** 2311 * Handle bluetooth profile connection state changes (for A2DP, HFP, HFP Client, A2DP Sink and 2312 * LE Audio). 2313 */ handleBluetoothProfileConnectionStateChanged( int profile, int fromState, int toState)2314 public void handleBluetoothProfileConnectionStateChanged( 2315 int profile, int fromState, int toState) { 2316 mHandler.post( 2317 () -> mHandler.handleProfileConnectionStateChanged(profile, fromState, toState)); 2318 } 2319 } 2320