1 /*
2  * Copyright (C) 2017 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.gatt;
18 
19 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
20 
21 import android.annotation.RequiresPermission;
22 import android.annotation.SuppressLint;
23 import android.app.AppOpsManager;
24 import android.app.PendingIntent;
25 import android.app.Service;
26 import android.bluetooth.BluetoothAdapter;
27 import android.bluetooth.BluetoothDevice;
28 import android.bluetooth.BluetoothGatt;
29 import android.bluetooth.BluetoothGattCharacteristic;
30 import android.bluetooth.BluetoothGattDescriptor;
31 import android.bluetooth.BluetoothGattService;
32 import android.bluetooth.BluetoothProfile;
33 import android.bluetooth.IBluetoothGatt;
34 import android.bluetooth.IBluetoothGattCallback;
35 import android.bluetooth.IBluetoothGattServerCallback;
36 import android.bluetooth.le.AdvertiseData;
37 import android.bluetooth.le.AdvertisingSetParameters;
38 import android.bluetooth.le.BluetoothLeScanner;
39 import android.bluetooth.le.IAdvertisingSetCallback;
40 import android.bluetooth.le.IPeriodicAdvertisingCallback;
41 import android.bluetooth.le.IScannerCallback;
42 import android.bluetooth.le.PeriodicAdvertisingParameters;
43 import android.bluetooth.le.ResultStorageDescriptor;
44 import android.bluetooth.le.ScanCallback;
45 import android.bluetooth.le.ScanFilter;
46 import android.bluetooth.le.ScanRecord;
47 import android.bluetooth.le.ScanResult;
48 import android.bluetooth.le.ScanSettings;
49 import android.companion.ICompanionDeviceManager;
50 import android.content.AttributionSource;
51 import android.content.Context;
52 import android.content.Intent;
53 import android.net.MacAddress;
54 import android.os.Binder;
55 import android.os.Handler;
56 import android.os.IBinder;
57 import android.os.Message;
58 import android.os.ParcelUuid;
59 import android.os.RemoteException;
60 import android.os.ServiceManager;
61 import android.os.SystemClock;
62 import android.os.UserHandle;
63 import android.os.WorkSource;
64 import android.provider.DeviceConfig;
65 import android.provider.Settings;
66 import android.text.format.DateUtils;
67 import android.util.Log;
68 
69 import com.android.bluetooth.BluetoothMetricsProto;
70 import com.android.bluetooth.R;
71 import com.android.bluetooth.Utils;
72 import com.android.bluetooth.btservice.AbstractionLayer;
73 import com.android.bluetooth.btservice.AdapterService;
74 import com.android.bluetooth.btservice.ProfileService;
75 import com.android.bluetooth.util.NumberUtils;
76 import com.android.internal.annotations.VisibleForTesting;
77 import com.android.internal.util.HexDump;
78 
79 import java.util.ArrayDeque;
80 import java.util.ArrayList;
81 import java.util.Arrays;
82 import java.util.Collections;
83 import java.util.HashMap;
84 import java.util.HashSet;
85 import java.util.List;
86 import java.util.Map;
87 import java.util.Set;
88 import java.util.UUID;
89 import java.util.concurrent.TimeUnit;
90 import java.util.function.Predicate;
91 
92 /**
93  * Provides Bluetooth Gatt profile, as a service in
94  * the Bluetooth application.
95  * @hide
96  */
97 public class GattService extends ProfileService {
98     private static final boolean DBG = GattServiceConfig.DBG;
99     private static final boolean VDBG = GattServiceConfig.VDBG;
100     private static final String TAG = GattServiceConfig.TAG_PREFIX + "GattService";
101     private static final String UUID_SUFFIX = "-0000-1000-8000-00805f9b34fb";
102     private static final String UUID_ZERO_PAD = "00000000";
103 
104     static final int SCAN_FILTER_ENABLED = 1;
105     static final int SCAN_FILTER_MODIFIED = 2;
106 
107     private static final int MAC_ADDRESS_LENGTH = 6;
108     // Batch scan related constants.
109     private static final int TRUNCATED_RESULT_SIZE = 11;
110     private static final int TIME_STAMP_LENGTH = 2;
111 
112     private enum MatchOrigin {
113         PSEUDO_ADDRESS,
114         ORIGINAL_ADDRESS
115     }
116 
117     private static class MatchResult {
118         private final boolean matches;
119         private final MatchOrigin origin;
MatchResult(boolean matches, MatchOrigin origin)120         private MatchResult(boolean matches, MatchOrigin origin) {
121             this.matches = matches;
122             this.origin = origin;
123         }
124 
getMatches()125         public boolean getMatches() {
126             return matches;
127         }
128 
getMatchOrigin()129         public MatchOrigin getMatchOrigin() {
130             return origin;
131         }
132     }
133 
134     /**
135      * The default floor value for LE batch scan report delays greater than 0
136      */
137     private static final long DEFAULT_REPORT_DELAY_FLOOR = 5000;
138 
139     // onFoundLost related constants
140     private static final int ADVT_STATE_ONFOUND = 0;
141     private static final int ADVT_STATE_ONLOST = 1;
142 
143     private static final int ET_LEGACY_MASK = 0x10;
144 
145     private static final UUID HID_SERVICE_UUID =
146             UUID.fromString("00001812-0000-1000-8000-00805F9B34FB");
147 
148     private static final UUID[] HID_UUIDS = {
149             UUID.fromString("00002A4A-0000-1000-8000-00805F9B34FB"),
150             UUID.fromString("00002A4B-0000-1000-8000-00805F9B34FB"),
151             UUID.fromString("00002A4C-0000-1000-8000-00805F9B34FB"),
152             UUID.fromString("00002A4D-0000-1000-8000-00805F9B34FB")
153     };
154 
155     private static final UUID ANDROID_TV_REMOTE_SERVICE_UUID =
156             UUID.fromString("AB5E0001-5A21-4F05-BC7D-AF01F617B664");
157 
158     private static final UUID FIDO_SERVICE_UUID =
159             UUID.fromString("0000FFFD-0000-1000-8000-00805F9B34FB"); // U2F
160 
161     /**
162      * Example raw beacons captured from a Blue Charm BC011
163      */
164     private static final String[] TEST_MODE_BEACONS = new String[] {
165             "020106",
166             "0201060303AAFE1716AAFE10EE01626C7565636861726D626561636F6E730009168020691E0EFE13551109426C7565436861726D5F313639363835000000",
167             "0201060303AAFE1716AAFE00EE626C7565636861726D31000000000001000009168020691E0EFE13551109426C7565436861726D5F313639363835000000",
168             "0201060303AAFE1116AAFE20000BF017000008874803FB93540916802069080EFE13551109426C7565436861726D5F313639363835000000000000000000",
169             "0201061AFF4C000215426C7565436861726D426561636F6E730EFE1355C509168020691E0EFE13551109426C7565436861726D5F31363936383500000000",
170     };
171 
172     /**
173      * Keep the arguments passed in for the PendingIntent.
174      */
175     class PendingIntentInfo {
176         public PendingIntent intent;
177         public ScanSettings settings;
178         public List<ScanFilter> filters;
179         public String callingPackage;
180 
181         @Override
equals(Object other)182         public boolean equals(Object other) {
183             if (!(other instanceof PendingIntentInfo)) {
184                 return false;
185             }
186             return intent.equals(((PendingIntentInfo) other).intent);
187         }
188     }
189 
190     /**
191      * List of our registered scanners.
192      */
193     class ScannerMap extends ContextMap<IScannerCallback, PendingIntentInfo> {}
194 
195     ScannerMap mScannerMap = new ScannerMap();
196 
197     /**
198      * List of our registered clients.
199      */
200     class ClientMap extends ContextMap<IBluetoothGattCallback, Void> {}
201 
202     ClientMap mClientMap = new ClientMap();
203 
204     /**
205      * List of our registered server apps.
206      */
207     class ServerMap extends ContextMap<IBluetoothGattServerCallback, Void> {}
208 
209     ServerMap mServerMap = new ServerMap();
210 
211     /**
212      * Server handle map.
213      */
214     HandleMap mHandleMap = new HandleMap();
215     private List<UUID> mAdvertisingServiceUuids = new ArrayList<UUID>();
216 
217     private int mMaxScanFilters;
218 
219     private static final int NUM_SCAN_EVENTS_KEPT = 20;
220 
221     /**
222      * Internal list of scan events to use with the proto
223      */
224     private final ArrayDeque<BluetoothMetricsProto.ScanEvent> mScanEvents =
225             new ArrayDeque<>(NUM_SCAN_EVENTS_KEPT);
226 
227     /**
228      * Set of restricted (which require a BLUETOOTH_PRIVILEGED permission) handles per connectionId.
229      */
230     private final Map<Integer, Set<Integer>> mRestrictedHandles = new HashMap<>();
231 
232     private AdapterService mAdapterService;
233     private AdvertiseManager mAdvertiseManager;
234     private PeriodicScanManager mPeriodicScanManager;
235     private ScanManager mScanManager;
236     private AppOpsManager mAppOps;
237     private ICompanionDeviceManager mCompanionManager;
238     private String mExposureNotificationPackage;
239     private Handler mTestModeHandler;
240     private final Object mTestModeLock = new Object();
241 
242     /**
243      */
244     private final Predicate<ScanResult> mLocationDenylistPredicate = (scanResult) -> {
245         final MacAddress parsedAddress = MacAddress
246                 .fromString(scanResult.getDevice().getAddress());
247         if (mAdapterService.getLocationDenylistMac().test(parsedAddress.toByteArray())) {
248             Log.v(TAG, "Skipping device matching denylist: " + parsedAddress);
249             return true;
250         }
251         final ScanRecord scanRecord = scanResult.getScanRecord();
252         if (scanRecord.matchesAnyField(mAdapterService.getLocationDenylistAdvertisingData())) {
253             Log.v(TAG, "Skipping data matching denylist: " + scanRecord);
254             return true;
255         }
256         return false;
257     };
258 
259     private static GattService sGattService;
260 
261     /**
262      * Reliable write queue
263      */
264     private Set<String> mReliableQueue = new HashSet<String>();
265 
266     static {
classInitNative()267         classInitNative();
268     }
269 
270     @Override
initBinder()271     protected IProfileServiceBinder initBinder() {
272         return new BluetoothGattBinder(this);
273     }
274 
275     @Override
start()276     protected boolean start() {
277         if (DBG) {
278             Log.d(TAG, "start()");
279         }
280         mExposureNotificationPackage = getString(R.string.exposure_notification_package);
281         Settings.Global.putInt(
282                 getContentResolver(), "bluetooth_sanitized_exposure_notification_supported", 1);
283 
284         initializeNative();
285         mAdapterService = AdapterService.getAdapterService();
286         mCompanionManager = ICompanionDeviceManager.Stub.asInterface(
287                 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
288         mAppOps = getSystemService(AppOpsManager.class);
289         mAdvertiseManager = new AdvertiseManager(this, mAdapterService);
290         mAdvertiseManager.start();
291 
292         mScanManager = new ScanManager(this);
293         mScanManager.start();
294 
295         mPeriodicScanManager = new PeriodicScanManager(mAdapterService);
296         mPeriodicScanManager.start();
297 
298         setGattService(this);
299         return true;
300     }
301 
302     @Override
stop()303     protected boolean stop() {
304         if (DBG) {
305             Log.d(TAG, "stop()");
306         }
307         setGattService(null);
308         mScannerMap.clear();
309         mClientMap.clear();
310         mServerMap.clear();
311         mHandleMap.clear();
312         mReliableQueue.clear();
313         if (mAdvertiseManager != null) {
314             mAdvertiseManager.cleanup();
315         }
316         if (mScanManager != null) {
317             mScanManager.cleanup();
318         }
319         if (mPeriodicScanManager != null) {
320             mPeriodicScanManager.cleanup();
321         }
322         return true;
323     }
324 
325     @Override
cleanup()326     protected void cleanup() {
327         if (DBG) {
328             Log.d(TAG, "cleanup()");
329         }
330         cleanupNative();
331         if (mAdvertiseManager != null) {
332             mAdvertiseManager.cleanup();
333         }
334         if (mScanManager != null) {
335             mScanManager.cleanup();
336         }
337         if (mPeriodicScanManager != null) {
338             mPeriodicScanManager.cleanup();
339         }
340     }
341 
342     // While test mode is enabled, pretend as if the underlying stack
343     // discovered a specific set of well-known beacons every second
344     @Override
setTestModeEnabled(boolean enableTestMode)345     protected void setTestModeEnabled(boolean enableTestMode) {
346         synchronized (mTestModeLock) {
347             if (mTestModeHandler == null) {
348                 mTestModeHandler = new Handler(getMainLooper()) {
349                     public void handleMessage(Message msg) {
350                         synchronized (mTestModeLock) {
351                             if (!GattService.this.isTestModeEnabled()) {
352                                 return;
353                             }
354                             for (String test : TEST_MODE_BEACONS) {
355                                 onScanResultInternal(0x1b, 0x1, "DD:34:02:05:5C:4D", 1, 0, 0xff,
356                                         127, -54, 0x0, HexDump.hexStringToByteArray(test),
357                                         "DD:34:02:05:5C:4E");
358                             }
359                             sendEmptyMessageDelayed(0, DateUtils.SECOND_IN_MILLIS);
360                         }
361                     }
362                 };
363             }
364             if (enableTestMode && !isTestModeEnabled()) {
365                 super.setTestModeEnabled(true);
366                 mTestModeHandler.removeMessages(0);
367                 mTestModeHandler.sendEmptyMessageDelayed(0, DateUtils.SECOND_IN_MILLIS);
368             } else if (!enableTestMode && isTestModeEnabled()) {
369                 super.setTestModeEnabled(false);
370                 mTestModeHandler.removeMessages(0);
371                 mTestModeHandler.sendEmptyMessage(0);
372             }
373         }
374     }
375 
376     /**
377      * Get the current instance of {@link GattService}
378      *
379      * @return current instance of {@link GattService}
380      */
381     @VisibleForTesting
getGattService()382     public static synchronized GattService getGattService() {
383         if (sGattService == null) {
384             Log.w(TAG, "getGattService(): service is null");
385             return null;
386         }
387         if (!sGattService.isAvailable()) {
388             Log.w(TAG, "getGattService(): service is not available");
389             return null;
390         }
391         return sGattService;
392     }
393 
setGattService(GattService instance)394     private static synchronized void setGattService(GattService instance) {
395         if (DBG) {
396             Log.d(TAG, "setGattService(): set to: " + instance);
397         }
398         sGattService = instance;
399     }
400 
401     // Suppressed since we're not actually enforcing here
402     @SuppressLint("AndroidFrameworkRequiresPermission")
permissionCheck(UUID characteristicUuid)403     private boolean permissionCheck(UUID characteristicUuid) {
404         return !isHidCharUuid(characteristicUuid)
405                 || (checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED)
406                         == PERMISSION_GRANTED);
407     }
408 
409     // Suppressed since we're not actually enforcing here
410     @SuppressLint("AndroidFrameworkRequiresPermission")
permissionCheck(int connId, int handle)411     private boolean permissionCheck(int connId, int handle) {
412         Set<Integer> restrictedHandles = mRestrictedHandles.get(connId);
413         if (restrictedHandles == null || !restrictedHandles.contains(handle)) {
414             return true;
415         }
416 
417         return (checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED)
418                 == PERMISSION_GRANTED);
419     }
420 
421     // Suppressed since we're not actually enforcing here
422     @SuppressLint("AndroidFrameworkRequiresPermission")
permissionCheck(ClientMap.App app, int connId, int handle)423     private boolean permissionCheck(ClientMap.App app, int connId, int handle) {
424         Set<Integer> restrictedHandles = mRestrictedHandles.get(connId);
425         if (restrictedHandles == null || !restrictedHandles.contains(handle)) {
426             return true;
427         }
428 
429         if (!app.hasBluetoothPrivilegedPermission
430                 && checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED)== PERMISSION_GRANTED) {
431             app.hasBluetoothPrivilegedPermission = true;
432         }
433 
434         return app.hasBluetoothPrivilegedPermission;
435     }
436 
437     @Override
onStartCommand(Intent intent, int flags, int startId)438     public int onStartCommand(Intent intent, int flags, int startId) {
439         if (GattDebugUtils.handleDebugAction(this, intent)) {
440             return Service.START_NOT_STICKY;
441         }
442         return super.onStartCommand(intent, flags, startId);
443     }
444 
445     /**
446      * DeathReceipient handlers used to unregister applications that
447      * disconnect ungracefully (ie. crash or forced close).
448      */
449 
450     class ScannerDeathRecipient implements IBinder.DeathRecipient {
451         int mScannerId;
452 
ScannerDeathRecipient(int scannerId)453         ScannerDeathRecipient(int scannerId) {
454             mScannerId = scannerId;
455         }
456 
457         @Override
binderDied()458         public void binderDied() {
459             if (DBG) {
460                 Log.d(TAG, "Binder is dead - unregistering scanner (" + mScannerId + ")!");
461             }
462 
463             ScanClient client = getScanClient(mScannerId);
464             if (client != null) {
465                 client.appDied = true;
466                 stopScan(client.scannerId, getAttributionSource());
467             }
468         }
469 
getScanClient(int clientIf)470         private ScanClient getScanClient(int clientIf) {
471             for (ScanClient client : mScanManager.getRegularScanQueue()) {
472                 if (client.scannerId == clientIf) {
473                     return client;
474                 }
475             }
476             for (ScanClient client : mScanManager.getBatchScanQueue()) {
477                 if (client.scannerId == clientIf) {
478                     return client;
479                 }
480             }
481             return null;
482         }
483     }
484 
485     class ServerDeathRecipient implements IBinder.DeathRecipient {
486         int mAppIf;
487 
ServerDeathRecipient(int appIf)488         ServerDeathRecipient(int appIf) {
489             mAppIf = appIf;
490         }
491 
492         @Override
binderDied()493         public void binderDied() {
494             if (DBG) {
495                 Log.d(TAG, "Binder is dead - unregistering server (" + mAppIf + ")!");
496             }
497             unregisterServer(mAppIf, getAttributionSource());
498         }
499     }
500 
501     class ClientDeathRecipient implements IBinder.DeathRecipient {
502         int mAppIf;
503 
ClientDeathRecipient(int appIf)504         ClientDeathRecipient(int appIf) {
505             mAppIf = appIf;
506         }
507 
508         @Override
binderDied()509         public void binderDied() {
510             if (DBG) {
511                 Log.d(TAG, "Binder is dead - unregistering client (" + mAppIf + ")!");
512             }
513             unregisterClient(mAppIf, getAttributionSource());
514         }
515     }
516 
517     /**
518      * Handlers for incoming service calls
519      */
520     private static class BluetoothGattBinder extends IBluetoothGatt.Stub
521             implements IProfileServiceBinder {
522         private GattService mService;
523 
BluetoothGattBinder(GattService svc)524         BluetoothGattBinder(GattService svc) {
525             mService = svc;
526         }
527 
528         @Override
cleanup()529         public void cleanup() {
530             mService = null;
531         }
532 
getService()533         private GattService getService() {
534             if (mService != null && mService.isAvailable()) {
535                 return mService;
536             }
537             Log.e(TAG, "getService() - Service requested, but not available!");
538             return null;
539         }
540 
541         @Override
getDevicesMatchingConnectionStates( int[] states, AttributionSource attributionSource)542         public List<BluetoothDevice> getDevicesMatchingConnectionStates(
543                 int[] states, AttributionSource attributionSource) {
544             GattService service = getService();
545             if (service == null) {
546                 return new ArrayList<BluetoothDevice>();
547             }
548             return service.getDevicesMatchingConnectionStates(states, attributionSource);
549         }
550 
551         @Override
registerClient(ParcelUuid uuid, IBluetoothGattCallback callback, boolean eatt_support, AttributionSource attributionSource)552         public void registerClient(ParcelUuid uuid, IBluetoothGattCallback callback,
553                 boolean eatt_support, AttributionSource attributionSource) {
554             GattService service = getService();
555             if (service == null) {
556                 return;
557             }
558             service.registerClient(uuid.getUuid(), callback, eatt_support, attributionSource);
559         }
560 
561         @Override
unregisterClient(int clientIf, AttributionSource attributionSource)562         public void unregisterClient(int clientIf, AttributionSource attributionSource) {
563             GattService service = getService();
564             if (service == null) {
565                 return;
566             }
567             service.unregisterClient(clientIf, attributionSource);
568         }
569 
570         @Override
registerScanner(IScannerCallback callback, WorkSource workSource, AttributionSource attributionSource)571         public void registerScanner(IScannerCallback callback, WorkSource workSource,
572                 AttributionSource attributionSource) throws RemoteException {
573             GattService service = getService();
574             if (service == null) {
575                 return;
576             }
577             service.registerScanner(callback, workSource, attributionSource);
578         }
579 
580         @Override
unregisterScanner(int scannerId, AttributionSource attributionSource)581         public void unregisterScanner(int scannerId, AttributionSource attributionSource) {
582             GattService service = getService();
583             if (service == null) {
584                 return;
585             }
586             service.unregisterScanner(scannerId, attributionSource);
587         }
588 
589         @Override
startScan(int scannerId, ScanSettings settings, List<ScanFilter> filters, List storages, AttributionSource attributionSource)590         public void startScan(int scannerId, ScanSettings settings, List<ScanFilter> filters,
591                 List storages, AttributionSource attributionSource) {
592             GattService service = getService();
593             if (service == null) {
594                 return;
595             }
596             service.startScan(scannerId, settings, filters, storages, attributionSource);
597         }
598 
599         @Override
startScanForIntent(PendingIntent intent, ScanSettings settings, List<ScanFilter> filters, AttributionSource attributionSource)600         public void startScanForIntent(PendingIntent intent, ScanSettings settings,
601                 List<ScanFilter> filters, AttributionSource attributionSource)
602                 throws RemoteException {
603             GattService service = getService();
604             if (service == null) {
605                 return;
606             }
607             service.registerPiAndStartScan(intent, settings, filters, attributionSource);
608         }
609 
610         @Override
stopScanForIntent(PendingIntent intent, AttributionSource attributionSource)611         public void stopScanForIntent(PendingIntent intent, AttributionSource attributionSource)
612                 throws RemoteException {
613             GattService service = getService();
614             if (service == null) {
615                 return;
616             }
617             service.stopScan(intent, attributionSource);
618         }
619 
620         @Override
stopScan(int scannerId, AttributionSource attributionSource)621         public void stopScan(int scannerId, AttributionSource attributionSource) {
622             GattService service = getService();
623             if (service == null) {
624                 return;
625             }
626             service.stopScan(scannerId, attributionSource);
627         }
628 
629         @Override
flushPendingBatchResults(int scannerId, AttributionSource attributionSource)630         public void flushPendingBatchResults(int scannerId, AttributionSource attributionSource) {
631             GattService service = getService();
632             if (service == null) {
633                 return;
634             }
635             service.flushPendingBatchResults(scannerId, attributionSource);
636         }
637 
638         @Override
clientConnect(int clientIf, String address, boolean isDirect, int transport, boolean opportunistic, int phy, AttributionSource attributionSource)639         public void clientConnect(int clientIf, String address, boolean isDirect, int transport,
640                 boolean opportunistic, int phy, AttributionSource attributionSource) {
641             GattService service = getService();
642             if (service == null) {
643                 return;
644             }
645             service.clientConnect(clientIf, address, isDirect, transport, opportunistic, phy,
646                     attributionSource);
647         }
648 
649         @Override
clientDisconnect( int clientIf, String address, AttributionSource attributionSource)650         public void clientDisconnect(
651                 int clientIf, String address, AttributionSource attributionSource) {
652             GattService service = getService();
653             if (service == null) {
654                 return;
655             }
656             service.clientDisconnect(clientIf, address, attributionSource);
657         }
658 
659         @Override
clientSetPreferredPhy(int clientIf, String address, int txPhy, int rxPhy, int phyOptions, AttributionSource attributionSource)660         public void clientSetPreferredPhy(int clientIf, String address, int txPhy, int rxPhy,
661                 int phyOptions, AttributionSource attributionSource) {
662             GattService service = getService();
663             if (service == null) {
664                 return;
665             }
666             service.clientSetPreferredPhy(clientIf, address, txPhy, rxPhy, phyOptions,
667                     attributionSource);
668         }
669 
670         @Override
clientReadPhy( int clientIf, String address, AttributionSource attributionSource)671         public void clientReadPhy(
672                 int clientIf, String address, AttributionSource attributionSource) {
673             GattService service = getService();
674             if (service == null) {
675                 return;
676             }
677             service.clientReadPhy(clientIf, address, attributionSource);
678         }
679 
680         @Override
refreshDevice( int clientIf, String address, AttributionSource attributionSource)681         public void refreshDevice(
682                 int clientIf, String address, AttributionSource attributionSource) {
683             GattService service = getService();
684             if (service == null) {
685                 return;
686             }
687             service.refreshDevice(clientIf, address, attributionSource);
688         }
689 
690         @Override
discoverServices( int clientIf, String address, AttributionSource attributionSource)691         public void discoverServices(
692                 int clientIf, String address, AttributionSource attributionSource) {
693             GattService service = getService();
694             if (service == null) {
695                 return;
696             }
697             service.discoverServices(clientIf, address, attributionSource);
698         }
699 
700         @Override
discoverServiceByUuid(int clientIf, String address, ParcelUuid uuid, AttributionSource attributionSource)701         public void discoverServiceByUuid(int clientIf, String address, ParcelUuid uuid,
702                 AttributionSource attributionSource) {
703             GattService service = getService();
704             if (service == null) {
705                 return;
706             }
707             service.discoverServiceByUuid(clientIf, address, uuid.getUuid(), attributionSource);
708         }
709 
710         @Override
readCharacteristic(int clientIf, String address, int handle, int authReq, AttributionSource attributionSource)711         public void readCharacteristic(int clientIf, String address, int handle, int authReq,
712                 AttributionSource attributionSource) {
713             GattService service = getService();
714             if (service == null) {
715                 return;
716             }
717             service.readCharacteristic(clientIf, address, handle, authReq, attributionSource);
718         }
719 
720         @Override
readUsingCharacteristicUuid(int clientIf, String address, ParcelUuid uuid, int startHandle, int endHandle, int authReq, AttributionSource attributionSource)721         public void readUsingCharacteristicUuid(int clientIf, String address, ParcelUuid uuid,
722                 int startHandle, int endHandle, int authReq, AttributionSource attributionSource) {
723             GattService service = getService();
724             if (service == null) {
725                 return;
726             }
727             service.readUsingCharacteristicUuid(clientIf, address, uuid.getUuid(), startHandle,
728                     endHandle, authReq, attributionSource);
729         }
730 
731         @Override
writeCharacteristic(int clientIf, String address, int handle, int writeType, int authReq, byte[] value, AttributionSource attributionSource)732         public void writeCharacteristic(int clientIf, String address, int handle, int writeType,
733                 int authReq, byte[] value, AttributionSource attributionSource) {
734             GattService service = getService();
735             if (service == null) {
736                 return;
737             }
738             service.writeCharacteristic(clientIf, address, handle, writeType, authReq, value,
739                     attributionSource);
740         }
741 
742         @Override
readDescriptor(int clientIf, String address, int handle, int authReq, AttributionSource attributionSource)743         public void readDescriptor(int clientIf, String address, int handle, int authReq,
744                 AttributionSource attributionSource) {
745             GattService service = getService();
746             if (service == null) {
747                 return;
748             }
749             service.readDescriptor(clientIf, address, handle, authReq, attributionSource);
750         }
751 
752         @Override
writeDescriptor(int clientIf, String address, int handle, int authReq, byte[] value, AttributionSource attributionSource)753         public void writeDescriptor(int clientIf, String address, int handle, int authReq,
754                 byte[] value, AttributionSource attributionSource) {
755             GattService service = getService();
756             if (service == null) {
757                 return;
758             }
759             service.writeDescriptor(clientIf, address, handle, authReq, value, attributionSource);
760         }
761 
762         @Override
beginReliableWrite( int clientIf, String address, AttributionSource attributionSource)763         public void beginReliableWrite(
764                 int clientIf, String address, AttributionSource attributionSource) {
765             GattService service = getService();
766             if (service == null) {
767                 return;
768             }
769             service.beginReliableWrite(clientIf, address, attributionSource);
770         }
771 
772         @Override
endReliableWrite(int clientIf, String address, boolean execute, AttributionSource attributionSource)773         public void endReliableWrite(int clientIf, String address, boolean execute,
774                 AttributionSource attributionSource) {
775             GattService service = getService();
776             if (service == null) {
777                 return;
778             }
779             service.endReliableWrite(clientIf, address, execute, attributionSource);
780         }
781 
782         @Override
registerForNotification(int clientIf, String address, int handle, boolean enable, AttributionSource attributionSource)783         public void registerForNotification(int clientIf, String address, int handle,
784                 boolean enable, AttributionSource attributionSource) {
785             GattService service = getService();
786             if (service == null) {
787                 return;
788             }
789             service.registerForNotification(clientIf, address, handle, enable, attributionSource);
790         }
791 
792         @Override
readRemoteRssi( int clientIf, String address, AttributionSource attributionSource)793         public void readRemoteRssi(
794                 int clientIf, String address, AttributionSource attributionSource) {
795             GattService service = getService();
796             if (service == null) {
797                 return;
798             }
799             service.readRemoteRssi(clientIf, address, attributionSource);
800         }
801 
802         @Override
configureMTU( int clientIf, String address, int mtu, AttributionSource attributionSource)803         public void configureMTU(
804                 int clientIf, String address, int mtu, AttributionSource attributionSource) {
805             GattService service = getService();
806             if (service == null) {
807                 return;
808             }
809             service.configureMTU(clientIf, address, mtu, attributionSource);
810         }
811 
812         @Override
connectionParameterUpdate(int clientIf, String address, int connectionPriority, AttributionSource attributionSource)813         public void connectionParameterUpdate(int clientIf, String address,
814                 int connectionPriority, AttributionSource attributionSource) {
815             GattService service = getService();
816             if (service == null) {
817                 return;
818             }
819             service.connectionParameterUpdate(
820                     clientIf, address, connectionPriority, attributionSource);
821         }
822 
823         @Override
leConnectionUpdate(int clientIf, String address, int minConnectionInterval, int maxConnectionInterval, int peripheralLatency, int supervisionTimeout, int minConnectionEventLen, int maxConnectionEventLen, AttributionSource attributionSource)824         public void leConnectionUpdate(int clientIf, String address,
825                 int minConnectionInterval, int maxConnectionInterval,
826                 int peripheralLatency, int supervisionTimeout,
827                 int minConnectionEventLen, int maxConnectionEventLen,
828                 AttributionSource attributionSource) {
829             GattService service = getService();
830             if (service == null) {
831                 return;
832             }
833             service.leConnectionUpdate(clientIf, address, minConnectionInterval,
834                                        maxConnectionInterval, peripheralLatency,
835                                        supervisionTimeout, minConnectionEventLen,
836                                        maxConnectionEventLen, attributionSource);
837         }
838 
839         @Override
registerServer(ParcelUuid uuid, IBluetoothGattServerCallback callback, boolean eatt_support, AttributionSource attributionSource)840         public void registerServer(ParcelUuid uuid, IBluetoothGattServerCallback callback,
841                 boolean eatt_support, AttributionSource attributionSource) {
842             GattService service = getService();
843             if (service == null) {
844                 return;
845             }
846             service.registerServer(uuid.getUuid(), callback, eatt_support, attributionSource);
847         }
848 
849         @Override
unregisterServer(int serverIf, AttributionSource attributionSource)850         public void unregisterServer(int serverIf, AttributionSource attributionSource) {
851             GattService service = getService();
852             if (service == null) {
853                 return;
854             }
855             service.unregisterServer(serverIf, attributionSource);
856         }
857 
858         @Override
serverConnect(int serverIf, String address, boolean isDirect, int transport, AttributionSource attributionSource)859         public void serverConnect(int serverIf, String address, boolean isDirect, int transport,
860                 AttributionSource attributionSource) {
861             GattService service = getService();
862             if (service == null) {
863                 return;
864             }
865             service.serverConnect(serverIf, address, isDirect, transport, attributionSource);
866         }
867 
868         @Override
serverDisconnect( int serverIf, String address, AttributionSource attributionSource)869         public void serverDisconnect(
870                 int serverIf, String address, AttributionSource attributionSource) {
871             GattService service = getService();
872             if (service == null) {
873                 return;
874             }
875             service.serverDisconnect(serverIf, address, attributionSource);
876         }
877 
878         @Override
serverSetPreferredPhy(int serverIf, String address, int txPhy, int rxPhy, int phyOptions, AttributionSource attributionSource)879         public void serverSetPreferredPhy(int serverIf, String address, int txPhy, int rxPhy,
880                 int phyOptions, AttributionSource attributionSource) {
881             GattService service = getService();
882             if (service == null) {
883                 return;
884             }
885             service.serverSetPreferredPhy(
886                     serverIf, address, txPhy, rxPhy, phyOptions, attributionSource);
887         }
888 
889         @Override
serverReadPhy( int clientIf, String address, AttributionSource attributionSource)890         public void serverReadPhy(
891                 int clientIf, String address, AttributionSource attributionSource) {
892             GattService service = getService();
893             if (service == null) {
894                 return;
895             }
896             service.serverReadPhy(clientIf, address, attributionSource);
897         }
898 
899         @Override
addService( int serverIf, BluetoothGattService svc, AttributionSource attributionSource)900         public void addService(
901                 int serverIf, BluetoothGattService svc, AttributionSource attributionSource) {
902             GattService service = getService();
903             if (service == null) {
904                 return;
905             }
906 
907             service.addService(serverIf, svc, attributionSource);
908         }
909 
910         @Override
removeService(int serverIf, int handle, AttributionSource attributionSource)911         public void removeService(int serverIf, int handle, AttributionSource attributionSource) {
912             GattService service = getService();
913             if (service == null) {
914                 return;
915             }
916             service.removeService(serverIf, handle, attributionSource);
917         }
918 
919         @Override
clearServices(int serverIf, AttributionSource attributionSource)920         public void clearServices(int serverIf, AttributionSource attributionSource) {
921             GattService service = getService();
922             if (service == null) {
923                 return;
924             }
925             service.clearServices(serverIf, attributionSource);
926         }
927 
928         @Override
sendResponse(int serverIf, String address, int requestId, int status, int offset, byte[] value, AttributionSource attributionSource)929         public void sendResponse(int serverIf, String address, int requestId, int status,
930                 int offset, byte[] value, AttributionSource attributionSource) {
931             GattService service = getService();
932             if (service == null) {
933                 return;
934             }
935             service.sendResponse(
936                     serverIf, address, requestId, status, offset, value, attributionSource);
937         }
938 
939         @Override
sendNotification(int serverIf, String address, int handle, boolean confirm, byte[] value, AttributionSource attributionSource)940         public void sendNotification(int serverIf, String address, int handle, boolean confirm,
941                 byte[] value, AttributionSource attributionSource) {
942             GattService service = getService();
943             if (service == null) {
944                 return;
945             }
946             service.sendNotification(serverIf, address, handle, confirm, value, attributionSource);
947         }
948 
949         @Override
startAdvertisingSet(AdvertisingSetParameters parameters, AdvertiseData advertiseData, AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData, int duration, int maxExtAdvEvents, IAdvertisingSetCallback callback, AttributionSource attributionSource)950         public void startAdvertisingSet(AdvertisingSetParameters parameters,
951                 AdvertiseData advertiseData, AdvertiseData scanResponse,
952                 PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData,
953                 int duration, int maxExtAdvEvents, IAdvertisingSetCallback callback,
954                 AttributionSource attributionSource) {
955             GattService service = getService();
956             if (service == null) {
957                 return;
958             }
959             service.startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
960                     periodicData, duration, maxExtAdvEvents, callback, attributionSource);
961         }
962 
963         @Override
stopAdvertisingSet( IAdvertisingSetCallback callback, AttributionSource attributionSource)964         public void stopAdvertisingSet(
965                 IAdvertisingSetCallback callback, AttributionSource attributionSource) {
966             GattService service = getService();
967             if (service == null) {
968                 return;
969             }
970             service.stopAdvertisingSet(callback, attributionSource);
971         }
972 
973         @Override
getOwnAddress(int advertiserId, AttributionSource attributionSource)974         public void getOwnAddress(int advertiserId, AttributionSource attributionSource) {
975             GattService service = getService();
976             if (service == null) {
977                 return;
978             }
979             service.getOwnAddress(advertiserId, attributionSource);
980         }
981 
982         @Override
enableAdvertisingSet(int advertiserId, boolean enable, int duration, int maxExtAdvEvents, AttributionSource attributionSource)983         public void enableAdvertisingSet(int advertiserId, boolean enable, int duration,
984                 int maxExtAdvEvents, AttributionSource attributionSource) {
985             GattService service = getService();
986             if (service == null) {
987                 return;
988             }
989             service.enableAdvertisingSet(
990                     advertiserId, enable, duration, maxExtAdvEvents, attributionSource);
991         }
992 
993         @Override
setAdvertisingData( int advertiserId, AdvertiseData data, AttributionSource attributionSource)994         public void setAdvertisingData(
995                 int advertiserId, AdvertiseData data, AttributionSource attributionSource) {
996             GattService service = getService();
997             if (service == null) {
998                 return;
999             }
1000             service.setAdvertisingData(advertiserId, data, attributionSource);
1001         }
1002 
1003         @Override
setScanResponseData( int advertiserId, AdvertiseData data, AttributionSource attributionSource)1004         public void setScanResponseData(
1005                 int advertiserId, AdvertiseData data, AttributionSource attributionSource) {
1006             GattService service = getService();
1007             if (service == null) {
1008                 return;
1009             }
1010             service.setScanResponseData(advertiserId, data, attributionSource);
1011         }
1012 
1013         @Override
setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters, AttributionSource attributionSource)1014         public void setAdvertisingParameters(int advertiserId,
1015                 AdvertisingSetParameters parameters, AttributionSource attributionSource) {
1016             GattService service = getService();
1017             if (service == null) {
1018                 return;
1019             }
1020             service.setAdvertisingParameters(advertiserId, parameters, attributionSource);
1021         }
1022 
1023         @Override
setPeriodicAdvertisingParameters(int advertiserId, PeriodicAdvertisingParameters parameters, AttributionSource attributionSource)1024         public void setPeriodicAdvertisingParameters(int advertiserId,
1025                 PeriodicAdvertisingParameters parameters, AttributionSource attributionSource) {
1026             GattService service = getService();
1027             if (service == null) {
1028                 return;
1029             }
1030             service.setPeriodicAdvertisingParameters(advertiserId, parameters, attributionSource);
1031         }
1032 
1033         @Override
setPeriodicAdvertisingData(int advertiserId, AdvertiseData data, AttributionSource attributionSource)1034         public void setPeriodicAdvertisingData(int advertiserId, AdvertiseData data,
1035                 AttributionSource attributionSource) {
1036             GattService service = getService();
1037             if (service == null) {
1038                 return;
1039             }
1040             service.setPeriodicAdvertisingData(advertiserId, data, attributionSource);
1041         }
1042 
1043         @Override
setPeriodicAdvertisingEnable( int advertiserId, boolean enable, AttributionSource attributionSource)1044         public void setPeriodicAdvertisingEnable(
1045                 int advertiserId, boolean enable, AttributionSource attributionSource) {
1046             GattService service = getService();
1047             if (service == null) {
1048                 return;
1049             }
1050             service.setPeriodicAdvertisingEnable(advertiserId, enable, attributionSource);
1051         }
1052 
1053         @Override
registerSync(ScanResult scanResult, int skip, int timeout, IPeriodicAdvertisingCallback callback, AttributionSource attributionSource)1054         public void registerSync(ScanResult scanResult, int skip, int timeout,
1055                 IPeriodicAdvertisingCallback callback, AttributionSource attributionSource) {
1056             GattService service = getService();
1057             if (service == null) {
1058                 return;
1059             }
1060             service.registerSync(scanResult, skip, timeout, callback, attributionSource);
1061         }
1062 
1063         @Override
unregisterSync( IPeriodicAdvertisingCallback callback, AttributionSource attributionSource)1064         public void unregisterSync(
1065                 IPeriodicAdvertisingCallback callback, AttributionSource attributionSource) {
1066             GattService service = getService();
1067             if (service == null) {
1068                 return;
1069             }
1070             service.unregisterSync(callback, attributionSource);
1071         }
1072 
1073         @Override
disconnectAll(AttributionSource attributionSource)1074         public void disconnectAll(AttributionSource attributionSource) {
1075             GattService service = getService();
1076             if (service == null) {
1077                 return;
1078             }
1079             service.disconnectAll(attributionSource);
1080         }
1081 
1082         @Override
unregAll(AttributionSource attributionSource)1083         public void unregAll(AttributionSource attributionSource) {
1084             GattService service = getService();
1085             if (service == null) {
1086                 return;
1087             }
1088             service.unregAll(attributionSource);
1089         }
1090 
1091         @Override
numHwTrackFiltersAvailable(AttributionSource attributionSource)1092         public int numHwTrackFiltersAvailable(AttributionSource attributionSource) {
1093             GattService service = getService();
1094             if (service == null) {
1095                 return 0;
1096             }
1097             return service.numHwTrackFiltersAvailable(attributionSource);
1098         }
1099     }
1100 
1101     ;
1102 
1103     /**************************************************************************
1104      * Callback functions - CLIENT
1105      *************************************************************************/
1106 
1107     // EN format defined here:
1108     // https://blog.google/documents/70/Exposure_Notification_-_Bluetooth_Specification_v1.2.2.pdf
1109     private static final byte[] EXPOSURE_NOTIFICATION_FLAGS_PREAMBLE = new byte[] {
1110         // size 2, flag field, flags byte (value is not important)
1111         (byte) 0x02, (byte) 0x01
1112     };
1113     private static final int EXPOSURE_NOTIFICATION_FLAGS_LENGTH = 0x2 + 1;
1114     private static final byte[] EXPOSURE_NOTIFICATION_PAYLOAD_PREAMBLE = new byte[] {
1115         // size 3, complete 16 bit UUID, EN UUID
1116         (byte) 0x03, (byte) 0x03, (byte) 0x6F, (byte) 0xFD,
1117         // size 23, data for 16 bit UUID, EN UUID
1118         (byte) 0x17, (byte) 0x16, (byte) 0x6F, (byte) 0xFD,
1119         // ...payload
1120     };
1121     private static final int EXPOSURE_NOTIFICATION_PAYLOAD_LENGTH = 0x03 + 0x17 + 2;
1122 
arrayStartsWith(byte[] array, byte[] prefix)1123     private static boolean arrayStartsWith(byte[] array, byte[] prefix) {
1124         if (array.length < prefix.length) {
1125             return false;
1126         }
1127         for (int i = 0; i < prefix.length; i++) {
1128             if (prefix[i] != array[i]) {
1129                 return false;
1130             }
1131         }
1132         return true;
1133     }
1134 
getSanitizedExposureNotification(ScanResult result)1135     ScanResult getSanitizedExposureNotification(ScanResult result) {
1136         ScanRecord record = result.getScanRecord();
1137         // Remove the flags part of the payload, if present
1138         if (record.getBytes().length > EXPOSURE_NOTIFICATION_FLAGS_LENGTH
1139                 && arrayStartsWith(record.getBytes(), EXPOSURE_NOTIFICATION_FLAGS_PREAMBLE)) {
1140             record = ScanRecord.parseFromBytes(
1141                     Arrays.copyOfRange(
1142                             record.getBytes(),
1143                             EXPOSURE_NOTIFICATION_FLAGS_LENGTH,
1144                             record.getBytes().length));
1145         }
1146 
1147         if (record.getBytes().length != EXPOSURE_NOTIFICATION_PAYLOAD_LENGTH) {
1148             return null;
1149         }
1150         if (!arrayStartsWith(record.getBytes(), EXPOSURE_NOTIFICATION_PAYLOAD_PREAMBLE)) {
1151             return null;
1152         }
1153 
1154         return new ScanResult(null, 0, 0, 0, 0, 0, result.getRssi(), 0, record, 0);
1155     }
1156 
onScanResult(int eventType, int addressType, String address, int primaryPhy, int secondaryPhy, int advertisingSid, int txPower, int rssi, int periodicAdvInt, byte[] advData, String originalAddress)1157     void onScanResult(int eventType, int addressType, String address, int primaryPhy,
1158             int secondaryPhy, int advertisingSid, int txPower, int rssi, int periodicAdvInt,
1159             byte[] advData, String originalAddress) {
1160         // When in testing mode, ignore all real-world events
1161         if (isTestModeEnabled()) return;
1162 
1163         onScanResultInternal(eventType, addressType, address, primaryPhy, secondaryPhy,
1164                 advertisingSid, txPower, rssi, periodicAdvInt, advData, originalAddress);
1165     }
1166 
onScanResultInternal(int eventType, int addressType, String address, int primaryPhy, int secondaryPhy, int advertisingSid, int txPower, int rssi, int periodicAdvInt, byte[] advData, String originalAddress)1167     void onScanResultInternal(int eventType, int addressType, String address, int primaryPhy,
1168             int secondaryPhy, int advertisingSid, int txPower, int rssi, int periodicAdvInt,
1169             byte[] advData, String originalAddress) {
1170         if (VDBG || mAdapterService.getIsVerboseLoggingEnabledForAll()) {
1171             Log.d(TAG, "onScanResult() - eventType=0x" + Integer.toHexString(eventType)
1172                     + ", addressType=" + addressType + ", address=" + address + ", primaryPhy="
1173                     + primaryPhy + ", secondaryPhy=" + secondaryPhy + ", advertisingSid=0x"
1174                     + Integer.toHexString(advertisingSid) + ", txPower=" + txPower + ", rssi="
1175                     + rssi + ", periodicAdvInt=0x" + Integer.toHexString(periodicAdvInt)
1176                     + ", originalAddress=" + originalAddress);
1177         }
1178 
1179         byte[] legacyAdvData = Arrays.copyOfRange(advData, 0, 62);
1180 
1181         for (ScanClient client : mScanManager.getRegularScanQueue()) {
1182             ScannerMap.App app = mScannerMap.getById(client.scannerId);
1183             if (app == null) {
1184                 if (VDBG || mAdapterService.getIsVerboseLoggingEnabledForAll()) {
1185                     Log.d(TAG, "App is null for scanner ID " + client.scannerId);
1186                 }
1187                 continue;
1188             }
1189 
1190             BluetoothDevice device = getAnonymousDevice(address);
1191 
1192             ScanSettings settings = client.settings;
1193             byte[] scanRecordData;
1194             // This is for compability with applications that assume fixed size scan data.
1195             if (settings.getLegacy()) {
1196                 if ((eventType & ET_LEGACY_MASK) == 0) {
1197                     // If this is legacy scan, but nonlegacy result - skip.
1198                     Log.i(TAG, "Non legacy result in legacy scan, skipping scanner id "
1199                                + client.scannerId + ", eventType=" + eventType);
1200                     continue;
1201                 } else {
1202                     // Some apps are used to fixed-size advertise data.
1203                     scanRecordData = legacyAdvData;
1204                 }
1205             } else {
1206                 scanRecordData = advData;
1207             }
1208 
1209             ScanRecord scanRecord = ScanRecord.parseFromBytes(scanRecordData);
1210             ScanResult result =
1211                     new ScanResult(device, eventType, primaryPhy, secondaryPhy, advertisingSid,
1212                             txPower, rssi, periodicAdvInt, scanRecord,
1213                             SystemClock.elapsedRealtimeNanos());
1214 
1215             if (client.hasDisavowedLocation) {
1216                 if (mLocationDenylistPredicate.test(result)) {
1217                     if (VDBG || mAdapterService.getIsVerboseLoggingEnabledForAll()) {
1218                         Log.d(TAG, "Result in location deny list, skipping scanner id "
1219                                 + client.scannerId);
1220                     }
1221                     continue;
1222                 }
1223             }
1224 
1225             boolean hasPermission = hasScanResultPermission(client);
1226             if (!hasPermission) {
1227                 for (String associatedDevice : client.associatedDevices) {
1228                     if (associatedDevice.equalsIgnoreCase(address)) {
1229                         hasPermission = true;
1230                         break;
1231                     }
1232                 }
1233             }
1234             if (!hasPermission && client.eligibleForSanitizedExposureNotification) {
1235                 ScanResult sanitized = getSanitizedExposureNotification(result);
1236                 if (sanitized != null) {
1237                     hasPermission = true;
1238                     result = sanitized;
1239                 }
1240             }
1241             if (!hasPermission) {
1242                 if (VDBG || mAdapterService.getIsVerboseLoggingEnabledForAll()) {
1243                     Log.d(TAG, "scanner id " + client.scannerId + " has no result permission");
1244                 }
1245                 continue;
1246             }
1247 
1248             MatchResult matchResult = matchesFilters(client, result, originalAddress);
1249             if (!matchResult.getMatches()) {
1250                 if (VDBG || mAdapterService.getIsVerboseLoggingEnabledForAll()) {
1251                     Log.d(TAG, "result did not match filter for scanner id " + client.scannerId);
1252                 }
1253                 continue;
1254             }
1255 
1256             if (matchResult.getMatchOrigin() == MatchOrigin.ORIGINAL_ADDRESS) {
1257                 result = new ScanResult(getAnonymousDevice(originalAddress), eventType, primaryPhy,
1258                         secondaryPhy, advertisingSid, txPower, rssi, periodicAdvInt, scanRecord,
1259                             SystemClock.elapsedRealtimeNanos());
1260 
1261             }
1262 
1263             if ((settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_ALL_MATCHES) == 0) {
1264                 if (VDBG || mAdapterService.getIsVerboseLoggingEnabledForAll()) {
1265                     Log.d(TAG, "callback type " + settings.getCallbackType()
1266                             + " is not ALL_MATCHES for scanner id " + client.scannerId);
1267                 }
1268                 continue;
1269             }
1270 
1271             try {
1272                 app.appScanStats.addResult(client.scannerId);
1273                 if (app.callback != null) {
1274                     app.callback.onScanResult(result);
1275                 } else {
1276                     // Send the PendingIntent
1277                     ArrayList<ScanResult> results = new ArrayList<>();
1278                     results.add(result);
1279                     sendResultsByPendingIntent(app.info, results,
1280                             ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
1281                 }
1282             } catch (RemoteException | PendingIntent.CanceledException e) {
1283                 Log.e(TAG, "Stop scan for scanner id " + client.scannerId + " due to : " + e);
1284                 mScannerMap.remove(client.scannerId);
1285                 mScanManager.stopScan(client.scannerId);
1286             }
1287         }
1288     }
1289 
sendResultByPendingIntent(PendingIntentInfo pii, ScanResult result, int callbackType, ScanClient client)1290     private void sendResultByPendingIntent(PendingIntentInfo pii, ScanResult result,
1291             int callbackType, ScanClient client) {
1292         ArrayList<ScanResult> results = new ArrayList<>();
1293         results.add(result);
1294         try {
1295             sendResultsByPendingIntent(pii, results, callbackType);
1296         } catch (PendingIntent.CanceledException e) {
1297             final long token = Binder.clearCallingIdentity();
1298             try {
1299                 stopScan(client.scannerId, getAttributionSource());
1300                 unregisterScanner(client.scannerId, getAttributionSource());
1301             } finally {
1302                 Binder.restoreCallingIdentity(token);
1303             }
1304         }
1305     }
1306 
sendResultsByPendingIntent(PendingIntentInfo pii, ArrayList<ScanResult> results, int callbackType)1307     private void sendResultsByPendingIntent(PendingIntentInfo pii, ArrayList<ScanResult> results,
1308             int callbackType) throws PendingIntent.CanceledException {
1309         Intent extrasIntent = new Intent();
1310         extrasIntent.putParcelableArrayListExtra(BluetoothLeScanner.EXTRA_LIST_SCAN_RESULT,
1311                 results);
1312         extrasIntent.putExtra(BluetoothLeScanner.EXTRA_CALLBACK_TYPE, callbackType);
1313         pii.intent.send(this, 0, extrasIntent);
1314     }
1315 
sendErrorByPendingIntent(PendingIntentInfo pii, int errorCode)1316     private void sendErrorByPendingIntent(PendingIntentInfo pii, int errorCode)
1317             throws PendingIntent.CanceledException {
1318         Intent extrasIntent = new Intent();
1319         extrasIntent.putExtra(BluetoothLeScanner.EXTRA_ERROR_CODE, errorCode);
1320         pii.intent.send(this, 0, extrasIntent);
1321     }
1322 
onScannerRegistered(int status, int scannerId, long uuidLsb, long uuidMsb)1323     void onScannerRegistered(int status, int scannerId, long uuidLsb, long uuidMsb)
1324             throws RemoteException {
1325         UUID uuid = new UUID(uuidMsb, uuidLsb);
1326         if (DBG) {
1327             Log.d(TAG, "onScannerRegistered() - UUID=" + uuid + ", scannerId=" + scannerId
1328                     + ", status=" + status);
1329         }
1330 
1331         // First check the callback map
1332         ScannerMap.App cbApp = mScannerMap.getByUuid(uuid);
1333         if (cbApp != null) {
1334             if (status == 0) {
1335                 cbApp.id = scannerId;
1336                 // If app is callback based, setup a death recipient. App will initiate the start.
1337                 // Otherwise, if PendingIntent based, start the scan directly.
1338                 if (cbApp.callback != null) {
1339                     cbApp.linkToDeath(new ScannerDeathRecipient(scannerId));
1340                 } else {
1341                     continuePiStartScan(scannerId, cbApp);
1342                 }
1343             } else {
1344                 mScannerMap.remove(scannerId);
1345             }
1346             if (cbApp.callback != null) {
1347                 cbApp.callback.onScannerRegistered(status, scannerId);
1348             }
1349         }
1350     }
1351 
1352     /** Determines if the given scan client has the appropriate permissions to receive callbacks. */
hasScanResultPermission(final ScanClient client)1353     private boolean hasScanResultPermission(final ScanClient client) {
1354         if (client.hasNetworkSettingsPermission
1355                 || client.hasNetworkSetupWizardPermission
1356                 || client.hasScanWithoutLocationPermission) {
1357             return true;
1358         }
1359         if (client.hasDisavowedLocation) {
1360             return true;
1361         }
1362         return client.hasLocationPermission && !Utils.blockedByLocationOff(this, client.userHandle);
1363     }
1364 
1365     // Check if a scan record matches a specific filters.
matchesFilters(ScanClient client, ScanResult scanResult)1366     private MatchResult matchesFilters(ScanClient client, ScanResult scanResult) {
1367         return matchesFilters(client, scanResult, null);
1368     }
1369 
1370 
1371     // Check if a scan record matches a specific filters.
matchesFilters(ScanClient client, ScanResult scanResult, String originalAddress)1372     private MatchResult matchesFilters(ScanClient client, ScanResult scanResult,
1373             String originalAddress) {
1374         if (client.filters == null || client.filters.isEmpty()) {
1375             // TODO: Do we really wanna return true here?
1376             return new MatchResult(true, MatchOrigin.PSEUDO_ADDRESS);
1377         }
1378         for (ScanFilter filter : client.filters) {
1379             // Need to check the filter matches, and the original address without changing the API
1380             if (filter.matches(scanResult)) {
1381                 return new MatchResult(true, MatchOrigin.PSEUDO_ADDRESS);
1382             }
1383             if (originalAddress != null
1384                     && originalAddress.equalsIgnoreCase(filter.getDeviceAddress())) {
1385                 return new MatchResult(true, MatchOrigin.ORIGINAL_ADDRESS);
1386             }
1387         }
1388         return new MatchResult(false, MatchOrigin.PSEUDO_ADDRESS);
1389     }
1390 
onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb)1391     void onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb)
1392             throws RemoteException {
1393         UUID uuid = new UUID(uuidMsb, uuidLsb);
1394         if (DBG) {
1395             Log.d(TAG, "onClientRegistered() - UUID=" + uuid + ", clientIf=" + clientIf);
1396         }
1397         ClientMap.App app = mClientMap.getByUuid(uuid);
1398         if (app != null) {
1399             if (status == 0) {
1400                 app.id = clientIf;
1401                 app.linkToDeath(new ClientDeathRecipient(clientIf));
1402             } else {
1403                 mClientMap.remove(uuid);
1404             }
1405             app.callback.onClientRegistered(status, clientIf);
1406         }
1407     }
1408 
onConnected(int clientIf, int connId, int status, String address)1409     void onConnected(int clientIf, int connId, int status, String address) throws RemoteException {
1410         if (DBG) {
1411             Log.d(TAG, "onConnected() - clientIf=" + clientIf + ", connId=" + connId + ", address="
1412                     + address);
1413         }
1414 
1415         if (status == 0) {
1416             mClientMap.addConnection(clientIf, connId, address);
1417         }
1418         ClientMap.App app = mClientMap.getById(clientIf);
1419         if (app != null) {
1420             app.callback.onClientConnectionState(status, clientIf,
1421                     (status == BluetoothGatt.GATT_SUCCESS), address);
1422         }
1423     }
1424 
onDisconnected(int clientIf, int connId, int status, String address)1425     void onDisconnected(int clientIf, int connId, int status, String address)
1426             throws RemoteException {
1427         if (DBG) {
1428             Log.d(TAG,
1429                     "onDisconnected() - clientIf=" + clientIf + ", connId=" + connId + ", address="
1430                             + address);
1431         }
1432 
1433         mClientMap.removeConnection(clientIf, connId);
1434         ClientMap.App app = mClientMap.getById(clientIf);
1435         if (app != null) {
1436             app.callback.onClientConnectionState(status, clientIf, false, address);
1437         }
1438     }
1439 
onClientPhyUpdate(int connId, int txPhy, int rxPhy, int status)1440     void onClientPhyUpdate(int connId, int txPhy, int rxPhy, int status) throws RemoteException {
1441         if (DBG) {
1442             Log.d(TAG, "onClientPhyUpdate() - connId=" + connId + ", status=" + status);
1443         }
1444 
1445         String address = mClientMap.addressByConnId(connId);
1446         if (address == null) {
1447             return;
1448         }
1449 
1450         ClientMap.App app = mClientMap.getByConnId(connId);
1451         if (app == null) {
1452             return;
1453         }
1454 
1455         app.callback.onPhyUpdate(address, txPhy, rxPhy, status);
1456     }
1457 
onClientPhyRead(int clientIf, String address, int txPhy, int rxPhy, int status)1458     void onClientPhyRead(int clientIf, String address, int txPhy, int rxPhy, int status)
1459             throws RemoteException {
1460         if (DBG) {
1461             Log.d(TAG,
1462                     "onClientPhyRead() - address=" + address + ", status=" + status + ", clientIf="
1463                             + clientIf);
1464         }
1465 
1466         Integer connId = mClientMap.connIdByAddress(clientIf, address);
1467         if (connId == null) {
1468             Log.d(TAG, "onClientPhyRead() - no connection to " + address);
1469             return;
1470         }
1471 
1472         ClientMap.App app = mClientMap.getByConnId(connId);
1473         if (app == null) {
1474             return;
1475         }
1476 
1477         app.callback.onPhyRead(address, txPhy, rxPhy, status);
1478     }
1479 
onClientConnUpdate(int connId, int interval, int latency, int timeout, int status)1480     void onClientConnUpdate(int connId, int interval, int latency, int timeout, int status)
1481             throws RemoteException {
1482         if (DBG) {
1483             Log.d(TAG, "onClientConnUpdate() - connId=" + connId + ", status=" + status);
1484         }
1485 
1486         String address = mClientMap.addressByConnId(connId);
1487         if (address == null) {
1488             return;
1489         }
1490 
1491         ClientMap.App app = mClientMap.getByConnId(connId);
1492         if (app == null) {
1493             return;
1494         }
1495 
1496         app.callback.onConnectionUpdated(address, interval, latency, timeout, status);
1497     }
1498 
onServiceChanged(int connId)1499     void onServiceChanged(int connId) throws RemoteException {
1500         if (DBG) {
1501             Log.d(TAG, "onServiceChanged - connId=" + connId);
1502         }
1503 
1504         String address = mClientMap.addressByConnId(connId);
1505         if (address == null) {
1506             return;
1507         }
1508 
1509         ClientMap.App app = mClientMap.getByConnId(connId);
1510         if (app == null) {
1511             return;
1512         }
1513 
1514         app.callback.onServiceChanged(address);
1515     }
1516 
onServerPhyUpdate(int connId, int txPhy, int rxPhy, int status)1517     void onServerPhyUpdate(int connId, int txPhy, int rxPhy, int status) throws RemoteException {
1518         if (DBG) {
1519             Log.d(TAG, "onServerPhyUpdate() - connId=" + connId + ", status=" + status);
1520         }
1521 
1522         String address = mServerMap.addressByConnId(connId);
1523         if (address == null) {
1524             return;
1525         }
1526 
1527         ServerMap.App app = mServerMap.getByConnId(connId);
1528         if (app == null) {
1529             return;
1530         }
1531 
1532         app.callback.onPhyUpdate(address, txPhy, rxPhy, status);
1533     }
1534 
onServerPhyRead(int serverIf, String address, int txPhy, int rxPhy, int status)1535     void onServerPhyRead(int serverIf, String address, int txPhy, int rxPhy, int status)
1536             throws RemoteException {
1537         if (DBG) {
1538             Log.d(TAG, "onServerPhyRead() - address=" + address + ", status=" + status);
1539         }
1540 
1541         Integer connId = mServerMap.connIdByAddress(serverIf, address);
1542         if (connId == null) {
1543             Log.d(TAG, "onServerPhyRead() - no connection to " + address);
1544             return;
1545         }
1546 
1547         ServerMap.App app = mServerMap.getByConnId(connId);
1548         if (app == null) {
1549             return;
1550         }
1551 
1552         app.callback.onPhyRead(address, txPhy, rxPhy, status);
1553     }
1554 
onServerConnUpdate(int connId, int interval, int latency, int timeout, int status)1555     void onServerConnUpdate(int connId, int interval, int latency, int timeout, int status)
1556             throws RemoteException {
1557         if (DBG) {
1558             Log.d(TAG, "onServerConnUpdate() - connId=" + connId + ", status=" + status);
1559         }
1560 
1561         String address = mServerMap.addressByConnId(connId);
1562         if (address == null) {
1563             return;
1564         }
1565 
1566         ServerMap.App app = mServerMap.getByConnId(connId);
1567         if (app == null) {
1568             return;
1569         }
1570 
1571         app.callback.onConnectionUpdated(address, interval, latency, timeout, status);
1572     }
1573 
onSearchCompleted(int connId, int status)1574     void onSearchCompleted(int connId, int status) throws RemoteException {
1575         if (DBG) {
1576             Log.d(TAG, "onSearchCompleted() - connId=" + connId + ", status=" + status);
1577         }
1578         // Gatt DB is ready!
1579 
1580         // This callback was called from the jni_workqueue thread. If we make request to the stack
1581         // on the same thread, it might cause deadlock. Schedule request on a new thread instead.
1582         Thread t = new Thread(new Runnable() {
1583             @Override
1584             public void run() {
1585                 gattClientGetGattDbNative(connId);
1586             }
1587         });
1588         t.start();
1589     }
1590 
getSampleGattDbElement()1591     GattDbElement getSampleGattDbElement() {
1592         return new GattDbElement();
1593     }
1594 
onGetGattDb(int connId, ArrayList<GattDbElement> db)1595     void onGetGattDb(int connId, ArrayList<GattDbElement> db) throws RemoteException {
1596         String address = mClientMap.addressByConnId(connId);
1597 
1598         if (DBG) {
1599             Log.d(TAG, "onGetGattDb() - address=" + address);
1600         }
1601 
1602         ClientMap.App app = mClientMap.getByConnId(connId);
1603         if (app == null || app.callback == null) {
1604             Log.e(TAG, "app or callback is null");
1605             return;
1606         }
1607 
1608         List<BluetoothGattService> dbOut = new ArrayList<BluetoothGattService>();
1609         Set<Integer> restrictedIds = new HashSet<>();
1610 
1611         BluetoothGattService currSrvc = null;
1612         BluetoothGattCharacteristic currChar = null;
1613         boolean isRestrictedSrvc = false;
1614         boolean isHidSrvc = false;
1615         boolean isRestrictedChar = false;
1616 
1617         for (GattDbElement el : db) {
1618             switch (el.type) {
1619                 case GattDbElement.TYPE_PRIMARY_SERVICE:
1620                 case GattDbElement.TYPE_SECONDARY_SERVICE:
1621                     if (DBG) {
1622                         Log.d(TAG, "got service with UUID=" + el.uuid + " id: " + el.id);
1623                     }
1624 
1625                     currSrvc = new BluetoothGattService(el.uuid, el.id, el.type);
1626                     dbOut.add(currSrvc);
1627                     isRestrictedSrvc =
1628                             isFidoSrvcUuid(el.uuid) || isAndroidTvRemoteSrvcUuid(el.uuid);
1629                     isHidSrvc = isHidSrvcUuid(el.uuid);
1630                     if (isRestrictedSrvc) {
1631                         restrictedIds.add(el.id);
1632                     }
1633                     break;
1634 
1635                 case GattDbElement.TYPE_CHARACTERISTIC:
1636                     if (DBG) {
1637                         Log.d(TAG, "got characteristic with UUID=" + el.uuid + " id: " + el.id);
1638                     }
1639 
1640                     currChar = new BluetoothGattCharacteristic(el.uuid, el.id, el.properties, 0);
1641                     currSrvc.addCharacteristic(currChar);
1642                     isRestrictedChar = isRestrictedSrvc || (isHidSrvc && isHidCharUuid(el.uuid));
1643                     if (isRestrictedChar) {
1644                         restrictedIds.add(el.id);
1645                     }
1646                     break;
1647 
1648                 case GattDbElement.TYPE_DESCRIPTOR:
1649                     if (DBG) {
1650                         Log.d(TAG, "got descriptor with UUID=" + el.uuid + " id: " + el.id);
1651                     }
1652 
1653                     currChar.addDescriptor(new BluetoothGattDescriptor(el.uuid, el.id, 0));
1654                     if (isRestrictedChar) {
1655                         restrictedIds.add(el.id);
1656                     }
1657                     break;
1658 
1659                 case GattDbElement.TYPE_INCLUDED_SERVICE:
1660                     if (DBG) {
1661                         Log.d(TAG, "got included service with UUID=" + el.uuid + " id: " + el.id
1662                                 + " startHandle: " + el.startHandle);
1663                     }
1664 
1665                     currSrvc.addIncludedService(
1666                             new BluetoothGattService(el.uuid, el.startHandle, el.type));
1667                     break;
1668 
1669                 default:
1670                     Log.e(TAG, "got unknown element with type=" + el.type + " and UUID=" + el.uuid
1671                             + " id: " + el.id);
1672             }
1673         }
1674 
1675         if (!restrictedIds.isEmpty()) {
1676             mRestrictedHandles.put(connId, restrictedIds);
1677         }
1678         // Search is complete when there was error, or nothing more to process
1679         app.callback.onSearchComplete(address, dbOut, 0 /* status */);
1680     }
1681 
onRegisterForNotifications(int connId, int status, int registered, int handle)1682     void onRegisterForNotifications(int connId, int status, int registered, int handle) {
1683         String address = mClientMap.addressByConnId(connId);
1684 
1685         if (DBG) {
1686             Log.d(TAG, "onRegisterForNotifications() - address=" + address + ", status=" + status
1687                     + ", registered=" + registered + ", handle=" + handle);
1688         }
1689     }
1690 
onNotify(int connId, String address, int handle, boolean isNotify, byte[] data)1691     void onNotify(int connId, String address, int handle, boolean isNotify, byte[] data)
1692             throws RemoteException {
1693 
1694         if (VDBG) {
1695             Log.d(TAG, "onNotify() - address=" + address + ", handle=" + handle + ", length="
1696                     + data.length);
1697         }
1698 
1699         ClientMap.App app = mClientMap.getByConnId(connId);
1700         if (app != null) {
1701             if (!permissionCheck(app, connId, handle)) {
1702                 Log.w(TAG, "onNotify() - permission check failed!");
1703                 return;
1704             }
1705             app.callback.onNotify(address, handle, data);
1706         }
1707     }
1708 
onReadCharacteristic(int connId, int status, int handle, byte[] data)1709     void onReadCharacteristic(int connId, int status, int handle, byte[] data)
1710             throws RemoteException {
1711         String address = mClientMap.addressByConnId(connId);
1712 
1713         if (VDBG) {
1714             Log.d(TAG, "onReadCharacteristic() - address=" + address + ", status=" + status
1715                     + ", length=" + data.length);
1716         }
1717 
1718         ClientMap.App app = mClientMap.getByConnId(connId);
1719         if (app != null) {
1720             app.callback.onCharacteristicRead(address, status, handle, data);
1721         }
1722     }
1723 
onWriteCharacteristic(int connId, int status, int handle)1724     void onWriteCharacteristic(int connId, int status, int handle) throws RemoteException {
1725         String address = mClientMap.addressByConnId(connId);
1726 
1727         if (VDBG) {
1728             Log.d(TAG, "onWriteCharacteristic() - address=" + address + ", status=" + status);
1729         }
1730 
1731         ClientMap.App app = mClientMap.getByConnId(connId);
1732         if (app == null) {
1733             return;
1734         }
1735 
1736         if (!app.isCongested) {
1737             app.callback.onCharacteristicWrite(address, status, handle);
1738         } else {
1739             if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) {
1740                 status = BluetoothGatt.GATT_SUCCESS;
1741             }
1742             CallbackInfo callbackInfo = new CallbackInfo(address, status, handle);
1743             app.queueCallback(callbackInfo);
1744         }
1745     }
1746 
onExecuteCompleted(int connId, int status)1747     void onExecuteCompleted(int connId, int status) throws RemoteException {
1748         String address = mClientMap.addressByConnId(connId);
1749         if (VDBG) {
1750             Log.d(TAG, "onExecuteCompleted() - address=" + address + ", status=" + status);
1751         }
1752 
1753         ClientMap.App app = mClientMap.getByConnId(connId);
1754         if (app != null) {
1755             app.callback.onExecuteWrite(address, status);
1756         }
1757     }
1758 
onReadDescriptor(int connId, int status, int handle, byte[] data)1759     void onReadDescriptor(int connId, int status, int handle, byte[] data) throws RemoteException {
1760         String address = mClientMap.addressByConnId(connId);
1761 
1762         if (VDBG) {
1763             Log.d(TAG,
1764                     "onReadDescriptor() - address=" + address + ", status=" + status + ", length="
1765                             + data.length);
1766         }
1767 
1768         ClientMap.App app = mClientMap.getByConnId(connId);
1769         if (app != null) {
1770             app.callback.onDescriptorRead(address, status, handle, data);
1771         }
1772     }
1773 
onWriteDescriptor(int connId, int status, int handle)1774     void onWriteDescriptor(int connId, int status, int handle) throws RemoteException {
1775         String address = mClientMap.addressByConnId(connId);
1776 
1777         if (VDBG) {
1778             Log.d(TAG, "onWriteDescriptor() - address=" + address + ", status=" + status);
1779         }
1780 
1781         ClientMap.App app = mClientMap.getByConnId(connId);
1782         if (app != null) {
1783             app.callback.onDescriptorWrite(address, status, handle);
1784         }
1785     }
1786 
onReadRemoteRssi(int clientIf, String address, int rssi, int status)1787     void onReadRemoteRssi(int clientIf, String address, int rssi, int status)
1788             throws RemoteException {
1789         if (DBG) {
1790             Log.d(TAG,
1791                     "onReadRemoteRssi() - clientIf=" + clientIf + " address=" + address + ", rssi="
1792                             + rssi + ", status=" + status);
1793         }
1794 
1795         ClientMap.App app = mClientMap.getById(clientIf);
1796         if (app != null) {
1797             app.callback.onReadRemoteRssi(address, rssi, status);
1798         }
1799     }
1800 
onScanFilterEnableDisabled(int action, int status, int clientIf)1801     void onScanFilterEnableDisabled(int action, int status, int clientIf) {
1802         if (DBG) {
1803             Log.d(TAG, "onScanFilterEnableDisabled() - clientIf=" + clientIf + ", status=" + status
1804                     + ", action=" + action);
1805         }
1806         mScanManager.callbackDone(clientIf, status);
1807     }
1808 
onScanFilterParamsConfigured(int action, int status, int clientIf, int availableSpace)1809     void onScanFilterParamsConfigured(int action, int status, int clientIf, int availableSpace) {
1810         if (DBG) {
1811             Log.d(TAG,
1812                     "onScanFilterParamsConfigured() - clientIf=" + clientIf + ", status=" + status
1813                             + ", action=" + action + ", availableSpace=" + availableSpace);
1814         }
1815         mScanManager.callbackDone(clientIf, status);
1816     }
1817 
onScanFilterConfig(int action, int status, int clientIf, int filterType, int availableSpace)1818     void onScanFilterConfig(int action, int status, int clientIf, int filterType,
1819             int availableSpace) {
1820         if (DBG) {
1821             Log.d(TAG, "onScanFilterConfig() - clientIf=" + clientIf + ", action = " + action
1822                     + " status = " + status + ", filterType=" + filterType + ", availableSpace="
1823                     + availableSpace);
1824         }
1825 
1826         mScanManager.callbackDone(clientIf, status);
1827     }
1828 
onBatchScanStorageConfigured(int status, int clientIf)1829     void onBatchScanStorageConfigured(int status, int clientIf) {
1830         if (DBG) {
1831             Log.d(TAG,
1832                     "onBatchScanStorageConfigured() - clientIf=" + clientIf + ", status=" + status);
1833         }
1834         mScanManager.callbackDone(clientIf, status);
1835     }
1836 
1837     // TODO: split into two different callbacks : onBatchScanStarted and onBatchScanStopped.
onBatchScanStartStopped(int startStopAction, int status, int clientIf)1838     void onBatchScanStartStopped(int startStopAction, int status, int clientIf) {
1839         if (DBG) {
1840             Log.d(TAG, "onBatchScanStartStopped() - clientIf=" + clientIf + ", status=" + status
1841                     + ", startStopAction=" + startStopAction);
1842         }
1843         mScanManager.callbackDone(clientIf, status);
1844     }
1845 
findBatchScanClientById(int scannerId)1846     ScanClient findBatchScanClientById(int scannerId) {
1847         for (ScanClient client : mScanManager.getBatchScanQueue()) {
1848             if (client.scannerId == scannerId) {
1849                 return client;
1850             }
1851         }
1852         return null;
1853     }
1854 
onBatchScanReports(int status, int scannerId, int reportType, int numRecords, byte[] recordData)1855     void onBatchScanReports(int status, int scannerId, int reportType, int numRecords,
1856             byte[] recordData) throws RemoteException {
1857         // When in testing mode, ignore all real-world events
1858         if (isTestModeEnabled()) return;
1859 
1860         onBatchScanReportsInternal(status, scannerId, reportType, numRecords, recordData);
1861     }
1862 
onBatchScanReportsInternal(int status, int scannerId, int reportType, int numRecords, byte[] recordData)1863     void onBatchScanReportsInternal(int status, int scannerId, int reportType, int numRecords,
1864             byte[] recordData) throws RemoteException {
1865         if (DBG) {
1866             Log.d(TAG, "onBatchScanReports() - scannerId=" + scannerId + ", status=" + status
1867                     + ", reportType=" + reportType + ", numRecords=" + numRecords);
1868         }
1869         mScanManager.callbackDone(scannerId, status);
1870         Set<ScanResult> results = parseBatchScanResults(numRecords, reportType, recordData);
1871         if (reportType == ScanManager.SCAN_RESULT_TYPE_TRUNCATED) {
1872             // We only support single client for truncated mode.
1873             ScannerMap.App app = mScannerMap.getById(scannerId);
1874             if (app == null) {
1875                 return;
1876             }
1877 
1878             ScanClient client = findBatchScanClientById(scannerId);
1879             if (client == null) {
1880                 return;
1881             }
1882 
1883             ArrayList<ScanResult> permittedResults;
1884             if (hasScanResultPermission(client)) {
1885                 permittedResults = new ArrayList<ScanResult>(results);
1886             } else {
1887                 permittedResults = new ArrayList<ScanResult>();
1888                 for (ScanResult scanResult : results) {
1889                     for (String associatedDevice : client.associatedDevices) {
1890                         if (associatedDevice.equalsIgnoreCase(scanResult.getDevice()
1891                                     .getAddress())) {
1892                             permittedResults.add(scanResult);
1893                         }
1894                     }
1895                 }
1896                 if (permittedResults.isEmpty()) {
1897                     return;
1898                 }
1899             }
1900 
1901             if (client.hasDisavowedLocation) {
1902                 permittedResults.removeIf(mLocationDenylistPredicate);
1903             }
1904 
1905             if (app.callback != null) {
1906                 app.callback.onBatchScanResults(permittedResults);
1907             } else {
1908                 // PendingIntent based
1909                 try {
1910                     sendResultsByPendingIntent(app.info, permittedResults,
1911                             ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
1912                 } catch (PendingIntent.CanceledException e) {
1913                 }
1914             }
1915         } else {
1916             for (ScanClient client : mScanManager.getFullBatchScanQueue()) {
1917                 // Deliver results for each client.
1918                 deliverBatchScan(client, results);
1919             }
1920         }
1921     }
1922 
sendBatchScanResults(ScannerMap.App app, ScanClient client, ArrayList<ScanResult> results)1923     private void sendBatchScanResults(ScannerMap.App app, ScanClient client,
1924             ArrayList<ScanResult> results) {
1925         try {
1926             if (app.callback != null) {
1927                 app.callback.onBatchScanResults(results);
1928             } else {
1929                 sendResultsByPendingIntent(app.info, results,
1930                         ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
1931             }
1932         } catch (RemoteException | PendingIntent.CanceledException e) {
1933             Log.e(TAG, "Exception: " + e);
1934             mScannerMap.remove(client.scannerId);
1935             mScanManager.stopScan(client.scannerId);
1936         }
1937     }
1938 
1939     // Check and deliver scan results for different scan clients.
deliverBatchScan(ScanClient client, Set<ScanResult> allResults)1940     private void deliverBatchScan(ScanClient client, Set<ScanResult> allResults)
1941             throws RemoteException {
1942         ScannerMap.App app = mScannerMap.getById(client.scannerId);
1943         if (app == null) {
1944             return;
1945         }
1946 
1947         ArrayList<ScanResult> permittedResults;
1948         if (hasScanResultPermission(client)) {
1949             permittedResults = new ArrayList<ScanResult>(allResults);
1950         } else {
1951             permittedResults = new ArrayList<ScanResult>();
1952             for (ScanResult scanResult : allResults) {
1953                 for (String associatedDevice : client.associatedDevices) {
1954                     if (associatedDevice.equalsIgnoreCase(scanResult.getDevice().getAddress())) {
1955                         permittedResults.add(scanResult);
1956                     }
1957                 }
1958             }
1959             if (permittedResults.isEmpty()) {
1960                 return;
1961             }
1962         }
1963 
1964         if (client.filters == null || client.filters.isEmpty()) {
1965             sendBatchScanResults(app, client, permittedResults);
1966             // TODO: Question to reviewer: Shouldn't there be a return here?
1967         }
1968         // Reconstruct the scan results.
1969         ArrayList<ScanResult> results = new ArrayList<ScanResult>();
1970         for (ScanResult scanResult : permittedResults) {
1971             if (matchesFilters(client, scanResult).getMatches()) {
1972                 results.add(scanResult);
1973             }
1974         }
1975         sendBatchScanResults(app, client, results);
1976     }
1977 
parseBatchScanResults(int numRecords, int reportType, byte[] batchRecord)1978     private Set<ScanResult> parseBatchScanResults(int numRecords, int reportType,
1979             byte[] batchRecord) {
1980         if (numRecords == 0) {
1981             return Collections.emptySet();
1982         }
1983         if (DBG) {
1984             Log.d(TAG, "current time is " + SystemClock.elapsedRealtimeNanos());
1985         }
1986         if (reportType == ScanManager.SCAN_RESULT_TYPE_TRUNCATED) {
1987             return parseTruncatedResults(numRecords, batchRecord);
1988         } else {
1989             return parseFullResults(numRecords, batchRecord);
1990         }
1991     }
1992 
parseTruncatedResults(int numRecords, byte[] batchRecord)1993     private Set<ScanResult> parseTruncatedResults(int numRecords, byte[] batchRecord) {
1994         if (DBG) {
1995             Log.d(TAG, "batch record " + Arrays.toString(batchRecord));
1996         }
1997         Set<ScanResult> results = new HashSet<ScanResult>(numRecords);
1998         long now = SystemClock.elapsedRealtimeNanos();
1999         for (int i = 0; i < numRecords; ++i) {
2000             byte[] record =
2001                     extractBytes(batchRecord, i * TRUNCATED_RESULT_SIZE, TRUNCATED_RESULT_SIZE);
2002             byte[] address = extractBytes(record, 0, 6);
2003             reverse(address);
2004             BluetoothDevice device = getAnonymousDevice(address);
2005             int rssi = record[8];
2006             long timestampNanos = now - parseTimestampNanos(extractBytes(record, 9, 2));
2007             results.add(new ScanResult(device, ScanRecord.parseFromBytes(new byte[0]), rssi,
2008                     timestampNanos));
2009         }
2010         return results;
2011     }
2012 
2013     @VisibleForTesting
parseTimestampNanos(byte[] data)2014     long parseTimestampNanos(byte[] data) {
2015         long timestampUnit = NumberUtils.littleEndianByteArrayToInt(data);
2016         // Timestamp is in every 50 ms.
2017         return TimeUnit.MILLISECONDS.toNanos(timestampUnit * 50);
2018     }
2019 
parseFullResults(int numRecords, byte[] batchRecord)2020     private Set<ScanResult> parseFullResults(int numRecords, byte[] batchRecord) {
2021         if (DBG) {
2022             Log.d(TAG, "Batch record : " + Arrays.toString(batchRecord));
2023         }
2024         Set<ScanResult> results = new HashSet<ScanResult>(numRecords);
2025         int position = 0;
2026         long now = SystemClock.elapsedRealtimeNanos();
2027         while (position < batchRecord.length) {
2028             byte[] address = extractBytes(batchRecord, position, 6);
2029             // TODO: remove temp hack.
2030             reverse(address);
2031             BluetoothDevice device = getAnonymousDevice(address);
2032             position += 6;
2033             // Skip address type.
2034             position++;
2035             // Skip tx power level.
2036             position++;
2037             int rssi = batchRecord[position++];
2038             long timestampNanos = now - parseTimestampNanos(extractBytes(batchRecord, position, 2));
2039             position += 2;
2040 
2041             // Combine advertise packet and scan response packet.
2042             int advertisePacketLen = batchRecord[position++];
2043             byte[] advertiseBytes = extractBytes(batchRecord, position, advertisePacketLen);
2044             position += advertisePacketLen;
2045             int scanResponsePacketLen = batchRecord[position++];
2046             byte[] scanResponseBytes = extractBytes(batchRecord, position, scanResponsePacketLen);
2047             position += scanResponsePacketLen;
2048             byte[] scanRecord = new byte[advertisePacketLen + scanResponsePacketLen];
2049             System.arraycopy(advertiseBytes, 0, scanRecord, 0, advertisePacketLen);
2050             System.arraycopy(scanResponseBytes, 0, scanRecord, advertisePacketLen,
2051                     scanResponsePacketLen);
2052             if (DBG) {
2053                 Log.d(TAG, "ScanRecord : " + Arrays.toString(scanRecord));
2054             }
2055             results.add(new ScanResult(device, ScanRecord.parseFromBytes(scanRecord), rssi,
2056                     timestampNanos));
2057         }
2058         return results;
2059     }
2060 
2061     // Reverse byte array.
reverse(byte[] address)2062     private void reverse(byte[] address) {
2063         int len = address.length;
2064         for (int i = 0; i < len / 2; ++i) {
2065             byte b = address[i];
2066             address[i] = address[len - 1 - i];
2067             address[len - 1 - i] = b;
2068         }
2069     }
2070 
2071     // Helper method to extract bytes from byte array.
extractBytes(byte[] scanRecord, int start, int length)2072     private static byte[] extractBytes(byte[] scanRecord, int start, int length) {
2073         byte[] bytes = new byte[length];
2074         System.arraycopy(scanRecord, start, bytes, 0, length);
2075         return bytes;
2076     }
2077 
2078     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
onBatchScanThresholdCrossed(int clientIf)2079     void onBatchScanThresholdCrossed(int clientIf) {
2080         if (DBG) {
2081             Log.d(TAG, "onBatchScanThresholdCrossed() - clientIf=" + clientIf);
2082         }
2083         flushPendingBatchResults(clientIf, getAttributionSource());
2084     }
2085 
createOnTrackAdvFoundLostObject(int clientIf, int advPktLen, byte[] advPkt, int scanRspLen, byte[] scanRsp, int filtIndex, int advState, int advInfoPresent, String address, int addrType, int txPower, int rssiValue, int timeStamp)2086     AdvtFilterOnFoundOnLostInfo createOnTrackAdvFoundLostObject(int clientIf, int advPktLen,
2087             byte[] advPkt, int scanRspLen, byte[] scanRsp, int filtIndex, int advState,
2088             int advInfoPresent, String address, int addrType, int txPower, int rssiValue,
2089             int timeStamp) {
2090 
2091         return new AdvtFilterOnFoundOnLostInfo(clientIf, advPktLen, advPkt, scanRspLen, scanRsp,
2092                 filtIndex, advState, advInfoPresent, address, addrType, txPower, rssiValue,
2093                 timeStamp);
2094     }
2095 
onTrackAdvFoundLost(AdvtFilterOnFoundOnLostInfo trackingInfo)2096     void onTrackAdvFoundLost(AdvtFilterOnFoundOnLostInfo trackingInfo) throws RemoteException {
2097         if (DBG) {
2098             Log.d(TAG, "onTrackAdvFoundLost() - scannerId= " + trackingInfo.getClientIf()
2099                     + " address = " + trackingInfo.getAddress() + " adv_state = "
2100                     + trackingInfo.getAdvState());
2101         }
2102 
2103         ScannerMap.App app = mScannerMap.getById(trackingInfo.getClientIf());
2104         if (app == null || (app.callback == null && app.info == null)) {
2105             Log.e(TAG, "app or callback is null");
2106             return;
2107         }
2108 
2109         BluetoothDevice device = getAnonymousDevice(trackingInfo.getAddress());
2110         int advertiserState = trackingInfo.getAdvState();
2111         ScanResult result =
2112                 new ScanResult(device, ScanRecord.parseFromBytes(trackingInfo.getResult()),
2113                         trackingInfo.getRSSIValue(), SystemClock.elapsedRealtimeNanos());
2114 
2115         for (ScanClient client : mScanManager.getRegularScanQueue()) {
2116             if (client.scannerId == trackingInfo.getClientIf()) {
2117                 ScanSettings settings = client.settings;
2118                 if ((advertiserState == ADVT_STATE_ONFOUND) && (
2119                         (settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH)
2120                                 != 0)) {
2121                     if (app.callback != null) {
2122                         app.callback.onFoundOrLost(true, result);
2123                     } else {
2124                         sendResultByPendingIntent(app.info, result,
2125                                 ScanSettings.CALLBACK_TYPE_FIRST_MATCH, client);
2126                     }
2127                 } else if ((advertiserState == ADVT_STATE_ONLOST) && (
2128                         (settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_MATCH_LOST)
2129                                 != 0)) {
2130                     if (app.callback != null) {
2131                         app.callback.onFoundOrLost(false, result);
2132                     } else {
2133                         sendResultByPendingIntent(app.info, result,
2134                                 ScanSettings.CALLBACK_TYPE_MATCH_LOST, client);
2135                     }
2136                 } else {
2137                     if (DBG) {
2138                         Log.d(TAG, "Not reporting onlost/onfound : " + advertiserState
2139                                 + " scannerId = " + client.scannerId + " callbackType "
2140                                 + settings.getCallbackType());
2141                     }
2142                 }
2143             }
2144         }
2145     }
2146 
onScanParamSetupCompleted(int status, int scannerId)2147     void onScanParamSetupCompleted(int status, int scannerId) throws RemoteException {
2148         ScannerMap.App app = mScannerMap.getById(scannerId);
2149         if (app == null || app.callback == null) {
2150             Log.e(TAG, "Advertise app or callback is null");
2151             return;
2152         }
2153         if (DBG) {
2154             Log.d(TAG, "onScanParamSetupCompleted : " + status);
2155         }
2156     }
2157 
2158     // callback from ScanManager for dispatch of errors apps.
onScanManagerErrorCallback(int scannerId, int errorCode)2159     void onScanManagerErrorCallback(int scannerId, int errorCode) throws RemoteException {
2160         ScannerMap.App app = mScannerMap.getById(scannerId);
2161         if (app == null || (app.callback == null && app.info == null)) {
2162             Log.e(TAG, "App or callback is null");
2163             return;
2164         }
2165         if (app.callback != null) {
2166             app.callback.onScanManagerErrorCallback(errorCode);
2167         } else {
2168             try {
2169                 sendErrorByPendingIntent(app.info, errorCode);
2170             } catch (PendingIntent.CanceledException e) {
2171                 Log.e(TAG, "Error sending error code via PendingIntent:" + e);
2172             }
2173         }
2174     }
2175 
onConfigureMTU(int connId, int status, int mtu)2176     void onConfigureMTU(int connId, int status, int mtu) throws RemoteException {
2177         String address = mClientMap.addressByConnId(connId);
2178 
2179         if (DBG) {
2180             Log.d(TAG,
2181                     "onConfigureMTU() address=" + address + ", status=" + status + ", mtu=" + mtu);
2182         }
2183 
2184         ClientMap.App app = mClientMap.getByConnId(connId);
2185         if (app != null) {
2186             app.callback.onConfigureMTU(address, mtu, status);
2187         }
2188     }
2189 
onClientCongestion(int connId, boolean congested)2190     void onClientCongestion(int connId, boolean congested) throws RemoteException {
2191         if (VDBG) {
2192             Log.d(TAG, "onClientCongestion() - connId=" + connId + ", congested=" + congested);
2193         }
2194 
2195         ClientMap.App app = mClientMap.getByConnId(connId);
2196 
2197         if (app != null) {
2198             app.isCongested = congested;
2199             while (!app.isCongested) {
2200                 CallbackInfo callbackInfo = app.popQueuedCallback();
2201                 if (callbackInfo == null) {
2202                     return;
2203                 }
2204                 app.callback.onCharacteristicWrite(callbackInfo.address, callbackInfo.status,
2205                         callbackInfo.handle);
2206             }
2207         }
2208     }
2209 
2210     /**************************************************************************
2211      * GATT Service functions - Shared CLIENT/SERVER
2212      *************************************************************************/
2213 
2214     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getDevicesMatchingConnectionStates( int[] states, AttributionSource attributionSource)2215     List<BluetoothDevice> getDevicesMatchingConnectionStates(
2216             int[] states, AttributionSource attributionSource) {
2217         if (!Utils.checkConnectPermissionForDataDelivery(
2218                 this, attributionSource,
2219                 "GattService getDevicesMatchingConnectionStates")) {
2220             return new ArrayList<>(0);
2221         }
2222 
2223         Map<BluetoothDevice, Integer> deviceStates = new HashMap<BluetoothDevice, Integer>();
2224 
2225         // Add paired LE devices
2226 
2227         BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
2228         for (BluetoothDevice device : bondedDevices) {
2229             if (getDeviceType(device) != AbstractionLayer.BT_DEVICE_TYPE_BREDR) {
2230                 deviceStates.put(device, BluetoothProfile.STATE_DISCONNECTED);
2231             }
2232         }
2233 
2234         // Add connected deviceStates
2235 
2236         Set<String> connectedDevices = new HashSet<String>();
2237         connectedDevices.addAll(mClientMap.getConnectedDevices());
2238         connectedDevices.addAll(mServerMap.getConnectedDevices());
2239 
2240         for (String address : connectedDevices) {
2241             BluetoothDevice device = getAnonymousDevice(address);
2242             if (device != null) {
2243                 deviceStates.put(device, BluetoothProfile.STATE_CONNECTED);
2244             }
2245         }
2246 
2247         // Create matching device sub-set
2248 
2249         List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>();
2250 
2251         for (Map.Entry<BluetoothDevice, Integer> entry : deviceStates.entrySet()) {
2252             for (int state : states) {
2253                 if (entry.getValue() == state) {
2254                     deviceList.add(entry.getKey());
2255                 }
2256             }
2257         }
2258 
2259         return deviceList;
2260     }
2261 
2262     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
registerScanner(IScannerCallback callback, WorkSource workSource, AttributionSource attributionSource)2263     void registerScanner(IScannerCallback callback, WorkSource workSource,
2264             AttributionSource attributionSource) throws RemoteException {
2265         if (!Utils.checkScanPermissionForDataDelivery(
2266                 this, attributionSource, "GattService registerScanner")) {
2267             return;
2268         }
2269 
2270         UUID uuid = UUID.randomUUID();
2271         if (DBG) {
2272             Log.d(TAG, "registerScanner() - UUID=" + uuid);
2273         }
2274 
2275         enforceImpersonatationPermissionIfNeeded(workSource);
2276 
2277         AppScanStats app = mScannerMap.getAppScanStatsByUid(Binder.getCallingUid());
2278         if (app != null && app.isScanningTooFrequently()
2279                 && !Utils.checkCallerHasPrivilegedPermission(this)) {
2280             Log.e(TAG, "App '" + app.appName + "' is scanning too frequently");
2281             callback.onScannerRegistered(ScanCallback.SCAN_FAILED_SCANNING_TOO_FREQUENTLY, -1);
2282             return;
2283         }
2284 
2285         mScannerMap.add(uuid, workSource, callback, null, this);
2286         mScanManager.registerScanner(uuid);
2287     }
2288 
2289     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
unregisterScanner(int scannerId, AttributionSource attributionSource)2290     void unregisterScanner(int scannerId, AttributionSource attributionSource) {
2291         if (!Utils.checkScanPermissionForDataDelivery(
2292                 this, attributionSource, "GattService unregisterScanner")) {
2293             return;
2294         }
2295 
2296         if (DBG) {
2297             Log.d(TAG, "unregisterScanner() - scannerId=" + scannerId);
2298         }
2299         mScannerMap.remove(scannerId);
2300         mScanManager.unregisterScanner(scannerId);
2301     }
2302 
getAssociatedDevices(String callingPackage, UserHandle userHandle)2303     private List<String> getAssociatedDevices(String callingPackage, UserHandle userHandle) {
2304         if (mCompanionManager == null) {
2305             return new ArrayList<String>();
2306         }
2307         long identity = Binder.clearCallingIdentity();
2308         try {
2309             return mCompanionManager.getAssociations(
2310                     callingPackage, userHandle.getIdentifier());
2311         } catch (SecurityException se) {
2312             // Not an app with associated devices
2313         } catch (RemoteException re) {
2314             Log.e(TAG, "Cannot reach companion device service", re);
2315         } catch (Exception e) {
2316             Log.e(TAG, "Cannot check device associations for " + callingPackage, e);
2317         } finally {
2318             Binder.restoreCallingIdentity(identity);
2319         }
2320         return new ArrayList<String>();
2321     }
2322 
2323     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
startScan(int scannerId, ScanSettings settings, List<ScanFilter> filters, List<List<ResultStorageDescriptor>> storages, AttributionSource attributionSource)2324     void startScan(int scannerId, ScanSettings settings, List<ScanFilter> filters,
2325             List<List<ResultStorageDescriptor>> storages, AttributionSource attributionSource) {
2326         if (DBG) {
2327             Log.d(TAG, "start scan with filters");
2328         }
2329 
2330         if (!Utils.checkScanPermissionForDataDelivery(
2331                 this, attributionSource, "Starting GATT scan.")) {
2332             return;
2333         }
2334 
2335         enforcePrivilegedPermissionIfNeeded(settings);
2336         String callingPackage = attributionSource.getPackageName();
2337         settings = enforceReportDelayFloor(settings);
2338         enforcePrivilegedPermissionIfNeeded(filters);
2339         final ScanClient scanClient = new ScanClient(scannerId, settings, filters, storages);
2340         scanClient.userHandle = UserHandle.of(UserHandle.getCallingUserId());
2341         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
2342         scanClient.eligibleForSanitizedExposureNotification =
2343                 callingPackage.equals(mExposureNotificationPackage);
2344 
2345         scanClient.hasDisavowedLocation =
2346                 Utils.hasDisavowedLocationForScan(this, attributionSource, isTestModeEnabled());
2347 
2348         scanClient.isQApp = Utils.isQApp(this, callingPackage);
2349         if (!scanClient.hasDisavowedLocation) {
2350             if (scanClient.isQApp) {
2351                 scanClient.hasLocationPermission = Utils.checkCallerHasFineLocation(
2352                         this, attributionSource, scanClient.userHandle);
2353             } else {
2354                 scanClient.hasLocationPermission = Utils.checkCallerHasCoarseOrFineLocation(
2355                         this, attributionSource, scanClient.userHandle);
2356             }
2357         }
2358         scanClient.hasNetworkSettingsPermission =
2359                 Utils.checkCallerHasNetworkSettingsPermission(this);
2360         scanClient.hasNetworkSetupWizardPermission =
2361                 Utils.checkCallerHasNetworkSetupWizardPermission(this);
2362         scanClient.hasScanWithoutLocationPermission =
2363                 Utils.checkCallerHasScanWithoutLocationPermission(this);
2364         scanClient.associatedDevices = getAssociatedDevices(callingPackage, scanClient.userHandle);
2365 
2366         AppScanStats app = mScannerMap.getAppScanStatsById(scannerId);
2367         ScannerMap.App cbApp = mScannerMap.getById(scannerId);
2368         if (app != null) {
2369             scanClient.stats = app;
2370             boolean isFilteredScan = (filters != null) && !filters.isEmpty();
2371             boolean isCallbackScan = false;
2372             if (cbApp != null) {
2373                 isCallbackScan = cbApp.callback != null;
2374             }
2375             app.recordScanStart(settings, filters, isFilteredScan, isCallbackScan, scannerId);
2376         }
2377 
2378         mScanManager.startScan(scanClient);
2379     }
2380 
2381     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
registerPiAndStartScan(PendingIntent pendingIntent, ScanSettings settings, List<ScanFilter> filters, AttributionSource attributionSource)2382     void registerPiAndStartScan(PendingIntent pendingIntent, ScanSettings settings,
2383             List<ScanFilter> filters, AttributionSource attributionSource) {
2384         if (DBG) {
2385             Log.d(TAG, "start scan with filters, for PendingIntent");
2386         }
2387 
2388         if (!Utils.checkScanPermissionForDataDelivery(
2389                 this, attributionSource, "Starting GATT scan.")) {
2390             return;
2391         }
2392         enforcePrivilegedPermissionIfNeeded(settings);
2393         settings = enforceReportDelayFloor(settings);
2394         enforcePrivilegedPermissionIfNeeded(filters);
2395         UUID uuid = UUID.randomUUID();
2396         if (DBG) {
2397             Log.d(TAG, "startScan(PI) - UUID=" + uuid);
2398         }
2399         String callingPackage = attributionSource.getPackageName();
2400         PendingIntentInfo piInfo = new PendingIntentInfo();
2401         piInfo.intent = pendingIntent;
2402         piInfo.settings = settings;
2403         piInfo.filters = filters;
2404         piInfo.callingPackage = callingPackage;
2405 
2406         // Don't start scan if the Pi scan already in mScannerMap.
2407         if (mScannerMap.getByContextInfo(piInfo) != null) {
2408             Log.d(TAG, "Don't startScan(PI) since the same Pi scan already in mScannerMap.");
2409             return;
2410         }
2411 
2412         ScannerMap.App app = mScannerMap.add(uuid, null, null, piInfo, this);
2413         app.mUserHandle = UserHandle.of(UserHandle.getCallingUserId());
2414         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
2415         app.mEligibleForSanitizedExposureNotification =
2416                 callingPackage.equals(mExposureNotificationPackage);
2417 
2418         app.mHasDisavowedLocation =
2419                 Utils.hasDisavowedLocationForScan(this, attributionSource, isTestModeEnabled());
2420 
2421         app.mIsQApp = Utils.isQApp(this, callingPackage);
2422         if (!app.mHasDisavowedLocation) {
2423             try {
2424                 if (app.mIsQApp) {
2425                     app.hasLocationPermission = Utils.checkCallerHasFineLocation(
2426                             this, attributionSource, app.mUserHandle);
2427                 } else {
2428                     app.hasLocationPermission = Utils.checkCallerHasCoarseOrFineLocation(
2429                             this, attributionSource, app.mUserHandle);
2430                 }
2431             } catch (SecurityException se) {
2432                 // No need to throw here. Just mark as not granted.
2433                 app.hasLocationPermission = false;
2434             }
2435         }
2436         app.mHasNetworkSettingsPermission =
2437                 Utils.checkCallerHasNetworkSettingsPermission(this);
2438         app.mHasNetworkSetupWizardPermission =
2439                 Utils.checkCallerHasNetworkSetupWizardPermission(this);
2440         app.mHasScanWithoutLocationPermission =
2441                 Utils.checkCallerHasScanWithoutLocationPermission(this);
2442         app.mAssociatedDevices = getAssociatedDevices(callingPackage, app.mUserHandle);
2443         mScanManager.registerScanner(uuid);
2444     }
2445 
continuePiStartScan(int scannerId, ScannerMap.App app)2446     void continuePiStartScan(int scannerId, ScannerMap.App app) {
2447         final PendingIntentInfo piInfo = app.info;
2448         final ScanClient scanClient =
2449                 new ScanClient(scannerId, piInfo.settings, piInfo.filters, null);
2450         scanClient.hasLocationPermission = app.hasLocationPermission;
2451         scanClient.userHandle = app.mUserHandle;
2452         scanClient.isQApp = app.mIsQApp;
2453         scanClient.eligibleForSanitizedExposureNotification =
2454                 app.mEligibleForSanitizedExposureNotification;
2455         scanClient.hasNetworkSettingsPermission = app.mHasNetworkSettingsPermission;
2456         scanClient.hasNetworkSetupWizardPermission = app.mHasNetworkSetupWizardPermission;
2457         scanClient.hasScanWithoutLocationPermission = app.mHasScanWithoutLocationPermission;
2458         scanClient.associatedDevices = app.mAssociatedDevices;
2459         scanClient.hasDisavowedLocation = app.mHasDisavowedLocation;
2460 
2461         AppScanStats scanStats = mScannerMap.getAppScanStatsById(scannerId);
2462         if (scanStats != null) {
2463             scanClient.stats = scanStats;
2464             boolean isFilteredScan = (piInfo.filters != null) && !piInfo.filters.isEmpty();
2465             scanStats.recordScanStart(
2466                     piInfo.settings, piInfo.filters, isFilteredScan, false, scannerId);
2467         }
2468 
2469         mScanManager.startScan(scanClient);
2470     }
2471 
2472     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
flushPendingBatchResults(int scannerId, AttributionSource attributionSource)2473     void flushPendingBatchResults(int scannerId, AttributionSource attributionSource) {
2474         if (!Utils.checkScanPermissionForDataDelivery(
2475                 this, attributionSource, "GattService flushPendingBatchResults")) {
2476             return;
2477         }
2478         if (DBG) {
2479             Log.d(TAG, "flushPendingBatchResults - scannerId=" + scannerId);
2480         }
2481         mScanManager.flushBatchScanResults(new ScanClient(scannerId));
2482     }
2483 
2484     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
stopScan(int scannerId, AttributionSource attributionSource)2485     void stopScan(int scannerId, AttributionSource attributionSource) {
2486         if (!Utils.checkScanPermissionForDataDelivery(
2487                 this, attributionSource, "GattService stopScan")) {
2488             return;
2489         }
2490         int scanQueueSize =
2491                 mScanManager.getBatchScanQueue().size() + mScanManager.getRegularScanQueue().size();
2492         if (DBG) {
2493             Log.d(TAG, "stopScan() - queue size =" + scanQueueSize);
2494         }
2495 
2496         AppScanStats app = null;
2497         app = mScannerMap.getAppScanStatsById(scannerId);
2498         if (app != null) {
2499             app.recordScanStop(scannerId);
2500         }
2501 
2502         mScanManager.stopScan(scannerId);
2503     }
2504 
2505     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
stopScan(PendingIntent intent, AttributionSource attributionSource)2506     void stopScan(PendingIntent intent, AttributionSource attributionSource) {
2507         if (!Utils.checkScanPermissionForDataDelivery(
2508                 this, attributionSource, "GattService stopScan")) {
2509             return;
2510         }
2511         PendingIntentInfo pii = new PendingIntentInfo();
2512         pii.intent = intent;
2513         ScannerMap.App app = mScannerMap.getByContextInfo(pii);
2514         if (VDBG) {
2515             Log.d(TAG, "stopScan(PendingIntent): app found = " + app);
2516         }
2517         if (app != null) {
2518             final int scannerId = app.id;
2519             stopScan(scannerId, attributionSource);
2520             // Also unregister the scanner
2521             unregisterScanner(scannerId, attributionSource);
2522         }
2523     }
2524 
2525     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
disconnectAll(AttributionSource attributionSource)2526     void disconnectAll(AttributionSource attributionSource) {
2527         if (DBG) {
2528             Log.d(TAG, "disconnectAll()");
2529         }
2530         Map<Integer, String> connMap = mClientMap.getConnectedMap();
2531         for (Map.Entry<Integer, String> entry : connMap.entrySet()) {
2532             if (DBG) {
2533                 Log.d(TAG, "disconnecting addr:" + entry.getValue());
2534             }
2535             clientDisconnect(entry.getKey(), entry.getValue(), attributionSource);
2536             //clientDisconnect(int clientIf, String address)
2537         }
2538     }
2539 
2540     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
unregAll(AttributionSource attributionSource)2541     void unregAll(AttributionSource attributionSource) {
2542         for (Integer appId : mClientMap.getAllAppsIds()) {
2543             if (DBG) {
2544                 Log.d(TAG, "unreg:" + appId);
2545             }
2546             unregisterClient(appId, attributionSource);
2547         }
2548     }
2549 
2550     /**************************************************************************
2551      * PERIODIC SCANNING
2552      *************************************************************************/
2553     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
registerSync(ScanResult scanResult, int skip, int timeout, IPeriodicAdvertisingCallback callback, AttributionSource attributionSource)2554     void registerSync(ScanResult scanResult, int skip, int timeout,
2555             IPeriodicAdvertisingCallback callback, AttributionSource attributionSource) {
2556         if (!Utils.checkScanPermissionForDataDelivery(
2557                 this, attributionSource, "GattService registerSync")) {
2558             return;
2559         }
2560         mPeriodicScanManager.startSync(scanResult, skip, timeout, callback);
2561     }
2562 
2563     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
unregisterSync( IPeriodicAdvertisingCallback callback, AttributionSource attributionSource)2564     void unregisterSync(
2565             IPeriodicAdvertisingCallback callback, AttributionSource attributionSource) {
2566         if (!Utils.checkScanPermissionForDataDelivery(
2567                 this, attributionSource, "GattService unregisterSync")) {
2568             return;
2569         }
2570         mPeriodicScanManager.stopSync(callback);
2571     }
2572 
2573     /**************************************************************************
2574      * ADVERTISING SET
2575      *************************************************************************/
2576     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
startAdvertisingSet(AdvertisingSetParameters parameters, AdvertiseData advertiseData, AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData, int duration, int maxExtAdvEvents, IAdvertisingSetCallback callback, AttributionSource attributionSource)2577     void startAdvertisingSet(AdvertisingSetParameters parameters, AdvertiseData advertiseData,
2578             AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters,
2579             AdvertiseData periodicData, int duration, int maxExtAdvEvents,
2580             IAdvertisingSetCallback callback, AttributionSource attributionSource) {
2581         if (!Utils.checkAdvertisePermissionForDataDelivery(
2582                 this, attributionSource, "GattService startAdvertisingSet")) {
2583             return;
2584         }
2585         mAdvertiseManager.startAdvertisingSet(parameters, advertiseData, scanResponse,
2586                 periodicParameters, periodicData, duration, maxExtAdvEvents, callback);
2587     }
2588 
2589     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
stopAdvertisingSet(IAdvertisingSetCallback callback, AttributionSource attributionSource)2590     void stopAdvertisingSet(IAdvertisingSetCallback callback, AttributionSource attributionSource) {
2591         if (!Utils.checkAdvertisePermissionForDataDelivery(
2592                 this, attributionSource, "GattService stopAdvertisingSet")) {
2593             return;
2594         }
2595         mAdvertiseManager.stopAdvertisingSet(callback);
2596     }
2597 
2598     @RequiresPermission(allOf = {
2599             android.Manifest.permission.BLUETOOTH_ADVERTISE,
2600             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
2601     })
getOwnAddress(int advertiserId, AttributionSource attributionSource)2602     void getOwnAddress(int advertiserId, AttributionSource attributionSource) {
2603         if (!Utils.checkAdvertisePermissionForDataDelivery(
2604                 this, attributionSource, "GattService getOwnAddress")) {
2605             return;
2606         }
2607         enforcePrivilegedPermission();
2608         mAdvertiseManager.getOwnAddress(advertiserId);
2609     }
2610 
2611     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
enableAdvertisingSet(int advertiserId, boolean enable, int duration, int maxExtAdvEvents, AttributionSource attributionSource)2612     void enableAdvertisingSet(int advertiserId, boolean enable, int duration, int maxExtAdvEvents,
2613             AttributionSource attributionSource) {
2614         if (!Utils.checkAdvertisePermissionForDataDelivery(
2615                 this, attributionSource, "GattService enableAdvertisingSet")) {
2616             return;
2617         }
2618         mAdvertiseManager.enableAdvertisingSet(advertiserId, enable, duration, maxExtAdvEvents);
2619     }
2620 
2621     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
setAdvertisingData( int advertiserId, AdvertiseData data, AttributionSource attributionSource)2622     void setAdvertisingData(
2623             int advertiserId, AdvertiseData data, AttributionSource attributionSource) {
2624         if (!Utils.checkAdvertisePermissionForDataDelivery(
2625                 this, attributionSource, "GattService setAdvertisingData")) {
2626             return;
2627         }
2628         mAdvertiseManager.setAdvertisingData(advertiserId, data);
2629     }
2630 
2631     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
setScanResponseData( int advertiserId, AdvertiseData data, AttributionSource attributionSource)2632     void setScanResponseData(
2633             int advertiserId, AdvertiseData data, AttributionSource attributionSource) {
2634         if (!Utils.checkAdvertisePermissionForDataDelivery(
2635                 this, attributionSource, "GattService setScanResponseData")) {
2636             return;
2637         }
2638         mAdvertiseManager.setScanResponseData(advertiserId, data);
2639     }
2640 
2641     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters, AttributionSource attributionSource)2642     void setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters,
2643             AttributionSource attributionSource) {
2644         if (!Utils.checkAdvertisePermissionForDataDelivery(
2645                 this, attributionSource, "GattService setAdvertisingParameters")) {
2646             return;
2647         }
2648         mAdvertiseManager.setAdvertisingParameters(advertiserId, parameters);
2649     }
2650 
2651     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
setPeriodicAdvertisingParameters(int advertiserId, PeriodicAdvertisingParameters parameters, AttributionSource attributionSource)2652     void setPeriodicAdvertisingParameters(int advertiserId,
2653             PeriodicAdvertisingParameters parameters, AttributionSource attributionSource) {
2654         if (!Utils.checkAdvertisePermissionForDataDelivery(
2655                 this, attributionSource, "GattService setPeriodicAdvertisingParameters")) {
2656             return;
2657         }
2658         mAdvertiseManager.setPeriodicAdvertisingParameters(advertiserId, parameters);
2659     }
2660 
2661     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
setPeriodicAdvertisingData( int advertiserId, AdvertiseData data, AttributionSource attributionSource)2662     void setPeriodicAdvertisingData(
2663             int advertiserId, AdvertiseData data, AttributionSource attributionSource) {
2664         if (!Utils.checkAdvertisePermissionForDataDelivery(
2665                 this, attributionSource, "GattService setPeriodicAdvertisingData")) {
2666             return;
2667         }
2668         mAdvertiseManager.setPeriodicAdvertisingData(advertiserId, data);
2669     }
2670 
2671     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
setPeriodicAdvertisingEnable( int advertiserId, boolean enable, AttributionSource attributionSource)2672     void setPeriodicAdvertisingEnable(
2673             int advertiserId, boolean enable, AttributionSource attributionSource) {
2674         if (!Utils.checkAdvertisePermissionForDataDelivery(
2675                 this, attributionSource, "GattService setPeriodicAdvertisingEnable")) {
2676             return;
2677         }
2678         mAdvertiseManager.setPeriodicAdvertisingEnable(advertiserId, enable);
2679     }
2680 
2681     /**************************************************************************
2682      * GATT Service functions - CLIENT
2683      *************************************************************************/
2684 
2685     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
registerClient(UUID uuid, IBluetoothGattCallback callback, boolean eatt_support, AttributionSource attributionSource)2686     void registerClient(UUID uuid, IBluetoothGattCallback callback, boolean eatt_support,
2687             AttributionSource attributionSource) {
2688         if (!Utils.checkConnectPermissionForDataDelivery(
2689                 this, attributionSource, "GattService registerClient")) {
2690             return;
2691         }
2692 
2693         if (DBG) {
2694             Log.d(TAG, "registerClient() - UUID=" + uuid);
2695         }
2696         mClientMap.add(uuid, null, callback, null, this);
2697         gattClientRegisterAppNative(uuid.getLeastSignificantBits(), uuid.getMostSignificantBits(), eatt_support);
2698     }
2699 
2700     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
unregisterClient(int clientIf, AttributionSource attributionSource)2701     void unregisterClient(int clientIf, AttributionSource attributionSource) {
2702         if (!Utils.checkConnectPermissionForDataDelivery(
2703                 this, attributionSource, "GattService unregisterClient")) {
2704             return;
2705         }
2706 
2707         if (DBG) {
2708             Log.d(TAG, "unregisterClient() - clientIf=" + clientIf);
2709         }
2710         mClientMap.remove(clientIf);
2711         gattClientUnregisterAppNative(clientIf);
2712     }
2713 
2714     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
clientConnect(int clientIf, String address, boolean isDirect, int transport, boolean opportunistic, int phy, AttributionSource attributionSource)2715     void clientConnect(int clientIf, String address, boolean isDirect, int transport,
2716             boolean opportunistic, int phy, AttributionSource attributionSource) {
2717         if (!Utils.checkConnectPermissionForDataDelivery(
2718                 this, attributionSource, "GattService clientConnect")) {
2719             return;
2720         }
2721 
2722         if (DBG) {
2723             Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect
2724                     + ", opportunistic=" + opportunistic + ", phy=" + phy);
2725         }
2726         gattClientConnectNative(clientIf, address, isDirect, transport, opportunistic, phy);
2727     }
2728 
2729     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
clientDisconnect(int clientIf, String address, AttributionSource attributionSource)2730     void clientDisconnect(int clientIf, String address, AttributionSource attributionSource) {
2731         if (!Utils.checkConnectPermissionForDataDelivery(
2732                 this, attributionSource, "GattService clientDisconnect")) {
2733             return;
2734         }
2735 
2736         Integer connId = mClientMap.connIdByAddress(clientIf, address);
2737         if (DBG) {
2738             Log.d(TAG, "clientDisconnect() - address=" + address + ", connId=" + connId);
2739         }
2740 
2741         gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0);
2742     }
2743 
2744     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
clientSetPreferredPhy(int clientIf, String address, int txPhy, int rxPhy, int phyOptions, AttributionSource attributionSource)2745     void clientSetPreferredPhy(int clientIf, String address, int txPhy, int rxPhy, int phyOptions,
2746             AttributionSource attributionSource) {
2747         if (!Utils.checkConnectPermissionForDataDelivery(
2748                 this, attributionSource, "GattService clientSetPreferredPhy")) {
2749             return;
2750         }
2751 
2752         Integer connId = mClientMap.connIdByAddress(clientIf, address);
2753         if (connId == null) {
2754             if (DBG) {
2755                 Log.d(TAG, "clientSetPreferredPhy() - no connection to " + address);
2756             }
2757             return;
2758         }
2759 
2760         if (DBG) {
2761             Log.d(TAG, "clientSetPreferredPhy() - address=" + address + ", connId=" + connId);
2762         }
2763         gattClientSetPreferredPhyNative(clientIf, address, txPhy, rxPhy, phyOptions);
2764     }
2765 
2766     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
clientReadPhy(int clientIf, String address, AttributionSource attributionSource)2767     void clientReadPhy(int clientIf, String address, AttributionSource attributionSource) {
2768         if (!Utils.checkConnectPermissionForDataDelivery(
2769                 this, attributionSource, "GattService clientReadPhy")) {
2770             return;
2771         }
2772 
2773         Integer connId = mClientMap.connIdByAddress(clientIf, address);
2774         if (connId == null) {
2775             if (DBG) {
2776                 Log.d(TAG, "clientReadPhy() - no connection to " + address);
2777             }
2778             return;
2779         }
2780 
2781         if (DBG) {
2782             Log.d(TAG, "clientReadPhy() - address=" + address + ", connId=" + connId);
2783         }
2784         gattClientReadPhyNative(clientIf, address);
2785     }
2786 
2787     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
numHwTrackFiltersAvailable(AttributionSource attributionSource)2788     int numHwTrackFiltersAvailable(AttributionSource attributionSource) {
2789         if (!Utils.checkConnectPermissionForDataDelivery(
2790                 this, attributionSource, "GattService numHwTrackFiltersAvailable")) {
2791             return 0;
2792         }
2793         return (AdapterService.getAdapterService().getTotalNumOfTrackableAdvertisements()
2794                 - mScanManager.getCurrentUsedTrackingAdvertisement());
2795     }
2796 
2797     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getRegisteredServiceUuids(AttributionSource attributionSource)2798     synchronized List<ParcelUuid> getRegisteredServiceUuids(AttributionSource attributionSource) {
2799         if (!Utils.checkConnectPermissionForDataDelivery(
2800                 this, attributionSource, "GattService getRegisteredServiceUuids")) {
2801             return new ArrayList<>(0);
2802         }
2803         List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
2804         for (HandleMap.Entry entry : mHandleMap.mEntries) {
2805             serviceUuids.add(new ParcelUuid(entry.uuid));
2806         }
2807         return serviceUuids;
2808     }
2809 
2810     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getConnectedDevices(AttributionSource attributionSource)2811     List<String> getConnectedDevices(AttributionSource attributionSource) {
2812         if (!Utils.checkConnectPermissionForDataDelivery(
2813                 this, attributionSource, "GattService getConnectedDevices")) {
2814             return new ArrayList<>(0);
2815         }
2816 
2817         Set<String> connectedDevAddress = new HashSet<String>();
2818         connectedDevAddress.addAll(mClientMap.getConnectedDevices());
2819         connectedDevAddress.addAll(mServerMap.getConnectedDevices());
2820         List<String> connectedDeviceList = new ArrayList<String>(connectedDevAddress);
2821         return connectedDeviceList;
2822     }
2823 
2824     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
refreshDevice(int clientIf, String address, AttributionSource attributionSource)2825     void refreshDevice(int clientIf, String address, AttributionSource attributionSource) {
2826         if (!Utils.checkConnectPermissionForDataDelivery(
2827                 this, attributionSource, "GattService refreshDevice")) {
2828             return;
2829         }
2830 
2831         if (DBG) {
2832             Log.d(TAG, "refreshDevice() - address=" + address);
2833         }
2834         gattClientRefreshNative(clientIf, address);
2835     }
2836 
2837     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
discoverServices(int clientIf, String address, AttributionSource attributionSource)2838     void discoverServices(int clientIf, String address, AttributionSource attributionSource) {
2839         if (!Utils.checkConnectPermissionForDataDelivery(
2840                 this, attributionSource, "GattService discoverServices")) {
2841             return;
2842         }
2843 
2844         Integer connId = mClientMap.connIdByAddress(clientIf, address);
2845         if (DBG) {
2846             Log.d(TAG, "discoverServices() - address=" + address + ", connId=" + connId);
2847         }
2848 
2849         if (connId != null) {
2850             gattClientSearchServiceNative(connId, true, 0, 0);
2851         } else {
2852             Log.e(TAG, "discoverServices() - No connection for " + address + "...");
2853         }
2854     }
2855 
2856     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
discoverServiceByUuid( int clientIf, String address, UUID uuid, AttributionSource attributionSource)2857     void discoverServiceByUuid(
2858             int clientIf, String address, UUID uuid, AttributionSource attributionSource) {
2859         if (!Utils.checkConnectPermissionForDataDelivery(
2860                 this, attributionSource, "GattService discoverServiceByUuid")) {
2861             return;
2862         }
2863 
2864         Integer connId = mClientMap.connIdByAddress(clientIf, address);
2865         if (connId != null) {
2866             gattClientDiscoverServiceByUuidNative(connId, uuid.getLeastSignificantBits(),
2867                     uuid.getMostSignificantBits());
2868         } else {
2869             Log.e(TAG, "discoverServiceByUuid() - No connection for " + address + "...");
2870         }
2871     }
2872 
2873     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
readCharacteristic(int clientIf, String address, int handle, int authReq, AttributionSource attributionSource)2874     void readCharacteristic(int clientIf, String address, int handle, int authReq,
2875             AttributionSource attributionSource) {
2876         if (!Utils.checkConnectPermissionForDataDelivery(
2877                 this, attributionSource, "GattService readCharacteristic")) {
2878             return;
2879         }
2880 
2881         if (VDBG) {
2882             Log.d(TAG, "readCharacteristic() - address=" + address);
2883         }
2884 
2885         Integer connId = mClientMap.connIdByAddress(clientIf, address);
2886         if (connId == null) {
2887             Log.e(TAG, "readCharacteristic() - No connection for " + address + "...");
2888             return;
2889         }
2890 
2891         if (!permissionCheck(connId, handle)) {
2892             Log.w(TAG, "readCharacteristic() - permission check failed!");
2893             return;
2894         }
2895 
2896         gattClientReadCharacteristicNative(connId, handle, authReq);
2897     }
2898 
2899     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
readUsingCharacteristicUuid(int clientIf, String address, UUID uuid, int startHandle, int endHandle, int authReq, AttributionSource attributionSource)2900     void readUsingCharacteristicUuid(int clientIf, String address, UUID uuid, int startHandle,
2901             int endHandle, int authReq, AttributionSource attributionSource) {
2902         if (!Utils.checkConnectPermissionForDataDelivery(
2903                 this, attributionSource, "GattService readUsingCharacteristicUuid")) {
2904             return;
2905         }
2906 
2907         if (VDBG) {
2908             Log.d(TAG, "readUsingCharacteristicUuid() - address=" + address);
2909         }
2910 
2911         Integer connId = mClientMap.connIdByAddress(clientIf, address);
2912         if (connId == null) {
2913             Log.e(TAG, "readUsingCharacteristicUuid() - No connection for " + address + "...");
2914             return;
2915         }
2916 
2917         if (!permissionCheck(uuid)) {
2918             Log.w(TAG, "readUsingCharacteristicUuid() - permission check failed!");
2919             return;
2920         }
2921 
2922         gattClientReadUsingCharacteristicUuidNative(connId, uuid.getLeastSignificantBits(),
2923                 uuid.getMostSignificantBits(), startHandle, endHandle, authReq);
2924     }
2925 
2926     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
writeCharacteristic(int clientIf, String address, int handle, int writeType, int authReq, byte[] value, AttributionSource attributionSource)2927     void writeCharacteristic(int clientIf, String address, int handle, int writeType, int authReq,
2928             byte[] value, AttributionSource attributionSource) {
2929         if (!Utils.checkConnectPermissionForDataDelivery(
2930                 this, attributionSource, "GattService writeCharacteristic")) {
2931             return;
2932         }
2933 
2934         if (VDBG) {
2935             Log.d(TAG, "writeCharacteristic() - address=" + address);
2936         }
2937 
2938         if (mReliableQueue.contains(address)) {
2939             writeType = 3; // Prepared write
2940         }
2941 
2942         Integer connId = mClientMap.connIdByAddress(clientIf, address);
2943         if (connId == null) {
2944             Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
2945             return;
2946         }
2947 
2948         if (!permissionCheck(connId, handle)) {
2949             Log.w(TAG, "writeCharacteristic() - permission check failed!");
2950             return;
2951         }
2952 
2953         gattClientWriteCharacteristicNative(connId, handle, writeType, authReq, value);
2954     }
2955 
2956     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
readDescriptor(int clientIf, String address, int handle, int authReq, AttributionSource attributionSource)2957     void readDescriptor(int clientIf, String address, int handle, int authReq,
2958             AttributionSource attributionSource) {
2959         if (!Utils.checkConnectPermissionForDataDelivery(
2960                 this, attributionSource, "GattService readDescriptor")) {
2961             return;
2962         }
2963 
2964         if (VDBG) {
2965             Log.d(TAG, "readDescriptor() - address=" + address);
2966         }
2967 
2968         Integer connId = mClientMap.connIdByAddress(clientIf, address);
2969         if (connId == null) {
2970             Log.e(TAG, "readDescriptor() - No connection for " + address + "...");
2971             return;
2972         }
2973 
2974         if (!permissionCheck(connId, handle)) {
2975             Log.w(TAG, "readDescriptor() - permission check failed!");
2976             return;
2977         }
2978 
2979         gattClientReadDescriptorNative(connId, handle, authReq);
2980     }
2981 
2982     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
writeDescriptor(int clientIf, String address, int handle, int authReq, byte[] value, AttributionSource attributionSource)2983     void writeDescriptor(int clientIf, String address, int handle, int authReq, byte[] value,
2984             AttributionSource attributionSource) {
2985         if (!Utils.checkConnectPermissionForDataDelivery(
2986                 this, attributionSource, "GattService writeDescriptor")) {
2987             return;
2988         }
2989         if (VDBG) {
2990             Log.d(TAG, "writeDescriptor() - address=" + address);
2991         }
2992 
2993         Integer connId = mClientMap.connIdByAddress(clientIf, address);
2994         if (connId == null) {
2995             Log.e(TAG, "writeDescriptor() - No connection for " + address + "...");
2996             return;
2997         }
2998 
2999         if (!permissionCheck(connId, handle)) {
3000             Log.w(TAG, "writeDescriptor() - permission check failed!");
3001             return;
3002         }
3003 
3004         gattClientWriteDescriptorNative(connId, handle, authReq, value);
3005     }
3006 
3007     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
beginReliableWrite(int clientIf, String address, AttributionSource attributionSource)3008     void beginReliableWrite(int clientIf, String address, AttributionSource attributionSource) {
3009         if (!Utils.checkConnectPermissionForDataDelivery(
3010                 this, attributionSource, "GattService beginReliableWrite")) {
3011             return;
3012         }
3013 
3014         if (DBG) {
3015             Log.d(TAG, "beginReliableWrite() - address=" + address);
3016         }
3017         mReliableQueue.add(address);
3018     }
3019 
3020     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
endReliableWrite( int clientIf, String address, boolean execute, AttributionSource attributionSource)3021     void endReliableWrite(
3022             int clientIf, String address, boolean execute, AttributionSource attributionSource) {
3023         if (!Utils.checkConnectPermissionForDataDelivery(
3024                 this, attributionSource, "GattService endReliableWrite")) {
3025             return;
3026         }
3027 
3028         if (DBG) {
3029             Log.d(TAG, "endReliableWrite() - address=" + address + " execute: " + execute);
3030         }
3031         mReliableQueue.remove(address);
3032 
3033         Integer connId = mClientMap.connIdByAddress(clientIf, address);
3034         if (connId != null) {
3035             gattClientExecuteWriteNative(connId, execute);
3036         }
3037     }
3038 
3039     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
registerForNotification(int clientIf, String address, int handle, boolean enable, AttributionSource attributionSource)3040     void registerForNotification(int clientIf, String address, int handle, boolean enable,
3041             AttributionSource attributionSource) {
3042         if (!Utils.checkConnectPermissionForDataDelivery(
3043                 this, attributionSource, "GattService registerForNotification")) {
3044             return;
3045         }
3046 
3047         if (DBG) {
3048             Log.d(TAG, "registerForNotification() - address=" + address + " enable: " + enable);
3049         }
3050 
3051         Integer connId = mClientMap.connIdByAddress(clientIf, address);
3052         if (connId == null) {
3053             Log.e(TAG, "registerForNotification() - No connection for " + address + "...");
3054             return;
3055         }
3056 
3057         if (!permissionCheck(connId, handle)) {
3058             Log.w(TAG, "registerForNotification() - permission check failed!");
3059             return;
3060         }
3061 
3062         gattClientRegisterForNotificationsNative(clientIf, address, handle, enable);
3063     }
3064 
3065     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
readRemoteRssi(int clientIf, String address, AttributionSource attributionSource)3066     void readRemoteRssi(int clientIf, String address, AttributionSource attributionSource) {
3067         if (!Utils.checkConnectPermissionForDataDelivery(
3068                 this, attributionSource, "GattService readRemoteRssi")) {
3069             return;
3070         }
3071 
3072         if (DBG) {
3073             Log.d(TAG, "readRemoteRssi() - address=" + address);
3074         }
3075         gattClientReadRemoteRssiNative(clientIf, address);
3076     }
3077 
3078     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
configureMTU(int clientIf, String address, int mtu, AttributionSource attributionSource)3079     void configureMTU(int clientIf, String address, int mtu, AttributionSource attributionSource) {
3080         if (!Utils.checkConnectPermissionForDataDelivery(
3081                 this, attributionSource, "GattService configureMTU")) {
3082             return;
3083         }
3084 
3085         if (DBG) {
3086             Log.d(TAG, "configureMTU() - address=" + address + " mtu=" + mtu);
3087         }
3088         Integer connId = mClientMap.connIdByAddress(clientIf, address);
3089         if (connId != null) {
3090             gattClientConfigureMTUNative(connId, mtu);
3091         } else {
3092             Log.e(TAG, "configureMTU() - No connection for " + address + "...");
3093         }
3094     }
3095 
3096     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
connectionParameterUpdate(int clientIf, String address, int connectionPriority, AttributionSource attributionSource)3097     void connectionParameterUpdate(int clientIf, String address, int connectionPriority,
3098             AttributionSource attributionSource) {
3099         if (!Utils.checkConnectPermissionForDataDelivery(
3100                 this, attributionSource, "GattService connectionParameterUpdate")) {
3101             return;
3102         }
3103 
3104         int minInterval;
3105         int maxInterval;
3106 
3107         // Peripheral latency
3108         int latency;
3109 
3110         // Link supervision timeout is measured in N * 10ms
3111         int timeout = 500; // 5s
3112 
3113         switch (connectionPriority) {
3114             case BluetoothGatt.CONNECTION_PRIORITY_HIGH:
3115                 minInterval = getResources().getInteger(R.integer.gatt_high_priority_min_interval);
3116                 maxInterval = getResources().getInteger(R.integer.gatt_high_priority_max_interval);
3117                 latency = getResources().getInteger(R.integer.gatt_high_priority_latency);
3118                 break;
3119 
3120             case BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER:
3121                 minInterval = getResources().getInteger(R.integer.gatt_low_power_min_interval);
3122                 maxInterval = getResources().getInteger(R.integer.gatt_low_power_max_interval);
3123                 latency = getResources().getInteger(R.integer.gatt_low_power_latency);
3124                 break;
3125 
3126             default:
3127                 // Using the values for CONNECTION_PRIORITY_BALANCED.
3128                 minInterval =
3129                         getResources().getInteger(R.integer.gatt_balanced_priority_min_interval);
3130                 maxInterval =
3131                         getResources().getInteger(R.integer.gatt_balanced_priority_max_interval);
3132                 latency = getResources().getInteger(R.integer.gatt_balanced_priority_latency);
3133                 break;
3134         }
3135 
3136         if (DBG) {
3137             Log.d(TAG, "connectionParameterUpdate() - address=" + address + "params="
3138                     + connectionPriority + " interval=" + minInterval + "/" + maxInterval);
3139         }
3140         gattConnectionParameterUpdateNative(clientIf, address, minInterval, maxInterval, latency,
3141                 timeout, 0, 0);
3142     }
3143 
3144     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
leConnectionUpdate(int clientIf, String address, int minInterval, int maxInterval, int peripheralLatency, int supervisionTimeout, int minConnectionEventLen, int maxConnectionEventLen, AttributionSource attributionSource)3145     void leConnectionUpdate(int clientIf, String address, int minInterval,
3146                             int maxInterval, int peripheralLatency,
3147                             int supervisionTimeout, int minConnectionEventLen,
3148                             int maxConnectionEventLen, AttributionSource attributionSource) {
3149         if (!Utils.checkConnectPermissionForDataDelivery(
3150                 this, attributionSource, "GattService leConnectionUpdate")) {
3151             return;
3152         }
3153 
3154         if (DBG) {
3155             Log.d(TAG, "leConnectionUpdate() - address=" + address + ", intervals="
3156                         + minInterval + "/" + maxInterval + ", latency=" + peripheralLatency
3157                         + ", timeout=" + supervisionTimeout + "msec" + ", min_ce="
3158                         + minConnectionEventLen + ", max_ce=" + maxConnectionEventLen);
3159 
3160 
3161         }
3162         gattConnectionParameterUpdateNative(clientIf, address, minInterval, maxInterval,
3163                                             peripheralLatency, supervisionTimeout,
3164                                             minConnectionEventLen, maxConnectionEventLen);
3165     }
3166 
3167     /**************************************************************************
3168      * Callback functions - SERVER
3169      *************************************************************************/
3170 
onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb)3171     void onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb)
3172             throws RemoteException {
3173 
3174         UUID uuid = new UUID(uuidMsb, uuidLsb);
3175         if (DBG) {
3176             Log.d(TAG, "onServerRegistered() - UUID=" + uuid + ", serverIf=" + serverIf);
3177         }
3178         ServerMap.App app = mServerMap.getByUuid(uuid);
3179         if (app != null) {
3180             app.id = serverIf;
3181             app.linkToDeath(new ServerDeathRecipient(serverIf));
3182             app.callback.onServerRegistered(status, serverIf);
3183         }
3184     }
3185 
onServiceAdded(int status, int serverIf, List<GattDbElement> service)3186     void onServiceAdded(int status, int serverIf, List<GattDbElement> service)
3187             throws RemoteException {
3188         if (DBG) {
3189             Log.d(TAG, "onServiceAdded(), status=" + status);
3190         }
3191 
3192         if (status != 0) {
3193             return;
3194         }
3195 
3196         GattDbElement svcEl = service.get(0);
3197         int srvcHandle = svcEl.attributeHandle;
3198 
3199         BluetoothGattService svc = null;
3200 
3201         for (GattDbElement el : service) {
3202             if (el.type == GattDbElement.TYPE_PRIMARY_SERVICE) {
3203                 mHandleMap.addService(serverIf, el.attributeHandle, el.uuid,
3204                         BluetoothGattService.SERVICE_TYPE_PRIMARY, 0, false);
3205                 svc = new BluetoothGattService(svcEl.uuid, svcEl.attributeHandle,
3206                         BluetoothGattService.SERVICE_TYPE_PRIMARY);
3207             } else if (el.type == GattDbElement.TYPE_SECONDARY_SERVICE) {
3208                 mHandleMap.addService(serverIf, el.attributeHandle, el.uuid,
3209                         BluetoothGattService.SERVICE_TYPE_SECONDARY, 0, false);
3210                 svc = new BluetoothGattService(svcEl.uuid, svcEl.attributeHandle,
3211                         BluetoothGattService.SERVICE_TYPE_SECONDARY);
3212             } else if (el.type == GattDbElement.TYPE_CHARACTERISTIC) {
3213                 mHandleMap.addCharacteristic(serverIf, el.attributeHandle, el.uuid, srvcHandle);
3214                 svc.addCharacteristic(
3215                         new BluetoothGattCharacteristic(el.uuid, el.attributeHandle, el.properties,
3216                                 el.permissions));
3217             } else if (el.type == GattDbElement.TYPE_DESCRIPTOR) {
3218                 mHandleMap.addDescriptor(serverIf, el.attributeHandle, el.uuid, srvcHandle);
3219                 List<BluetoothGattCharacteristic> chars = svc.getCharacteristics();
3220                 chars.get(chars.size() - 1)
3221                         .addDescriptor(new BluetoothGattDescriptor(el.uuid, el.attributeHandle,
3222                                 el.permissions));
3223             }
3224         }
3225         mHandleMap.setStarted(serverIf, srvcHandle, true);
3226 
3227         ServerMap.App app = mServerMap.getById(serverIf);
3228         if (app != null) {
3229             app.callback.onServiceAdded(status, svc);
3230         }
3231     }
3232 
onServiceStopped(int status, int serverIf, int srvcHandle)3233     void onServiceStopped(int status, int serverIf, int srvcHandle) throws RemoteException {
3234         if (DBG) {
3235             Log.d(TAG, "onServiceStopped() srvcHandle=" + srvcHandle + ", status=" + status);
3236         }
3237         if (status == 0) {
3238             mHandleMap.setStarted(serverIf, srvcHandle, false);
3239         }
3240         stopNextService(serverIf, status);
3241     }
3242 
onServiceDeleted(int status, int serverIf, int srvcHandle)3243     void onServiceDeleted(int status, int serverIf, int srvcHandle) {
3244         if (DBG) {
3245             Log.d(TAG, "onServiceDeleted() srvcHandle=" + srvcHandle + ", status=" + status);
3246         }
3247         mHandleMap.deleteService(serverIf, srvcHandle);
3248     }
3249 
onClientConnected(String address, boolean connected, int connId, int serverIf)3250     void onClientConnected(String address, boolean connected, int connId, int serverIf)
3251             throws RemoteException {
3252 
3253         if (DBG) {
3254             Log.d(TAG,
3255                     "onClientConnected() connId=" + connId + ", address=" + address + ", connected="
3256                             + connected);
3257         }
3258 
3259         ServerMap.App app = mServerMap.getById(serverIf);
3260         if (app == null) {
3261             return;
3262         }
3263 
3264         if (connected) {
3265             mServerMap.addConnection(serverIf, connId, address);
3266         } else {
3267             mServerMap.removeConnection(serverIf, connId);
3268         }
3269 
3270         app.callback.onServerConnectionState((byte) 0, serverIf, connected, address);
3271     }
3272 
onServerReadCharacteristic(String address, int connId, int transId, int handle, int offset, boolean isLong)3273     void onServerReadCharacteristic(String address, int connId, int transId, int handle, int offset,
3274             boolean isLong) throws RemoteException {
3275         if (VDBG) {
3276             Log.d(TAG, "onServerReadCharacteristic() connId=" + connId + ", address=" + address
3277                     + ", handle=" + handle + ", requestId=" + transId + ", offset=" + offset);
3278         }
3279 
3280         HandleMap.Entry entry = mHandleMap.getByHandle(handle);
3281         if (entry == null) {
3282             return;
3283         }
3284 
3285         mHandleMap.addRequest(transId, handle);
3286 
3287         ServerMap.App app = mServerMap.getById(entry.serverIf);
3288         if (app == null) {
3289             return;
3290         }
3291 
3292         app.callback.onCharacteristicReadRequest(address, transId, offset, isLong, handle);
3293     }
3294 
onServerReadDescriptor(String address, int connId, int transId, int handle, int offset, boolean isLong)3295     void onServerReadDescriptor(String address, int connId, int transId, int handle, int offset,
3296             boolean isLong) throws RemoteException {
3297         if (VDBG) {
3298             Log.d(TAG, "onServerReadDescriptor() connId=" + connId + ", address=" + address
3299                     + ", handle=" + handle + ", requestId=" + transId + ", offset=" + offset);
3300         }
3301 
3302         HandleMap.Entry entry = mHandleMap.getByHandle(handle);
3303         if (entry == null) {
3304             return;
3305         }
3306 
3307         mHandleMap.addRequest(transId, handle);
3308 
3309         ServerMap.App app = mServerMap.getById(entry.serverIf);
3310         if (app == null) {
3311             return;
3312         }
3313 
3314         app.callback.onDescriptorReadRequest(address, transId, offset, isLong, handle);
3315     }
3316 
onServerWriteCharacteristic(String address, int connId, int transId, int handle, int offset, int length, boolean needRsp, boolean isPrep, byte[] data)3317     void onServerWriteCharacteristic(String address, int connId, int transId, int handle,
3318             int offset, int length, boolean needRsp, boolean isPrep, byte[] data)
3319             throws RemoteException {
3320         if (VDBG) {
3321             Log.d(TAG, "onServerWriteCharacteristic() connId=" + connId + ", address=" + address
3322                     + ", handle=" + handle + ", requestId=" + transId + ", isPrep=" + isPrep
3323                     + ", offset=" + offset);
3324         }
3325 
3326         HandleMap.Entry entry = mHandleMap.getByHandle(handle);
3327         if (entry == null) {
3328             return;
3329         }
3330 
3331         mHandleMap.addRequest(transId, handle);
3332 
3333         ServerMap.App app = mServerMap.getById(entry.serverIf);
3334         if (app == null) {
3335             return;
3336         }
3337 
3338         app.callback.onCharacteristicWriteRequest(address, transId, offset, length, isPrep, needRsp,
3339                 handle, data);
3340     }
3341 
onServerWriteDescriptor(String address, int connId, int transId, int handle, int offset, int length, boolean needRsp, boolean isPrep, byte[] data)3342     void onServerWriteDescriptor(String address, int connId, int transId, int handle, int offset,
3343             int length, boolean needRsp, boolean isPrep, byte[] data) throws RemoteException {
3344         if (VDBG) {
3345             Log.d(TAG, "onAttributeWrite() connId=" + connId + ", address=" + address + ", handle="
3346                     + handle + ", requestId=" + transId + ", isPrep=" + isPrep + ", offset="
3347                     + offset);
3348         }
3349 
3350         HandleMap.Entry entry = mHandleMap.getByHandle(handle);
3351         if (entry == null) {
3352             return;
3353         }
3354 
3355         mHandleMap.addRequest(transId, handle);
3356 
3357         ServerMap.App app = mServerMap.getById(entry.serverIf);
3358         if (app == null) {
3359             return;
3360         }
3361 
3362         app.callback.onDescriptorWriteRequest(address, transId, offset, length, isPrep, needRsp,
3363                 handle, data);
3364     }
3365 
onExecuteWrite(String address, int connId, int transId, int execWrite)3366     void onExecuteWrite(String address, int connId, int transId, int execWrite)
3367             throws RemoteException {
3368         if (DBG) {
3369             Log.d(TAG, "onExecuteWrite() connId=" + connId + ", address=" + address + ", transId="
3370                     + transId);
3371         }
3372 
3373         ServerMap.App app = mServerMap.getByConnId(connId);
3374         if (app == null) {
3375             return;
3376         }
3377 
3378         app.callback.onExecuteWrite(address, transId, execWrite == 1);
3379     }
3380 
onResponseSendCompleted(int status, int attrHandle)3381     void onResponseSendCompleted(int status, int attrHandle) {
3382         if (DBG) {
3383             Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle);
3384         }
3385     }
3386 
onNotificationSent(int connId, int status)3387     void onNotificationSent(int connId, int status) throws RemoteException {
3388         if (VDBG) {
3389             Log.d(TAG, "onNotificationSent() connId=" + connId + ", status=" + status);
3390         }
3391 
3392         String address = mServerMap.addressByConnId(connId);
3393         if (address == null) {
3394             return;
3395         }
3396 
3397         ServerMap.App app = mServerMap.getByConnId(connId);
3398         if (app == null) {
3399             return;
3400         }
3401 
3402         if (!app.isCongested) {
3403             app.callback.onNotificationSent(address, status);
3404         } else {
3405             if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) {
3406                 status = BluetoothGatt.GATT_SUCCESS;
3407             }
3408             app.queueCallback(new CallbackInfo(address, status));
3409         }
3410     }
3411 
onServerCongestion(int connId, boolean congested)3412     void onServerCongestion(int connId, boolean congested) throws RemoteException {
3413         if (DBG) {
3414             Log.d(TAG, "onServerCongestion() - connId=" + connId + ", congested=" + congested);
3415         }
3416 
3417         ServerMap.App app = mServerMap.getByConnId(connId);
3418         if (app == null) {
3419             return;
3420         }
3421 
3422         app.isCongested = congested;
3423         while (!app.isCongested) {
3424             CallbackInfo callbackInfo = app.popQueuedCallback();
3425             if (callbackInfo == null) {
3426                 return;
3427             }
3428             app.callback.onNotificationSent(callbackInfo.address, callbackInfo.status);
3429         }
3430     }
3431 
onMtuChanged(int connId, int mtu)3432     void onMtuChanged(int connId, int mtu) throws RemoteException {
3433         if (DBG) {
3434             Log.d(TAG, "onMtuChanged() - connId=" + connId + ", mtu=" + mtu);
3435         }
3436 
3437         String address = mServerMap.addressByConnId(connId);
3438         if (address == null) {
3439             return;
3440         }
3441 
3442         ServerMap.App app = mServerMap.getByConnId(connId);
3443         if (app == null) {
3444             return;
3445         }
3446 
3447         app.callback.onMtuChanged(address, mtu);
3448     }
3449 
3450     /**************************************************************************
3451      * GATT Service functions - SERVER
3452      *************************************************************************/
3453 
3454     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
registerServer(UUID uuid, IBluetoothGattServerCallback callback, boolean eatt_support, AttributionSource attributionSource)3455     void registerServer(UUID uuid, IBluetoothGattServerCallback callback, boolean eatt_support,
3456             AttributionSource attributionSource) {
3457         if (!Utils.checkConnectPermissionForDataDelivery(
3458                 this, attributionSource, "GattService registerServer")) {
3459             return;
3460         }
3461 
3462         if (DBG) {
3463             Log.d(TAG, "registerServer() - UUID=" + uuid);
3464         }
3465         mServerMap.add(uuid, null, callback, null, this);
3466         gattServerRegisterAppNative(uuid.getLeastSignificantBits(), uuid.getMostSignificantBits(), eatt_support);
3467     }
3468 
3469     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
unregisterServer(int serverIf, AttributionSource attributionSource)3470     void unregisterServer(int serverIf, AttributionSource attributionSource) {
3471         if (!Utils.checkConnectPermissionForDataDelivery(
3472                 this, attributionSource, "GattService unregisterServer")) {
3473             return;
3474         }
3475 
3476         if (DBG) {
3477             Log.d(TAG, "unregisterServer() - serverIf=" + serverIf);
3478         }
3479 
3480         deleteServices(serverIf);
3481 
3482         mServerMap.remove(serverIf);
3483         gattServerUnregisterAppNative(serverIf);
3484     }
3485 
3486     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
serverConnect(int serverIf, String address, boolean isDirect, int transport, AttributionSource attributionSource)3487     void serverConnect(int serverIf, String address, boolean isDirect, int transport,
3488             AttributionSource attributionSource) {
3489         if (!Utils.checkConnectPermissionForDataDelivery(
3490                 this, attributionSource, "GattService serverConnect")) {
3491             return;
3492         }
3493 
3494         if (DBG) {
3495             Log.d(TAG, "serverConnect() - address=" + address);
3496         }
3497         gattServerConnectNative(serverIf, address, isDirect, transport);
3498     }
3499 
3500     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
serverDisconnect(int serverIf, String address, AttributionSource attributionSource)3501     void serverDisconnect(int serverIf, String address, AttributionSource attributionSource) {
3502         if (!Utils.checkConnectPermissionForDataDelivery(
3503                 this, attributionSource, "GattService serverDisconnect")) {
3504             return;
3505         }
3506 
3507         Integer connId = mServerMap.connIdByAddress(serverIf, address);
3508         if (DBG) {
3509             Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId);
3510         }
3511 
3512         gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0);
3513     }
3514 
3515     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
serverSetPreferredPhy(int serverIf, String address, int txPhy, int rxPhy, int phyOptions, AttributionSource attributionSource)3516     void serverSetPreferredPhy(int serverIf, String address, int txPhy, int rxPhy, int phyOptions,
3517             AttributionSource attributionSource) {
3518         if (!Utils.checkConnectPermissionForDataDelivery(
3519                 this, attributionSource, "GattService serverSetPreferredPhy")) {
3520             return;
3521         }
3522 
3523         Integer connId = mServerMap.connIdByAddress(serverIf, address);
3524         if (connId == null) {
3525             if (DBG) {
3526                 Log.d(TAG, "serverSetPreferredPhy() - no connection to " + address);
3527             }
3528             return;
3529         }
3530 
3531         if (DBG) {
3532             Log.d(TAG, "serverSetPreferredPhy() - address=" + address + ", connId=" + connId);
3533         }
3534         gattServerSetPreferredPhyNative(serverIf, address, txPhy, rxPhy, phyOptions);
3535     }
3536 
3537     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
serverReadPhy(int serverIf, String address, AttributionSource attributionSource)3538     void serverReadPhy(int serverIf, String address, AttributionSource attributionSource) {
3539         if (!Utils.checkConnectPermissionForDataDelivery(
3540                 this, attributionSource, "GattService serverReadPhy")) {
3541             return;
3542         }
3543 
3544         Integer connId = mServerMap.connIdByAddress(serverIf, address);
3545         if (connId == null) {
3546             if (DBG) {
3547                 Log.d(TAG, "serverReadPhy() - no connection to " + address);
3548             }
3549             return;
3550         }
3551 
3552         if (DBG) {
3553             Log.d(TAG, "serverReadPhy() - address=" + address + ", connId=" + connId);
3554         }
3555         gattServerReadPhyNative(serverIf, address);
3556     }
3557 
3558     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
addService( int serverIf, BluetoothGattService service, AttributionSource attributionSource)3559     void addService(
3560             int serverIf, BluetoothGattService service, AttributionSource attributionSource) {
3561         if (!Utils.checkConnectPermissionForDataDelivery(
3562                 this, attributionSource, "GattService addService")) {
3563             return;
3564         }
3565 
3566         if (DBG) {
3567             Log.d(TAG, "addService() - uuid=" + service.getUuid());
3568         }
3569 
3570         List<GattDbElement> db = new ArrayList<GattDbElement>();
3571 
3572         if (service.getType() == BluetoothGattService.SERVICE_TYPE_PRIMARY) {
3573             db.add(GattDbElement.createPrimaryService(service.getUuid()));
3574         } else {
3575             db.add(GattDbElement.createSecondaryService(service.getUuid()));
3576         }
3577 
3578         for (BluetoothGattService includedService : service.getIncludedServices()) {
3579             int inclSrvcHandle = includedService.getInstanceId();
3580 
3581             if (mHandleMap.checkServiceExists(includedService.getUuid(), inclSrvcHandle)) {
3582                 db.add(GattDbElement.createIncludedService(inclSrvcHandle));
3583             } else {
3584                 Log.e(TAG,
3585                         "included service with UUID " + includedService.getUuid() + " not found!");
3586             }
3587         }
3588 
3589         for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
3590             int permission =
3591                     ((characteristic.getKeySize() - 7) << 12) + characteristic.getPermissions();
3592             db.add(GattDbElement.createCharacteristic(characteristic.getUuid(),
3593                     characteristic.getProperties(), permission));
3594 
3595             for (BluetoothGattDescriptor descriptor : characteristic.getDescriptors()) {
3596                 permission =
3597                         ((characteristic.getKeySize() - 7) << 12) + descriptor.getPermissions();
3598                 db.add(GattDbElement.createDescriptor(descriptor.getUuid(), permission));
3599             }
3600         }
3601 
3602         gattServerAddServiceNative(serverIf, db);
3603     }
3604 
3605     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
removeService(int serverIf, int handle, AttributionSource attributionSource)3606     void removeService(int serverIf, int handle, AttributionSource attributionSource) {
3607         if (!Utils.checkConnectPermissionForDataDelivery(
3608                 this, attributionSource, "GattService removeService")) {
3609             return;
3610         }
3611 
3612         if (DBG) {
3613             Log.d(TAG, "removeService() - handle=" + handle);
3614         }
3615 
3616         gattServerDeleteServiceNative(serverIf, handle);
3617     }
3618 
3619     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
clearServices(int serverIf, AttributionSource attributionSource)3620     void clearServices(int serverIf, AttributionSource attributionSource) {
3621         if (!Utils.checkConnectPermissionForDataDelivery(
3622                 this, attributionSource, "GattService clearServices")) {
3623             return;
3624         }
3625 
3626         if (DBG) {
3627             Log.d(TAG, "clearServices()");
3628         }
3629         deleteServices(serverIf);
3630     }
3631 
3632     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
sendResponse(int serverIf, String address, int requestId, int status, int offset, byte[] value, AttributionSource attributionSource)3633     void sendResponse(int serverIf, String address, int requestId, int status, int offset,
3634             byte[] value, AttributionSource attributionSource) {
3635         if (!Utils.checkConnectPermissionForDataDelivery(
3636                 this, attributionSource, "GattService sendResponse")) {
3637             return;
3638         }
3639 
3640         if (VDBG) {
3641             Log.d(TAG, "sendResponse() - address=" + address);
3642         }
3643 
3644         int handle = 0;
3645         HandleMap.Entry entry = mHandleMap.getByRequestId(requestId);
3646         if (entry != null) {
3647             handle = entry.handle;
3648         }
3649 
3650         Integer connId = mServerMap.connIdByAddress(serverIf, address);
3651         gattServerSendResponseNative(serverIf, connId != null ? connId : 0, requestId,
3652                 (byte) status, handle, offset, value, (byte) 0);
3653         mHandleMap.deleteRequest(requestId);
3654     }
3655 
3656     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
sendNotification(int serverIf, String address, int handle, boolean confirm, byte[] value, AttributionSource attributionSource)3657     void sendNotification(int serverIf, String address, int handle, boolean confirm, byte[] value,
3658             AttributionSource attributionSource) {
3659         if (!Utils.checkConnectPermissionForDataDelivery(
3660                 this, attributionSource, "GattService sendNotification")) {
3661             return;
3662         }
3663 
3664         if (VDBG) {
3665             Log.d(TAG, "sendNotification() - address=" + address + " handle=" + handle);
3666         }
3667 
3668         Integer connId = mServerMap.connIdByAddress(serverIf, address);
3669         if (connId == null || connId == 0) {
3670             return;
3671         }
3672 
3673         if (confirm) {
3674             gattServerSendIndicationNative(serverIf, handle, connId, value);
3675         } else {
3676             gattServerSendNotificationNative(serverIf, handle, connId, value);
3677         }
3678     }
3679 
3680 
3681     /**************************************************************************
3682      * Private functions
3683      *************************************************************************/
3684 
isHidSrvcUuid(final UUID uuid)3685     private boolean isHidSrvcUuid(final UUID uuid) {
3686         return HID_SERVICE_UUID.equals(uuid);
3687     }
3688 
isHidCharUuid(final UUID uuid)3689     private boolean isHidCharUuid(final UUID uuid) {
3690         for (UUID hidUuid : HID_UUIDS) {
3691             if (hidUuid.equals(uuid)) {
3692                 return true;
3693             }
3694         }
3695         return false;
3696     }
3697 
isAndroidTvRemoteSrvcUuid(final UUID uuid)3698     private boolean isAndroidTvRemoteSrvcUuid(final UUID uuid) {
3699         return ANDROID_TV_REMOTE_SERVICE_UUID.equals(uuid);
3700     }
3701 
isFidoSrvcUuid(final UUID uuid)3702     private boolean isFidoSrvcUuid(final UUID uuid) {
3703         return FIDO_SERVICE_UUID.equals(uuid);
3704     }
3705 
getDeviceType(BluetoothDevice device)3706     private int getDeviceType(BluetoothDevice device) {
3707         int type = gattClientGetDeviceTypeNative(device.getAddress());
3708         if (DBG) {
3709             Log.d(TAG, "getDeviceType() - device=" + device + ", type=" + type);
3710         }
3711         return type;
3712     }
3713 
needsPrivilegedPermissionForScan(ScanSettings settings)3714     private boolean needsPrivilegedPermissionForScan(ScanSettings settings) {
3715         // BLE scan only mode needs special permission.
3716         if (mAdapterService.getState() != BluetoothAdapter.STATE_ON) {
3717             return true;
3718         }
3719 
3720         // Regular scan, no special permission.
3721         if (settings == null) {
3722             return false;
3723         }
3724 
3725         // Ambient discovery mode, needs privileged permission.
3726         if (settings.getScanMode() == ScanSettings.SCAN_MODE_AMBIENT_DISCOVERY) {
3727             return true;
3728         }
3729 
3730         // Regular scan, no special permission.
3731         if (settings.getReportDelayMillis() == 0) {
3732             return false;
3733         }
3734 
3735         // Batch scan, truncated mode needs permission.
3736         return settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_ABBREVIATED;
3737     }
3738 
3739     /*
3740      * The {@link ScanFilter#setDeviceAddress} API overloads are @SystemApi access methods.  This
3741      * requires that the permissions be BLUETOOTH_PRIVILEGED.
3742      */
3743     @SuppressLint("AndroidFrameworkRequiresPermission")
enforcePrivilegedPermissionIfNeeded(List<ScanFilter> filters)3744     private void enforcePrivilegedPermissionIfNeeded(List<ScanFilter> filters) {
3745         if (DBG) {
3746             Log.d(TAG, "enforcePrivilegedPermissionIfNeeded(" + filters + ")");
3747         }
3748         // Some 3p API cases may have null filters, need to allow
3749         if (filters != null) {
3750             for (ScanFilter filter : filters) {
3751                 // The only case to enforce here is if there is an address
3752                 // If there is an address, enforce if the correct combination criteria is met.
3753                 if (filter.getDeviceAddress() != null) {
3754                     // At this point we have an address, that means a caller used the
3755                     // setDeviceAddress(address) public API for the ScanFilter
3756                     // We don't want to enforce if the type is PUBLIC and the IRK is null
3757                     // However, if we have a different type that means the caller used a new
3758                     // @SystemApi such as setDeviceAddress(address, type) or
3759                     // setDeviceAddress(address, type, irk) which are both @SystemApi and require
3760                     // permissions to be enforced
3761                     if (filter.getAddressType()
3762                             == BluetoothDevice.ADDRESS_TYPE_PUBLIC && filter.getIrk() == null) {
3763                         // Do not enforce
3764                     } else {
3765                         enforcePrivilegedPermission();
3766                     }
3767                 }
3768             }
3769         }
3770     }
3771 
3772     // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be
3773     // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission.
3774     @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
enforcePrivilegedPermission()3775     private void enforcePrivilegedPermission() {
3776         enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
3777                 "Need BLUETOOTH_PRIVILEGED permission");
3778     }
3779 
3780     @SuppressLint("AndroidFrameworkRequiresPermission")
enforcePrivilegedPermissionIfNeeded(ScanSettings settings)3781     private void enforcePrivilegedPermissionIfNeeded(ScanSettings settings) {
3782         if (needsPrivilegedPermissionForScan(settings)) {
3783             enforcePrivilegedPermission();
3784         }
3785     }
3786 
3787     // Enforce caller has UPDATE_DEVICE_STATS permission, which allows the caller to blame other
3788     // apps for Bluetooth usage. A {@link SecurityException} will be thrown if the caller app does
3789     // not have UPDATE_DEVICE_STATS permission.
3790     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
enforceImpersonatationPermission()3791     private void enforceImpersonatationPermission() {
3792         enforceCallingOrSelfPermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
3793                 "Need UPDATE_DEVICE_STATS permission");
3794     }
3795 
3796     @SuppressLint("AndroidFrameworkRequiresPermission")
enforceImpersonatationPermissionIfNeeded(WorkSource workSource)3797     private void enforceImpersonatationPermissionIfNeeded(WorkSource workSource) {
3798         if (workSource != null) {
3799             enforceImpersonatationPermission();
3800         }
3801     }
3802 
3803     /**
3804      * Ensures the report delay is either 0 or at least the floor value (5000ms)
3805      *
3806      * @param  settings are the scan settings passed into a request to start le scanning
3807      * @return the passed in ScanSettings object if the report delay is 0 or above the floor value;
3808      *         a new ScanSettings object with the report delay being the floor value if the original
3809      *         report delay was between 0 and the floor value (exclusive of both)
3810      */
enforceReportDelayFloor(ScanSettings settings)3811     private ScanSettings enforceReportDelayFloor(ScanSettings settings) {
3812         if (settings.getReportDelayMillis() == 0) {
3813             return settings;
3814         }
3815 
3816         // Need to clear identity to pass device config permission check
3817         long callerToken = Binder.clearCallingIdentity();
3818         long floor = DeviceConfig.getLong(DeviceConfig.NAMESPACE_BLUETOOTH, "report_delay",
3819                 DEFAULT_REPORT_DELAY_FLOOR);
3820         Binder.restoreCallingIdentity(callerToken);
3821 
3822         if (settings.getReportDelayMillis() > floor) {
3823             return settings;
3824         } else {
3825             return new ScanSettings.Builder()
3826                     .setCallbackType(settings.getCallbackType())
3827                     .setLegacy(settings.getLegacy())
3828                     .setMatchMode(settings.getMatchMode())
3829                     .setNumOfMatches(settings.getNumOfMatches())
3830                     .setPhy(settings.getPhy())
3831                     .setReportDelay(floor)
3832                     .setScanMode(settings.getScanMode())
3833                     .setScanResultType(settings.getScanResultType())
3834                     .build();
3835         }
3836     }
3837 
stopNextService(int serverIf, int status)3838     private void stopNextService(int serverIf, int status) throws RemoteException {
3839         if (DBG) {
3840             Log.d(TAG, "stopNextService() - serverIf=" + serverIf + ", status=" + status);
3841         }
3842 
3843         if (status == 0) {
3844             List<HandleMap.Entry> entries = mHandleMap.getEntries();
3845             for (HandleMap.Entry entry : entries) {
3846                 if (entry.type != HandleMap.TYPE_SERVICE || entry.serverIf != serverIf
3847                         || !entry.started) {
3848                     continue;
3849                 }
3850 
3851                 gattServerStopServiceNative(serverIf, entry.handle);
3852                 return;
3853             }
3854         }
3855     }
3856 
deleteServices(int serverIf)3857     private void deleteServices(int serverIf) {
3858         if (DBG) {
3859             Log.d(TAG, "deleteServices() - serverIf=" + serverIf);
3860         }
3861 
3862         /*
3863          * Figure out which handles to delete.
3864          * The handles are copied into a new list to avoid race conditions.
3865          */
3866         List<Integer> handleList = new ArrayList<Integer>();
3867         List<HandleMap.Entry> entries = mHandleMap.getEntries();
3868         for (HandleMap.Entry entry : entries) {
3869             if (entry.type != HandleMap.TYPE_SERVICE || entry.serverIf != serverIf) {
3870                 continue;
3871             }
3872             handleList.add(entry.handle);
3873         }
3874 
3875         /* Now actually delete the services.... */
3876         for (Integer handle : handleList) {
3877             gattServerDeleteServiceNative(serverIf, handle);
3878         }
3879     }
3880 
dumpRegisterId(StringBuilder sb)3881     void dumpRegisterId(StringBuilder sb) {
3882         sb.append("  Scanner:\n");
3883         for (Integer appId : mScannerMap.getAllAppsIds()) {
3884             println(sb, "    app_if: " + appId + ", appName: " + mScannerMap.getById(appId).name);
3885         }
3886         sb.append("  Client:\n");
3887         for (Integer appId : mClientMap.getAllAppsIds()) {
3888             println(sb, "    app_if: " + appId + ", appName: " + mClientMap.getById(appId).name);
3889         }
3890         sb.append("  Server:\n");
3891         for (Integer appId : mServerMap.getAllAppsIds()) {
3892             println(sb, "    app_if: " + appId + ", appName: " + mServerMap.getById(appId).name);
3893         }
3894         sb.append("\n\n");
3895     }
3896 
3897     @Override
dump(StringBuilder sb)3898     public void dump(StringBuilder sb) {
3899         super.dump(sb);
3900         println(sb, "mAdvertisingServiceUuids:");
3901         for (UUID uuid : mAdvertisingServiceUuids) {
3902             println(sb, "  " + uuid);
3903         }
3904 
3905         println(sb, "mMaxScanFilters: " + mMaxScanFilters);
3906 
3907         sb.append("\nRegistered App\n");
3908         dumpRegisterId(sb);
3909 
3910         sb.append("GATT Scanner Map\n");
3911         mScannerMap.dump(sb);
3912 
3913         sb.append("GATT Client Map\n");
3914         mClientMap.dump(sb);
3915 
3916         sb.append("GATT Server Map\n");
3917         mServerMap.dump(sb);
3918 
3919         sb.append("GATT Handle Map\n");
3920         mHandleMap.dump(sb);
3921     }
3922 
addScanEvent(BluetoothMetricsProto.ScanEvent event)3923     void addScanEvent(BluetoothMetricsProto.ScanEvent event) {
3924         synchronized (mScanEvents) {
3925             if (mScanEvents.size() == NUM_SCAN_EVENTS_KEPT) {
3926                 mScanEvents.remove();
3927             }
3928             mScanEvents.add(event);
3929         }
3930     }
3931 
3932     @Override
dumpProto(BluetoothMetricsProto.BluetoothLog.Builder builder)3933     public void dumpProto(BluetoothMetricsProto.BluetoothLog.Builder builder) {
3934         synchronized (mScanEvents) {
3935             builder.addAllScanEvent(mScanEvents);
3936         }
3937     }
3938 
3939     /**************************************************************************
3940      * GATT Test functions
3941      *************************************************************************/
3942 
gattTestCommand(int command, UUID uuid1, String bda1, int p1, int p2, int p3, int p4, int p5)3943     void gattTestCommand(int command, UUID uuid1, String bda1, int p1, int p2, int p3, int p4,
3944             int p5) {
3945         if (bda1 == null) {
3946             bda1 = "00:00:00:00:00:00";
3947         }
3948         if (uuid1 != null) {
3949             gattTestNative(command, uuid1.getLeastSignificantBits(), uuid1.getMostSignificantBits(),
3950                     bda1, p1, p2, p3, p4, p5);
3951         } else {
3952             gattTestNative(command, 0, 0, bda1, p1, p2, p3, p4, p5);
3953         }
3954     }
3955 
gattTestNative(int command, long uuid1Lsb, long uuid1Msb, String bda1, int p1, int p2, int p3, int p4, int p5)3956     private native void gattTestNative(int command, long uuid1Lsb, long uuid1Msb, String bda1,
3957             int p1, int p2, int p3, int p4, int p5);
3958 
3959     /**************************************************************************
3960      * Native functions prototypes
3961      *************************************************************************/
3962 
classInitNative()3963     private static native void classInitNative();
3964 
initializeNative()3965     private native void initializeNative();
3966 
cleanupNative()3967     private native void cleanupNative();
3968 
gattClientGetDeviceTypeNative(String address)3969     private native int gattClientGetDeviceTypeNative(String address);
3970 
gattClientRegisterAppNative(long appUuidLsb, long appUuidMsb, boolean eatt_support)3971     private native void gattClientRegisterAppNative(long appUuidLsb, long appUuidMsb, boolean eatt_support);
3972 
gattClientUnregisterAppNative(int clientIf)3973     private native void gattClientUnregisterAppNative(int clientIf);
3974 
gattClientConnectNative(int clientIf, String address, boolean isDirect, int transport, boolean opportunistic, int initiatingPhys)3975     private native void gattClientConnectNative(int clientIf, String address, boolean isDirect,
3976             int transport, boolean opportunistic, int initiatingPhys);
3977 
gattClientDisconnectNative(int clientIf, String address, int connId)3978     private native void gattClientDisconnectNative(int clientIf, String address, int connId);
3979 
gattClientSetPreferredPhyNative(int clientIf, String address, int txPhy, int rxPhy, int phyOptions)3980     private native void gattClientSetPreferredPhyNative(int clientIf, String address, int txPhy,
3981             int rxPhy, int phyOptions);
3982 
gattClientReadPhyNative(int clientIf, String address)3983     private native void gattClientReadPhyNative(int clientIf, String address);
3984 
gattClientRefreshNative(int clientIf, String address)3985     private native void gattClientRefreshNative(int clientIf, String address);
3986 
gattClientSearchServiceNative(int connId, boolean searchAll, long serviceUuidLsb, long serviceUuidMsb)3987     private native void gattClientSearchServiceNative(int connId, boolean searchAll,
3988             long serviceUuidLsb, long serviceUuidMsb);
3989 
gattClientDiscoverServiceByUuidNative(int connId, long serviceUuidLsb, long serviceUuidMsb)3990     private native void gattClientDiscoverServiceByUuidNative(int connId, long serviceUuidLsb,
3991             long serviceUuidMsb);
3992 
gattClientGetGattDbNative(int connId)3993     private native void gattClientGetGattDbNative(int connId);
3994 
gattClientReadCharacteristicNative(int connId, int handle, int authReq)3995     private native void gattClientReadCharacteristicNative(int connId, int handle, int authReq);
3996 
gattClientReadUsingCharacteristicUuidNative(int connId, long uuidMsb, long uuidLsb, int sHandle, int eHandle, int authReq)3997     private native void gattClientReadUsingCharacteristicUuidNative(int connId, long uuidMsb,
3998             long uuidLsb, int sHandle, int eHandle, int authReq);
3999 
gattClientReadDescriptorNative(int connId, int handle, int authReq)4000     private native void gattClientReadDescriptorNative(int connId, int handle, int authReq);
4001 
gattClientWriteCharacteristicNative(int connId, int handle, int writeType, int authReq, byte[] value)4002     private native void gattClientWriteCharacteristicNative(int connId, int handle, int writeType,
4003             int authReq, byte[] value);
4004 
gattClientWriteDescriptorNative(int connId, int handle, int authReq, byte[] value)4005     private native void gattClientWriteDescriptorNative(int connId, int handle, int authReq,
4006             byte[] value);
4007 
gattClientExecuteWriteNative(int connId, boolean execute)4008     private native void gattClientExecuteWriteNative(int connId, boolean execute);
4009 
gattClientRegisterForNotificationsNative(int clientIf, String address, int handle, boolean enable)4010     private native void gattClientRegisterForNotificationsNative(int clientIf, String address,
4011             int handle, boolean enable);
4012 
gattClientReadRemoteRssiNative(int clientIf, String address)4013     private native void gattClientReadRemoteRssiNative(int clientIf, String address);
4014 
gattClientConfigureMTUNative(int connId, int mtu)4015     private native void gattClientConfigureMTUNative(int connId, int mtu);
4016 
gattConnectionParameterUpdateNative(int clientIf, String address, int minInterval, int maxInterval, int latency, int timeout, int minConnectionEventLen, int maxConnectionEventLen)4017     private native void gattConnectionParameterUpdateNative(int clientIf, String address,
4018             int minInterval, int maxInterval, int latency, int timeout, int minConnectionEventLen,
4019             int maxConnectionEventLen);
4020 
gattServerRegisterAppNative(long appUuidLsb, long appUuidMsb, boolean eatt_support)4021     private native void gattServerRegisterAppNative(long appUuidLsb, long appUuidMsb, boolean eatt_support);
4022 
gattServerUnregisterAppNative(int serverIf)4023     private native void gattServerUnregisterAppNative(int serverIf);
4024 
gattServerConnectNative(int serverIf, String address, boolean isDirect, int transport)4025     private native void gattServerConnectNative(int serverIf, String address, boolean isDirect,
4026             int transport);
4027 
gattServerDisconnectNative(int serverIf, String address, int connId)4028     private native void gattServerDisconnectNative(int serverIf, String address, int connId);
4029 
gattServerSetPreferredPhyNative(int clientIf, String address, int txPhy, int rxPhy, int phyOptions)4030     private native void gattServerSetPreferredPhyNative(int clientIf, String address, int txPhy,
4031             int rxPhy, int phyOptions);
4032 
gattServerReadPhyNative(int clientIf, String address)4033     private native void gattServerReadPhyNative(int clientIf, String address);
4034 
gattServerAddServiceNative(int serverIf, List<GattDbElement> service)4035     private native void gattServerAddServiceNative(int serverIf, List<GattDbElement> service);
4036 
gattServerStopServiceNative(int serverIf, int svcHandle)4037     private native void gattServerStopServiceNative(int serverIf, int svcHandle);
4038 
gattServerDeleteServiceNative(int serverIf, int svcHandle)4039     private native void gattServerDeleteServiceNative(int serverIf, int svcHandle);
4040 
gattServerSendIndicationNative(int serverIf, int attrHandle, int connId, byte[] val)4041     private native void gattServerSendIndicationNative(int serverIf, int attrHandle, int connId,
4042             byte[] val);
4043 
gattServerSendNotificationNative(int serverIf, int attrHandle, int connId, byte[] val)4044     private native void gattServerSendNotificationNative(int serverIf, int attrHandle, int connId,
4045             byte[] val);
4046 
gattServerSendResponseNative(int serverIf, int connId, int transId, int status, int handle, int offset, byte[] val, int authReq)4047     private native void gattServerSendResponseNative(int serverIf, int connId, int transId,
4048             int status, int handle, int offset, byte[] val, int authReq);
4049 }
4050