• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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