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