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