• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.bluetooth.Utils.callerIsSystemOrActiveOrManagedUser;
20 import static com.android.bluetooth.Utils.checkCallerTargetSdk;
21 import static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission;
22 
23 import android.annotation.RequiresPermission;
24 import android.annotation.SuppressLint;
25 import android.app.AppOpsManager;
26 import android.app.PendingIntent;
27 import android.app.Service;
28 import android.bluetooth.BluetoothAdapter;
29 import android.bluetooth.BluetoothDevice;
30 import android.bluetooth.BluetoothGatt;
31 import android.bluetooth.BluetoothGattCharacteristic;
32 import android.bluetooth.BluetoothGattDescriptor;
33 import android.bluetooth.BluetoothGattService;
34 import android.bluetooth.BluetoothProfile;
35 import android.bluetooth.BluetoothProtoEnums;
36 import android.bluetooth.BluetoothStatusCodes;
37 import android.bluetooth.BluetoothUtils;
38 import android.bluetooth.IBluetoothGatt;
39 import android.bluetooth.IBluetoothGattCallback;
40 import android.bluetooth.IBluetoothGattServerCallback;
41 import android.bluetooth.le.AdvertiseData;
42 import android.bluetooth.le.AdvertisingSetParameters;
43 import android.bluetooth.le.BluetoothLeScanner;
44 import android.bluetooth.le.DistanceMeasurementMethod;
45 import android.bluetooth.le.DistanceMeasurementParams;
46 import android.bluetooth.le.IAdvertisingSetCallback;
47 import android.bluetooth.le.IDistanceMeasurementCallback;
48 import android.bluetooth.le.IPeriodicAdvertisingCallback;
49 import android.bluetooth.le.IScannerCallback;
50 import android.bluetooth.le.PeriodicAdvertisingParameters;
51 import android.bluetooth.le.ScanCallback;
52 import android.bluetooth.le.ScanFilter;
53 import android.bluetooth.le.ScanRecord;
54 import android.bluetooth.le.ScanResult;
55 import android.bluetooth.le.ScanSettings;
56 import android.companion.AssociationInfo;
57 import android.companion.CompanionDeviceManager;
58 import android.content.AttributionSource;
59 import android.content.Intent;
60 import android.content.pm.PackageManager.NameNotFoundException;
61 import android.content.pm.PackageManager.PackageInfoFlags;
62 import android.content.res.Resources;
63 import android.net.MacAddress;
64 import android.os.Binder;
65 import android.os.Build;
66 import android.os.Handler;
67 import android.os.IBinder;
68 import android.os.Message;
69 import android.os.ParcelUuid;
70 import android.os.RemoteException;
71 import android.os.SystemClock;
72 import android.os.UserHandle;
73 import android.os.WorkSource;
74 import android.provider.DeviceConfig;
75 import android.provider.Settings;
76 import android.sysprop.BluetoothProperties;
77 import android.text.format.DateUtils;
78 import android.util.Log;
79 
80 import com.android.bluetooth.BluetoothMetricsProto;
81 import com.android.bluetooth.BluetoothStatsLog;
82 import com.android.bluetooth.R;
83 import com.android.bluetooth.Utils;
84 import com.android.bluetooth.btservice.AbstractionLayer;
85 import com.android.bluetooth.btservice.AdapterService;
86 import com.android.bluetooth.btservice.BluetoothAdapterProxy;
87 import com.android.bluetooth.btservice.MetricsLogger;
88 import com.android.bluetooth.btservice.CompanionManager;
89 import com.android.bluetooth.btservice.ProfileService;
90 import com.android.bluetooth.util.NumberUtils;
91 import com.android.internal.annotations.VisibleForTesting;
92 import com.android.modules.utils.SynchronousResultReceiver;
93 
94 import libcore.util.HexEncoding;
95 
96 import java.util.ArrayDeque;
97 import java.util.ArrayList;
98 import java.util.Arrays;
99 import java.util.Collections;
100 import java.util.HashMap;
101 import java.util.HashSet;
102 import java.util.List;
103 import java.util.Map;
104 import java.util.Set;
105 import java.util.UUID;
106 import java.util.concurrent.TimeUnit;
107 import java.util.function.Predicate;
108 
109 /**
110  * Provides Bluetooth Gatt profile, as a service in
111  * the Bluetooth application.
112  * @hide
113  */
114 public class GattService extends ProfileService {
115     private static final boolean DBG = GattServiceConfig.DBG;
116     private static final boolean VDBG = GattServiceConfig.VDBG;
117     private static final String TAG = GattServiceConfig.TAG_PREFIX + "GattService";
118     private static final String UUID_SUFFIX = "-0000-1000-8000-00805f9b34fb";
119     private static final String UUID_ZERO_PAD = "00000000";
120 
121     static final int SCAN_FILTER_ENABLED = 1;
122     static final int SCAN_FILTER_MODIFIED = 2;
123 
124     private static final int MAC_ADDRESS_LENGTH = 6;
125     // Batch scan related constants.
126     private static final int TRUNCATED_RESULT_SIZE = 11;
127     private static final int TIME_STAMP_LENGTH = 2;
128 
129     private enum MatchOrigin {
130         PSEUDO_ADDRESS,
131         ORIGINAL_ADDRESS
132     }
133 
134     private static class MatchResult {
135         private final boolean mMatches;
136         private final MatchOrigin mOrigin;
MatchResult(boolean matches, MatchOrigin origin)137         private MatchResult(boolean matches, MatchOrigin origin) {
138             this.mMatches = matches;
139             this.mOrigin = origin;
140         }
141 
getMatches()142         public boolean getMatches() {
143             return mMatches;
144         }
145 
getMatchOrigin()146         public MatchOrigin getMatchOrigin() {
147             return mOrigin;
148         }
149     }
150 
151     /**
152      * The default floor value for LE batch scan report delays greater than 0
153      */
154     @VisibleForTesting
155     static final long DEFAULT_REPORT_DELAY_FLOOR = 5000;
156 
157     // onFoundLost related constants
158     private static final int ADVT_STATE_ONFOUND = 0;
159     private static final int ADVT_STATE_ONLOST = 1;
160 
161     private static final int ET_LEGACY_MASK = 0x10;
162 
163     private static final UUID HID_SERVICE_UUID =
164             UUID.fromString("00001812-0000-1000-8000-00805F9B34FB");
165 
166     private static final UUID[] HID_UUIDS = {
167             UUID.fromString("00002A4A-0000-1000-8000-00805F9B34FB"),
168             UUID.fromString("00002A4B-0000-1000-8000-00805F9B34FB"),
169             UUID.fromString("00002A4C-0000-1000-8000-00805F9B34FB"),
170             UUID.fromString("00002A4D-0000-1000-8000-00805F9B34FB")
171     };
172 
173     private static final UUID ANDROID_TV_REMOTE_SERVICE_UUID =
174             UUID.fromString("AB5E0001-5A21-4F05-BC7D-AF01F617B664");
175 
176     private static final UUID FIDO_SERVICE_UUID =
177             UUID.fromString("0000FFFD-0000-1000-8000-00805F9B34FB"); // U2F
178 
179     private static final UUID[] LE_AUDIO_SERVICE_UUIDS = {
180             UUID.fromString("00001844-0000-1000-8000-00805F9B34FB"), // VCS
181             UUID.fromString("00001845-0000-1000-8000-00805F9B34FB"), // VOCS
182             UUID.fromString("00001843-0000-1000-8000-00805F9B34FB"), // AICS
183             UUID.fromString("00001850-0000-1000-8000-00805F9B34FB"), // PACS
184             UUID.fromString("0000184E-0000-1000-8000-00805F9B34FB"), // ASCS
185             UUID.fromString("0000184F-0000-1000-8000-00805F9B34FB"), // BASS
186             UUID.fromString("00001854-0000-1000-8000-00805F9B34FB"), // HAP
187             UUID.fromString("00001846-0000-1000-8000-00805F9B34FB"), // CSIS
188     };
189 
190     /**
191      * Example raw beacons captured from a Blue Charm BC011
192      */
193     private static final String[] TEST_MODE_BEACONS = new String[] {
194             "020106",
195             "0201060303AAFE1716AAFE10EE01626C7565636861726D626561636F6E730009168020691E0EFE13551109426C7565436861726D5F313639363835000000",
196             "0201060303AAFE1716AAFE00EE626C7565636861726D31000000000001000009168020691E0EFE13551109426C7565436861726D5F313639363835000000",
197             "0201060303AAFE1116AAFE20000BF017000008874803FB93540916802069080EFE13551109426C7565436861726D5F313639363835000000000000000000",
198             "0201061AFF4C000215426C7565436861726D426561636F6E730EFE1355C509168020691E0EFE13551109426C7565436861726D5F31363936383500000000",
199     };
200 
201     /**
202      * Keep the arguments passed in for the PendingIntent.
203      */
204     class PendingIntentInfo {
205         public PendingIntent intent;
206         public ScanSettings settings;
207         public List<ScanFilter> filters;
208         public String callingPackage;
209 
210         @Override
equals(Object other)211         public boolean equals(Object other) {
212             if (!(other instanceof PendingIntentInfo)) {
213                 return false;
214             }
215             return intent.equals(((PendingIntentInfo) other).intent);
216         }
217     }
218 
219     private final PendingIntent.CancelListener mScanIntentCancelListener =
220             new PendingIntent.CancelListener(){
221                 public void onCanceled(PendingIntent intent) {
222                     Log.d(TAG, "scanning PendingIntent canceled");
223                     stopScan(intent, getAttributionSource());
224                 }
225             };
226 
227     /**
228      * List of our registered scanners.
229      */
230     class ScannerMap extends ContextMap<IScannerCallback, PendingIntentInfo> {}
231 
232     ScannerMap mScannerMap = new ScannerMap();
233 
234     /**
235      * List of our registered advertisers.
236      */
237     static class AdvertiserMap extends ContextMap<IAdvertisingSetCallback, Void> {}
238 
239     private AdvertiserMap mAdvertiserMap = new AdvertiserMap();
240 
241     /**
242      * List of our registered clients.
243      */
244     class ClientMap extends ContextMap<IBluetoothGattCallback, Void> {}
245 
246     ClientMap mClientMap = new ClientMap();
247 
248     /**
249      * List of our registered server apps.
250      */
251     class ServerMap extends ContextMap<IBluetoothGattServerCallback, Void> {}
252 
253     ServerMap mServerMap = new ServerMap();
254 
255     /**
256      * Server handle map.
257      */
258     HandleMap mHandleMap = new HandleMap();
259     private List<UUID> mAdvertisingServiceUuids = new ArrayList<UUID>();
260 
261     private int mMaxScanFilters;
262 
263     private static final int NUM_SCAN_EVENTS_KEPT = 20;
264 
265     /**
266      * Internal list of scan events to use with the proto
267      */
268     private final ArrayDeque<BluetoothMetricsProto.ScanEvent> mScanEvents =
269             new ArrayDeque<>(NUM_SCAN_EVENTS_KEPT);
270 
271     /**
272      * Set of restricted (which require a BLUETOOTH_PRIVILEGED permission) handles per connectionId.
273      */
274     private final Map<Integer, Set<Integer>> mRestrictedHandles = new HashMap<>();
275 
276     /**
277      * HashMap used to synchronize writeCharacteristic calls mapping remote device address to
278      * available permit (connectId or -1).
279      */
280     private final HashMap<String, Integer> mPermits = new HashMap<>();
281 
282     private AdapterService mAdapterService;
283     private BluetoothAdapterProxy mBluetoothAdapterProxy;
284     @VisibleForTesting
285     AdvertiseManager mAdvertiseManager;
286     @VisibleForTesting
287     PeriodicScanManager mPeriodicScanManager;
288     @VisibleForTesting
289     DistanceMeasurementManager mDistanceMeasurementManager;
290     @VisibleForTesting
291     ScanManager mScanManager;
292     private AppOpsManager mAppOps;
293     private CompanionDeviceManager mCompanionManager;
294     private String mExposureNotificationPackage;
295     private Handler mTestModeHandler;
296     private final Object mTestModeLock = new Object();
297 
isEnabled()298     public static boolean isEnabled() {
299         return BluetoothProperties.isProfileGattEnabled().orElse(true);
300     }
301 
302     /**
303      */
304     private final Predicate<ScanResult> mLocationDenylistPredicate = (scanResult) -> {
305         final MacAddress parsedAddress = MacAddress
306                 .fromString(scanResult.getDevice().getAddress());
307         if (mAdapterService.getLocationDenylistMac().test(parsedAddress.toByteArray())) {
308             Log.v(TAG, "Skipping device matching denylist: " + scanResult.getDevice());
309             return true;
310         }
311         final ScanRecord scanRecord = scanResult.getScanRecord();
312         if (scanRecord.matchesAnyField(mAdapterService.getLocationDenylistAdvertisingData())) {
313             Log.v(TAG, "Skipping data matching denylist: " + scanRecord);
314             return true;
315         }
316         return false;
317     };
318 
319     private static GattService sGattService;
320 
321     /**
322      * Reliable write queue
323      */
324     @VisibleForTesting
325     Set<String> mReliableQueue = new HashSet<String>();
326 
327     private GattNativeInterface mNativeInterface;
328 
329     @Override
initBinder()330     protected IProfileServiceBinder initBinder() {
331         return new BluetoothGattBinder(this);
332     }
333 
334     @Override
start()335     protected boolean start() {
336         if (DBG) {
337             Log.d(TAG, "start()");
338         }
339         mExposureNotificationPackage = getString(R.string.exposure_notification_package);
340         Settings.Global.putInt(
341                 getContentResolver(), "bluetooth_sanitized_exposure_notification_supported", 1);
342 
343         mNativeInterface = GattObjectsFactory.getInstance().getNativeInterface();
344         mNativeInterface.init(this);
345         mAdapterService = AdapterService.getAdapterService();
346         mBluetoothAdapterProxy = BluetoothAdapterProxy.getInstance();
347         mCompanionManager = getSystemService(CompanionDeviceManager.class);
348         mAppOps = getSystemService(AppOpsManager.class);
349         mAdvertiseManager = new AdvertiseManager(this, mAdapterService, mAdvertiserMap);
350         mAdvertiseManager.start();
351 
352         mScanManager = new ScanManager(this, mAdapterService, mBluetoothAdapterProxy);
353         mScanManager.start();
354 
355         mPeriodicScanManager = new PeriodicScanManager(mAdapterService);
356         mPeriodicScanManager.start();
357 
358         mDistanceMeasurementManager = new DistanceMeasurementManager(mAdapterService);
359         mDistanceMeasurementManager.start();
360 
361         setGattService(this);
362         return true;
363     }
364 
365     @Override
stop()366     protected boolean stop() {
367         if (DBG) {
368             Log.d(TAG, "stop()");
369         }
370         setGattService(null);
371         mScannerMap.clear();
372         mAdvertiserMap.clear();
373         mClientMap.clear();
374         mServerMap.clear();
375         mHandleMap.clear();
376         mReliableQueue.clear();
377         cleanup();
378 
379         return true;
380     }
381 
382     @Override
cleanup()383     protected void cleanup() {
384         if (DBG) {
385             Log.d(TAG, "cleanup()");
386         }
387         if (mNativeInterface != null) {
388             mNativeInterface.cleanup();
389             mNativeInterface = null;
390         }
391         if (mAdvertiseManager != null) {
392             mAdvertiseManager.cleanup();
393         }
394         if (mScanManager != null) {
395             mScanManager.cleanup();
396         }
397         if (mPeriodicScanManager != null) {
398             mPeriodicScanManager.cleanup();
399         }
400         if (mDistanceMeasurementManager != null) {
401             mDistanceMeasurementManager.cleanup();
402         }
403     }
404 
405     // While test mode is enabled, pretend as if the underlying stack
406     // discovered a specific set of well-known beacons every second
407     @Override
setTestModeEnabled(boolean enableTestMode)408     protected void setTestModeEnabled(boolean enableTestMode) {
409         synchronized (mTestModeLock) {
410             if (mTestModeHandler == null) {
411                 mTestModeHandler = new Handler(getMainLooper()) {
412                     public void handleMessage(Message msg) {
413                         synchronized (mTestModeLock) {
414                             if (!GattService.this.isTestModeEnabled()) {
415                                 return;
416                             }
417                             for (String test : TEST_MODE_BEACONS) {
418                                 onScanResultInternal(0x1b, 0x1, "DD:34:02:05:5C:4D", 1, 0, 0xff,
419                                         127, -54, 0x0, HexEncoding.decode(test),
420                                         "DD:34:02:05:5C:4E");
421                             }
422                             sendEmptyMessageDelayed(0, DateUtils.SECOND_IN_MILLIS);
423                         }
424                     }
425                 };
426             }
427             if (enableTestMode && !isTestModeEnabled()) {
428                 super.setTestModeEnabled(true);
429                 mTestModeHandler.removeMessages(0);
430                 mTestModeHandler.sendEmptyMessageDelayed(0, DateUtils.SECOND_IN_MILLIS);
431             } else if (!enableTestMode && isTestModeEnabled()) {
432                 super.setTestModeEnabled(false);
433                 mTestModeHandler.removeMessages(0);
434                 mTestModeHandler.sendEmptyMessage(0);
435             }
436         }
437     }
438 
439     /**
440      * Get the current instance of {@link GattService}
441      *
442      * @return current instance of {@link GattService}
443      */
444     @VisibleForTesting
getGattService()445     public static synchronized GattService getGattService() {
446         if (sGattService == null) {
447             Log.w(TAG, "getGattService(): service is null");
448             return null;
449         }
450         if (!sGattService.isAvailable()) {
451             Log.w(TAG, "getGattService(): service is not available");
452             return null;
453         }
454         return sGattService;
455     }
456 
457     @VisibleForTesting
getScanManager()458     ScanManager getScanManager() {
459         if (mScanManager == null) {
460             Log.w(TAG, "getScanManager(): scan manager is null");
461             return null;
462         }
463         return mScanManager;
464     }
465 
setGattService(GattService instance)466     private static synchronized void setGattService(GattService instance) {
467         if (DBG) {
468             Log.d(TAG, "setGattService(): set to: " + instance);
469         }
470         sGattService = instance;
471     }
472 
473     // Suppressed because we are conditionally enforcing
474     @SuppressLint("AndroidFrameworkRequiresPermission")
permissionCheck(UUID characteristicUuid)475     private void permissionCheck(UUID characteristicUuid) {
476         if (!isHidCharUuid(characteristicUuid)) {
477             return;
478         }
479         enforceBluetoothPrivilegedPermission(this);
480     }
481 
482     // Suppressed because we are conditionally enforcing
483     @SuppressLint("AndroidFrameworkRequiresPermission")
permissionCheck(int connId, int handle)484     private void permissionCheck(int connId, int handle) {
485         if (!isHandleRestricted(connId, handle)) {
486             return;
487         }
488         enforceBluetoothPrivilegedPermission(this);
489     }
490 
491     // Suppressed because we are conditionally enforcing
492     @SuppressLint("AndroidFrameworkRequiresPermission")
permissionCheck(ClientMap.App app, int connId, int handle)493     private void permissionCheck(ClientMap.App app, int connId, int handle) {
494         if (!isHandleRestricted(connId, handle) || app.hasBluetoothPrivilegedPermission) {
495             return;
496         }
497         enforceBluetoothPrivilegedPermission(this);
498         app.hasBluetoothPrivilegedPermission = true;
499     }
500 
isHandleRestricted(int connId, int handle)501     private boolean isHandleRestricted(int connId, int handle) {
502         Set<Integer> restrictedHandles = mRestrictedHandles.get(connId);
503         return restrictedHandles != null && restrictedHandles.contains(handle);
504     }
505 
506     @Override
onStartCommand(Intent intent, int flags, int startId)507     public int onStartCommand(Intent intent, int flags, int startId) {
508         if (GattDebugUtils.handleDebugAction(this, intent)) {
509             return Service.START_NOT_STICKY;
510         }
511         return super.onStartCommand(intent, flags, startId);
512     }
513 
514     /**
515      * DeathReceipient handlers used to unregister applications that
516      * disconnect ungracefully (ie. crash or forced close).
517      */
518 
519     class ScannerDeathRecipient implements IBinder.DeathRecipient {
520         int mScannerId;
521 
ScannerDeathRecipient(int scannerId)522         ScannerDeathRecipient(int scannerId) {
523             mScannerId = scannerId;
524         }
525 
526         @Override
binderDied()527         public void binderDied() {
528             if (DBG) {
529                 Log.d(TAG, "Binder is dead - unregistering scanner (" + mScannerId + ")!");
530             }
531 
532             ScanClient client = getScanClient(mScannerId);
533             if (client != null) {
534                 client.appDied = true;
535                 stopScan(client.scannerId, getAttributionSource());
536             }
537         }
538 
getScanClient(int clientIf)539         private ScanClient getScanClient(int clientIf) {
540             for (ScanClient client : mScanManager.getRegularScanQueue()) {
541                 if (client.scannerId == clientIf) {
542                     return client;
543                 }
544             }
545             for (ScanClient client : mScanManager.getBatchScanQueue()) {
546                 if (client.scannerId == clientIf) {
547                     return client;
548                 }
549             }
550             return null;
551         }
552     }
553 
554     class ServerDeathRecipient implements IBinder.DeathRecipient {
555         int mAppIf;
556 
ServerDeathRecipient(int appIf)557         ServerDeathRecipient(int appIf) {
558             mAppIf = appIf;
559         }
560 
561         @Override
binderDied()562         public void binderDied() {
563             if (DBG) {
564                 Log.d(TAG, "Binder is dead - unregistering server (" + mAppIf + ")!");
565             }
566             unregisterServer(mAppIf, getAttributionSource());
567         }
568     }
569 
570     class ClientDeathRecipient implements IBinder.DeathRecipient {
571         int mAppIf;
572 
ClientDeathRecipient(int appIf)573         ClientDeathRecipient(int appIf) {
574             mAppIf = appIf;
575         }
576 
577         @Override
binderDied()578         public void binderDied() {
579             if (DBG) {
580                 Log.d(TAG, "Binder is dead - unregistering client (" + mAppIf + ")!");
581             }
582             unregisterClient(mAppIf, getAttributionSource());
583         }
584     }
585 
586     /**
587      * Handlers for incoming service calls
588      */
589     @VisibleForTesting
590     static class BluetoothGattBinder extends IBluetoothGatt.Stub
591             implements IProfileServiceBinder {
592         private GattService mService;
593 
BluetoothGattBinder(GattService svc)594         BluetoothGattBinder(GattService svc) {
595             mService = svc;
596         }
597 
598         @Override
cleanup()599         public void cleanup() {
600             mService = null;
601         }
602 
getService()603         private GattService getService() {
604             if (mService != null && mService.isAvailable()) {
605                 return mService;
606             }
607             Log.e(TAG, "getService() - Service requested, but not available!");
608             return null;
609         }
610 
611         @Override
getDevicesMatchingConnectionStates(int[] states, AttributionSource attributionSource, SynchronousResultReceiver receiver)612         public void getDevicesMatchingConnectionStates(int[] states,
613                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
614             try {
615                 receiver.send(getDevicesMatchingConnectionStates(states, attributionSource));
616             } catch (RuntimeException e) {
617                 receiver.propagateException(e);
618             }
619         }
getDevicesMatchingConnectionStates(int[] states, AttributionSource attributionSource)620         private List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states,
621                 AttributionSource attributionSource) {
622             GattService service = getService();
623             if (service == null) {
624                 return new ArrayList<BluetoothDevice>();
625             }
626             return service.getDevicesMatchingConnectionStates(states, attributionSource);
627         }
628 
629         @Override
registerClient(ParcelUuid uuid, IBluetoothGattCallback callback, boolean eattSupport, AttributionSource attributionSource, SynchronousResultReceiver receiver)630         public void registerClient(ParcelUuid uuid, IBluetoothGattCallback callback,
631                 boolean eattSupport, AttributionSource attributionSource,
632                 SynchronousResultReceiver receiver) {
633             try {
634                 registerClient(uuid, callback, eattSupport, attributionSource);
635                 receiver.send(null);
636             } catch (RuntimeException e) {
637                 receiver.propagateException(e);
638             }
639         }
registerClient(ParcelUuid uuid, IBluetoothGattCallback callback, boolean eatt_support, AttributionSource attributionSource)640         private void registerClient(ParcelUuid uuid, IBluetoothGattCallback callback,
641                 boolean eatt_support, AttributionSource attributionSource) {
642             GattService service = getService();
643             if (service == null) {
644                 return;
645             }
646             service.registerClient(uuid.getUuid(), callback, eatt_support, attributionSource);
647         }
648 
649         @Override
unregisterClient(int clientIf, AttributionSource attributionSource, SynchronousResultReceiver receiver)650         public void unregisterClient(int clientIf, AttributionSource attributionSource,
651                 SynchronousResultReceiver receiver) {
652             try {
653                 unregisterClient(clientIf, attributionSource);
654                 receiver.send(null);
655             } catch (RuntimeException e) {
656                 receiver.propagateException(e);
657             }
658         }
unregisterClient(int clientIf, AttributionSource attributionSource)659         private void unregisterClient(int clientIf, AttributionSource attributionSource) {
660             GattService service = getService();
661             if (service == null) {
662                 return;
663             }
664             service.unregisterClient(clientIf, attributionSource);
665         }
666 
667         @Override
registerScanner(IScannerCallback callback, WorkSource workSource, AttributionSource attributionSource, SynchronousResultReceiver receiver)668         public void registerScanner(IScannerCallback callback, WorkSource workSource,
669                 AttributionSource attributionSource, SynchronousResultReceiver receiver)
670                 throws RemoteException {
671             try {
672                 registerScanner(callback, workSource, attributionSource);
673                 receiver.send(null);
674             } catch (RuntimeException e) {
675                 receiver.propagateException(e);
676             }
677         }
registerScanner(IScannerCallback callback, WorkSource workSource, AttributionSource attributionSource)678         private void registerScanner(IScannerCallback callback, WorkSource workSource,
679                 AttributionSource attributionSource) throws RemoteException {
680             GattService service = getService();
681             if (service == null) {
682                 return;
683             }
684             service.registerScanner(callback, workSource, attributionSource);
685         }
686 
687         @Override
unregisterScanner(int scannerId, AttributionSource attributionSource, SynchronousResultReceiver receiver)688         public void unregisterScanner(int scannerId, AttributionSource attributionSource,
689                 SynchronousResultReceiver receiver) {
690             try {
691                 unregisterScanner(scannerId, attributionSource);
692                 receiver.send(null);
693             } catch (RuntimeException e) {
694                 receiver.propagateException(e);
695             }
696         }
unregisterScanner(int scannerId, AttributionSource attributionSource)697         private void unregisterScanner(int scannerId, AttributionSource attributionSource) {
698             GattService service = getService();
699             if (service == null) {
700                 return;
701             }
702             service.unregisterScanner(scannerId, attributionSource);
703         }
704 
705         @Override
startScan(int scannerId, ScanSettings settings, List<ScanFilter> filters, AttributionSource attributionSource, SynchronousResultReceiver receiver)706         public void startScan(int scannerId, ScanSettings settings, List<ScanFilter> filters,
707                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
708             try {
709                 startScan(scannerId, settings, filters,
710                         attributionSource);
711                 receiver.send(null);
712             } catch (RuntimeException e) {
713                 receiver.propagateException(e);
714             }
715         }
startScan(int scannerId, ScanSettings settings, List<ScanFilter> filters, AttributionSource attributionSource)716         private void startScan(int scannerId, ScanSettings settings, List<ScanFilter> filters,
717                 AttributionSource attributionSource) {
718             GattService service = getService();
719             if (service == null) {
720                 return;
721             }
722             service.startScan(scannerId, settings, filters, attributionSource);
723         }
724 
725         @Override
startScanForIntent(PendingIntent intent, ScanSettings settings, List<ScanFilter> filters, AttributionSource attributionSource, SynchronousResultReceiver receiver)726         public void startScanForIntent(PendingIntent intent, ScanSettings settings,
727                 List<ScanFilter> filters, AttributionSource attributionSource,
728                 SynchronousResultReceiver receiver)
729                 throws RemoteException {
730             try {
731                 startScanForIntent(intent, settings,
732                         filters, attributionSource);
733                 receiver.send(null);
734             } catch (RuntimeException e) {
735                 receiver.propagateException(e);
736             }
737         }
startScanForIntent(PendingIntent intent, ScanSettings settings, List<ScanFilter> filters, AttributionSource attributionSource)738         private void startScanForIntent(PendingIntent intent, ScanSettings settings,
739                 List<ScanFilter> filters, AttributionSource attributionSource)
740                 throws RemoteException {
741             GattService service = getService();
742             if (service == null) {
743                 return;
744             }
745             service.registerPiAndStartScan(intent, settings, filters, attributionSource);
746         }
747 
748         @Override
stopScanForIntent(PendingIntent intent, AttributionSource attributionSource, SynchronousResultReceiver receiver)749         public void stopScanForIntent(PendingIntent intent, AttributionSource attributionSource,
750                 SynchronousResultReceiver receiver) throws RemoteException {
751             try {
752                 stopScanForIntent(intent, attributionSource);
753                 receiver.send(null);
754             } catch (RuntimeException e) {
755                 receiver.propagateException(e);
756             }
757         }
stopScanForIntent(PendingIntent intent, AttributionSource attributionSource)758         private void stopScanForIntent(PendingIntent intent, AttributionSource attributionSource)
759                 throws RemoteException {
760             GattService service = getService();
761             if (service == null) {
762                 return;
763             }
764             service.stopScan(intent, attributionSource);
765         }
766 
767         @Override
stopScan(int scannerId, AttributionSource attributionSource, SynchronousResultReceiver receiver)768         public void stopScan(int scannerId, AttributionSource attributionSource,
769                 SynchronousResultReceiver receiver) {
770             try {
771                 stopScan(scannerId, attributionSource);
772                 receiver.send(null);
773             } catch (RuntimeException e) {
774                 receiver.propagateException(e);
775             }
776         }
stopScan(int scannerId, AttributionSource attributionSource)777         private void stopScan(int scannerId, AttributionSource attributionSource) {
778             GattService service = getService();
779             if (service == null) {
780                 return;
781             }
782             service.stopScan(scannerId, attributionSource);
783         }
784 
785         @Override
flushPendingBatchResults(int scannerId, AttributionSource attributionSource, SynchronousResultReceiver receiver)786         public void flushPendingBatchResults(int scannerId, AttributionSource attributionSource,
787                 SynchronousResultReceiver receiver) {
788             try {
789                 flushPendingBatchResults(scannerId, attributionSource);
790                 receiver.send(null);
791             } catch (RuntimeException e) {
792                 receiver.propagateException(e);
793             }
794         }
flushPendingBatchResults(int scannerId, AttributionSource attributionSource)795         private void flushPendingBatchResults(int scannerId, AttributionSource attributionSource) {
796             GattService service = getService();
797             if (service == null) {
798                 return;
799             }
800             service.flushPendingBatchResults(scannerId, attributionSource);
801         }
802 
803         @Override
clientConnect(int clientIf, String address, int addressType, boolean isDirect, int transport, boolean opportunistic, int phy, AttributionSource attributionSource, SynchronousResultReceiver receiver)804         public void clientConnect(int clientIf, String address, int addressType, boolean isDirect,
805                 int transport, boolean opportunistic, int phy, AttributionSource attributionSource,
806                 SynchronousResultReceiver receiver) {
807             try {
808                 clientConnect(clientIf, address, addressType, isDirect, transport, opportunistic,
809                         phy, attributionSource);
810                 receiver.send(null);
811             } catch (RuntimeException e) {
812                 receiver.propagateException(e);
813             }
814         }
clientConnect(int clientIf, String address, int addressType, boolean isDirect, int transport, boolean opportunistic, int phy, AttributionSource attributionSource)815         private void clientConnect(int clientIf, String address, int addressType, boolean isDirect,
816                 int transport, boolean opportunistic, int phy,
817                 AttributionSource attributionSource) {
818             GattService service = getService();
819             if (service == null) {
820                 return;
821             }
822             service.clientConnect(clientIf, address, addressType, isDirect, transport,
823                     opportunistic, phy, attributionSource);
824         }
825 
826         @Override
clientDisconnect(int clientIf, String address, AttributionSource attributionSource, SynchronousResultReceiver receiver)827         public void clientDisconnect(int clientIf, String address,
828                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
829             try {
830                 clientDisconnect(clientIf, address, attributionSource);
831                 receiver.send(null);
832             } catch (RuntimeException e) {
833                 receiver.propagateException(e);
834             }
835         }
clientDisconnect(int clientIf, String address, AttributionSource attributionSource)836         private void clientDisconnect(int clientIf, String address,
837                 AttributionSource attributionSource) {
838             GattService service = getService();
839             if (service == null) {
840                 return;
841             }
842             service.clientDisconnect(clientIf, address, attributionSource);
843         }
844 
845         @Override
clientSetPreferredPhy(int clientIf, String address, int txPhy, int rxPhy, int phyOptions, AttributionSource attributionSource, SynchronousResultReceiver receiver)846         public void clientSetPreferredPhy(int clientIf, String address, int txPhy, int rxPhy,
847                 int phyOptions, AttributionSource attributionSource,
848                 SynchronousResultReceiver receiver) {
849             try {
850                 clientSetPreferredPhy(clientIf, address, txPhy, rxPhy, phyOptions,
851                         attributionSource);
852                 receiver.send(null);
853             } catch (RuntimeException e) {
854                 receiver.propagateException(e);
855             }
856         }
clientSetPreferredPhy(int clientIf, String address, int txPhy, int rxPhy, int phyOptions, AttributionSource attributionSource)857         private void clientSetPreferredPhy(int clientIf, String address, int txPhy, int rxPhy,
858                 int phyOptions, AttributionSource attributionSource) {
859             GattService service = getService();
860             if (service == null) {
861                 return;
862             }
863             service.clientSetPreferredPhy(clientIf, address, txPhy, rxPhy, phyOptions,
864                     attributionSource);
865         }
866 
867         @Override
clientReadPhy(int clientIf, String address, AttributionSource attributionSource, SynchronousResultReceiver receiver)868         public void clientReadPhy(int clientIf, String address,
869                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
870             try {
871                 clientReadPhy(clientIf, address, attributionSource);
872                 receiver.send(null);
873             } catch (RuntimeException e) {
874                 receiver.propagateException(e);
875             }
876         }
clientReadPhy(int clientIf, String address, AttributionSource attributionSource)877         private void clientReadPhy(int clientIf, String address,
878                 AttributionSource attributionSource) {
879             GattService service = getService();
880             if (service == null) {
881                 return;
882             }
883             service.clientReadPhy(clientIf, address, attributionSource);
884         }
885 
886         @Override
refreshDevice(int clientIf, String address, AttributionSource attributionSource, SynchronousResultReceiver receiver)887         public void refreshDevice(int clientIf, String address,
888                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
889             try {
890                 refreshDevice(clientIf, address, attributionSource);
891                 receiver.send(null);
892             } catch (RuntimeException e) {
893                 receiver.propagateException(e);
894             }
895         }
refreshDevice(int clientIf, String address, AttributionSource attributionSource)896         private void refreshDevice(int clientIf, String address,
897                 AttributionSource attributionSource) {
898             GattService service = getService();
899             if (service == null) {
900                 return;
901             }
902             service.refreshDevice(clientIf, address, attributionSource);
903         }
904 
905         @Override
discoverServices(int clientIf, String address, AttributionSource attributionSource, SynchronousResultReceiver receiver)906         public void discoverServices(int clientIf, String address,
907                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
908             try {
909                 discoverServices(clientIf, address, attributionSource);
910                 receiver.send(null);
911             } catch (RuntimeException e) {
912                 receiver.propagateException(e);
913             }
914         }
discoverServices(int clientIf, String address, AttributionSource attributionSource)915         private void discoverServices(int clientIf, String address,
916                 AttributionSource attributionSource) {
917             GattService service = getService();
918             if (service == null) {
919                 return;
920             }
921             service.discoverServices(clientIf, address, attributionSource);
922         }
923 
924         @Override
discoverServiceByUuid(int clientIf, String address, ParcelUuid uuid, AttributionSource attributionSource, SynchronousResultReceiver receiver)925         public void discoverServiceByUuid(int clientIf, String address, ParcelUuid uuid,
926                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
927             try {
928                 discoverServiceByUuid(clientIf, address, uuid, attributionSource);
929                 receiver.send(null);
930             } catch (RuntimeException e) {
931                 receiver.propagateException(e);
932             }
933         }
discoverServiceByUuid(int clientIf, String address, ParcelUuid uuid, AttributionSource attributionSource)934         private void discoverServiceByUuid(int clientIf, String address, ParcelUuid uuid,
935                 AttributionSource attributionSource) {
936             GattService service = getService();
937             if (service == null) {
938                 return;
939             }
940             service.discoverServiceByUuid(clientIf, address, uuid.getUuid(), attributionSource);
941         }
942 
943         @Override
readCharacteristic(int clientIf, String address, int handle, int authReq, AttributionSource attributionSource, SynchronousResultReceiver receiver)944         public void readCharacteristic(int clientIf, String address, int handle, int authReq,
945                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
946             try {
947                 readCharacteristic(clientIf, address, handle, authReq, attributionSource);
948                 receiver.send(null);
949             } catch (RuntimeException e) {
950                 receiver.propagateException(e);
951             }
952         }
readCharacteristic(int clientIf, String address, int handle, int authReq, AttributionSource attributionSource)953         private void readCharacteristic(int clientIf, String address, int handle, int authReq,
954                 AttributionSource attributionSource) {
955             GattService service = getService();
956             if (service == null) {
957                 return;
958             }
959             service.readCharacteristic(clientIf, address, handle, authReq, attributionSource);
960         }
961 
962         @Override
readUsingCharacteristicUuid(int clientIf, String address, ParcelUuid uuid, int startHandle, int endHandle, int authReq, AttributionSource attributionSource, SynchronousResultReceiver receiver)963         public void readUsingCharacteristicUuid(int clientIf, String address, ParcelUuid uuid,
964                 int startHandle, int endHandle, int authReq, AttributionSource attributionSource,
965                 SynchronousResultReceiver receiver) {
966             try {
967                 readUsingCharacteristicUuid(clientIf, address, uuid, startHandle, endHandle,
968                         authReq, attributionSource);
969                 receiver.send(null);
970             } catch (RuntimeException e) {
971                 receiver.propagateException(e);
972             }
973         }
readUsingCharacteristicUuid(int clientIf, String address, ParcelUuid uuid, int startHandle, int endHandle, int authReq, AttributionSource attributionSource)974         private void readUsingCharacteristicUuid(int clientIf, String address, ParcelUuid uuid,
975                 int startHandle, int endHandle, int authReq, AttributionSource attributionSource) {
976             GattService service = getService();
977             if (service == null) {
978                 return;
979             }
980             service.readUsingCharacteristicUuid(clientIf, address, uuid.getUuid(), startHandle,
981                     endHandle, authReq, attributionSource);
982         }
983 
984         @Override
writeCharacteristic(int clientIf, String address, int handle, int writeType, int authReq, byte[] value, AttributionSource attributionSource, SynchronousResultReceiver receiver)985         public void writeCharacteristic(int clientIf, String address, int handle, int writeType,
986                 int authReq, byte[] value, AttributionSource attributionSource,
987                 SynchronousResultReceiver receiver) {
988             try {
989                 receiver.send(writeCharacteristic(clientIf, address, handle, writeType, authReq,
990                             value, attributionSource));
991             } catch (RuntimeException e) {
992                 receiver.propagateException(e);
993             }
994         }
writeCharacteristic(int clientIf, String address, int handle, int writeType, int authReq, byte[] value, AttributionSource attributionSource)995         private int writeCharacteristic(int clientIf, String address, int handle, int writeType,
996                 int authReq, byte[] value, AttributionSource attributionSource) {
997             GattService service = getService();
998             if (service == null) {
999                 return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
1000             }
1001             return service.writeCharacteristic(clientIf, address, handle, writeType, authReq, value,
1002                     attributionSource);
1003         }
1004 
1005         @Override
readDescriptor(int clientIf, String address, int handle, int authReq, AttributionSource attributionSource, SynchronousResultReceiver receiver)1006         public void readDescriptor(int clientIf, String address, int handle, int authReq,
1007                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1008             try {
1009                 readDescriptor(clientIf, address, handle, authReq, attributionSource);
1010                 receiver.send(null);
1011             } catch (RuntimeException e) {
1012                 receiver.propagateException(e);
1013             }
1014         }
readDescriptor(int clientIf, String address, int handle, int authReq, AttributionSource attributionSource)1015         private void readDescriptor(int clientIf, String address, int handle, int authReq,
1016                 AttributionSource attributionSource) {
1017             GattService service = getService();
1018             if (service == null) {
1019                 return;
1020             }
1021             service.readDescriptor(clientIf, address, handle, authReq, attributionSource);
1022         }
1023 
1024         @Override
writeDescriptor(int clientIf, String address, int handle, int authReq, byte[] value, AttributionSource attributionSource, SynchronousResultReceiver receiver)1025         public void writeDescriptor(int clientIf, String address, int handle, int authReq,
1026                 byte[] value, AttributionSource attributionSource,
1027                 SynchronousResultReceiver receiver) {
1028             try {
1029                 receiver.send(writeDescriptor(clientIf, address, handle, authReq, value,
1030                             attributionSource));
1031             } catch (RuntimeException e) {
1032                 receiver.propagateException(e);
1033             }
1034         }
writeDescriptor(int clientIf, String address, int handle, int authReq, byte[] value, AttributionSource attributionSource)1035         private int writeDescriptor(int clientIf, String address, int handle, int authReq,
1036                 byte[] value, AttributionSource attributionSource) {
1037             GattService service = getService();
1038             if (service == null) {
1039                 return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
1040             }
1041             return service.writeDescriptor(clientIf, address, handle, authReq, value,
1042                     attributionSource);
1043         }
1044 
1045         @Override
beginReliableWrite(int clientIf, String address, AttributionSource attributionSource, SynchronousResultReceiver receiver)1046         public void beginReliableWrite(int clientIf, String address,
1047                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1048             try {
1049                 beginReliableWrite(clientIf, address, attributionSource);
1050                 receiver.send(null);
1051             } catch (RuntimeException e) {
1052                 receiver.propagateException(e);
1053             }
1054         }
beginReliableWrite(int clientIf, String address, AttributionSource attributionSource)1055         private void beginReliableWrite(int clientIf, String address,
1056                 AttributionSource attributionSource) {
1057             GattService service = getService();
1058             if (service == null) {
1059                 return;
1060             }
1061             service.beginReliableWrite(clientIf, address, attributionSource);
1062         }
1063 
1064         @Override
endReliableWrite(int clientIf, String address, boolean execute, AttributionSource attributionSource, SynchronousResultReceiver receiver)1065         public void endReliableWrite(int clientIf, String address, boolean execute,
1066                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1067             try {
1068                 endReliableWrite(clientIf, address, execute, attributionSource);
1069                 receiver.send(null);
1070             } catch (RuntimeException e) {
1071                 receiver.propagateException(e);
1072             }
1073         }
endReliableWrite(int clientIf, String address, boolean execute, AttributionSource attributionSource)1074         private void endReliableWrite(int clientIf, String address, boolean execute,
1075                 AttributionSource attributionSource) {
1076             GattService service = getService();
1077             if (service == null) {
1078                 return;
1079             }
1080             service.endReliableWrite(clientIf, address, execute, attributionSource);
1081         }
1082 
1083         @Override
registerForNotification(int clientIf, String address, int handle, boolean enable, AttributionSource attributionSource, SynchronousResultReceiver receiver)1084         public void registerForNotification(int clientIf, String address, int handle,
1085                 boolean enable, AttributionSource attributionSource,
1086                 SynchronousResultReceiver receiver) {
1087             try {
1088                 registerForNotification(clientIf, address, handle, enable, attributionSource);
1089                 receiver.send(null);
1090             } catch (RuntimeException e) {
1091                 receiver.propagateException(e);
1092             }
1093         }
registerForNotification(int clientIf, String address, int handle, boolean enable, AttributionSource attributionSource)1094         private void registerForNotification(int clientIf, String address, int handle,
1095                 boolean enable, AttributionSource attributionSource) {
1096             GattService service = getService();
1097             if (service == null) {
1098                 return;
1099             }
1100             service.registerForNotification(clientIf, address, handle, enable, attributionSource);
1101         }
1102 
1103         @Override
readRemoteRssi(int clientIf, String address, AttributionSource attributionSource, SynchronousResultReceiver receiver)1104         public void readRemoteRssi(int clientIf, String address,
1105                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1106             try {
1107                 readRemoteRssi(clientIf, address, attributionSource);
1108                 receiver.send(null);
1109             } catch (RuntimeException e) {
1110                 receiver.propagateException(e);
1111             }
1112         }
readRemoteRssi(int clientIf, String address, AttributionSource attributionSource)1113         private void readRemoteRssi(int clientIf, String address,
1114                 AttributionSource attributionSource) {
1115             GattService service = getService();
1116             if (service == null) {
1117                 return;
1118             }
1119             service.readRemoteRssi(clientIf, address, attributionSource);
1120         }
1121 
1122         @Override
configureMTU(int clientIf, String address, int mtu, AttributionSource attributionSource, SynchronousResultReceiver receiver)1123         public void configureMTU(int clientIf, String address, int mtu,
1124                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1125             try {
1126                 configureMTU(clientIf, address, mtu, attributionSource);
1127                 receiver.send(null);
1128             } catch (RuntimeException e) {
1129                 receiver.propagateException(e);
1130             }
1131         }
configureMTU(int clientIf, String address, int mtu, AttributionSource attributionSource)1132         private void configureMTU(int clientIf, String address, int mtu,
1133                 AttributionSource attributionSource) {
1134             GattService service = getService();
1135             if (service == null) {
1136                 return;
1137             }
1138             service.configureMTU(clientIf, address, mtu, attributionSource);
1139         }
1140 
1141         @Override
connectionParameterUpdate(int clientIf, String address, int connectionPriority, AttributionSource attributionSource, SynchronousResultReceiver receiver)1142         public void connectionParameterUpdate(int clientIf, String address,
1143                 int connectionPriority, AttributionSource attributionSource,
1144                 SynchronousResultReceiver receiver) {
1145             try {
1146                 connectionParameterUpdate(clientIf, address, connectionPriority, attributionSource);
1147                 receiver.send(null);
1148             } catch (RuntimeException e) {
1149                 receiver.propagateException(e);
1150             }
1151         }
connectionParameterUpdate(int clientIf, String address, int connectionPriority, AttributionSource attributionSource)1152         private void connectionParameterUpdate(int clientIf, String address,
1153                 int connectionPriority, AttributionSource attributionSource) {
1154             GattService service = getService();
1155             if (service == null) {
1156                 return;
1157             }
1158             service.connectionParameterUpdate(
1159                     clientIf, address, connectionPriority, attributionSource);
1160         }
1161 
1162         @Override
leConnectionUpdate(int clientIf, String address, int minConnectionInterval, int maxConnectionInterval, int peripheralLatency, int supervisionTimeout, int minConnectionEventLen, int maxConnectionEventLen, AttributionSource attributionSource, SynchronousResultReceiver receiver)1163         public void leConnectionUpdate(int clientIf, String address,
1164                 int minConnectionInterval, int maxConnectionInterval,
1165                 int peripheralLatency, int supervisionTimeout,
1166                 int minConnectionEventLen, int maxConnectionEventLen,
1167                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1168             try {
1169                 leConnectionUpdate(clientIf, address, minConnectionInterval, maxConnectionInterval,
1170                         peripheralLatency, supervisionTimeout, minConnectionEventLen,
1171                         maxConnectionEventLen, attributionSource);
1172                 receiver.send(null);
1173             } catch (RuntimeException e) {
1174                 receiver.propagateException(e);
1175             }
1176         }
leConnectionUpdate(int clientIf, String address, int minConnectionInterval, int maxConnectionInterval, int peripheralLatency, int supervisionTimeout, int minConnectionEventLen, int maxConnectionEventLen, AttributionSource attributionSource)1177         private void leConnectionUpdate(int clientIf, String address,
1178                 int minConnectionInterval, int maxConnectionInterval,
1179                 int peripheralLatency, int supervisionTimeout,
1180                 int minConnectionEventLen, int maxConnectionEventLen,
1181                 AttributionSource attributionSource) {
1182             GattService service = getService();
1183             if (service == null) {
1184                 return;
1185             }
1186             service.leConnectionUpdate(clientIf, address, minConnectionInterval,
1187                                        maxConnectionInterval, peripheralLatency,
1188                                        supervisionTimeout, minConnectionEventLen,
1189                                        maxConnectionEventLen, attributionSource);
1190         }
1191 
1192         @Override
subrateModeRequest(int clientIf, String address, int subrateMode, AttributionSource attributionSource, SynchronousResultReceiver receiver)1193         public void subrateModeRequest(int clientIf, String address, int subrateMode,
1194                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1195             try {
1196                 subrateModeRequest(clientIf, address, subrateMode, attributionSource);
1197                 receiver.send(null);
1198             } catch (RuntimeException e) {
1199                 receiver.propagateException(e);
1200             }
1201         }
subrateModeRequest(int clientIf, String address, int subrateMode, AttributionSource attributionSource)1202         private void subrateModeRequest(int clientIf, String address, int subrateMode,
1203                 AttributionSource attributionSource) {
1204             GattService service = getService();
1205             if (service == null) {
1206                 return;
1207             }
1208             service.subrateModeRequest(clientIf, address, subrateMode, attributionSource);
1209         }
1210 
1211         @Override
leSubrateRequest(int clientIf, String address, int subrateMin, int subrateMax, int maxLatency, int contNumber, int supervisionTimeout, AttributionSource attributionSource, SynchronousResultReceiver receiver)1212         public void leSubrateRequest(int clientIf, String address, int subrateMin, int subrateMax,
1213                 int maxLatency, int contNumber, int supervisionTimeout,
1214                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1215             try {
1216                 leSubrateRequest(clientIf, address, subrateMin, subrateMax, maxLatency, contNumber,
1217                                  supervisionTimeout, attributionSource);
1218                 receiver.send(null);
1219             } catch (RuntimeException e) {
1220                 receiver.propagateException(e);
1221             }
1222         }
leSubrateRequest(int clientIf, String address, int subrateMin, int subrateMax, int maxLatency, int contNumber, int supervisionTimeout, AttributionSource attributionSource)1223         private void leSubrateRequest(int clientIf, String address, int subrateMin, int subrateMax,
1224                 int maxLatency, int contNumber, int supervisionTimeout,
1225                 AttributionSource attributionSource) {
1226             GattService service = getService();
1227             if (service == null) {
1228                 return;
1229             }
1230             service.leSubrateRequest(clientIf, address, subrateMin, subrateMax, maxLatency,
1231                                      contNumber, supervisionTimeout, attributionSource);
1232         }
1233 
1234         @Override
registerServer(ParcelUuid uuid, IBluetoothGattServerCallback callback, boolean eattSupport, AttributionSource attributionSource, SynchronousResultReceiver receiver)1235         public void registerServer(ParcelUuid uuid, IBluetoothGattServerCallback callback,
1236                 boolean eattSupport, AttributionSource attributionSource,
1237                 SynchronousResultReceiver receiver) {
1238             try {
1239                 registerServer(uuid, callback, eattSupport, attributionSource);
1240                 receiver.send(null);
1241             } catch (RuntimeException e) {
1242                 receiver.propagateException(e);
1243             }
1244         }
registerServer(ParcelUuid uuid, IBluetoothGattServerCallback callback, boolean eatt_support, AttributionSource attributionSource)1245         private void registerServer(ParcelUuid uuid, IBluetoothGattServerCallback callback,
1246                 boolean eatt_support, AttributionSource attributionSource) {
1247             GattService service = getService();
1248             if (service == null) {
1249                 return;
1250             }
1251             service.registerServer(uuid.getUuid(), callback, eatt_support, attributionSource);
1252         }
1253 
1254         @Override
unregisterServer(int serverIf, AttributionSource attributionSource, SynchronousResultReceiver receiver)1255         public void unregisterServer(int serverIf, AttributionSource attributionSource,
1256                 SynchronousResultReceiver receiver) {
1257             try {
1258                 unregisterServer(serverIf, attributionSource);
1259                 receiver.send(null);
1260             } catch (RuntimeException e) {
1261                 receiver.propagateException(e);
1262             }
1263         }
unregisterServer(int serverIf, AttributionSource attributionSource)1264         private void unregisterServer(int serverIf, AttributionSource attributionSource) {
1265             GattService service = getService();
1266             if (service == null) {
1267                 return;
1268             }
1269             service.unregisterServer(serverIf, attributionSource);
1270         }
1271 
1272         @Override
serverConnect(int serverIf, String address, boolean isDirect, int transport, AttributionSource attributionSource, SynchronousResultReceiver receiver)1273         public void serverConnect(int serverIf, String address, boolean isDirect, int transport,
1274                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1275             try {
1276                 serverConnect(serverIf, address, isDirect, transport, attributionSource);
1277                 receiver.send(null);
1278             } catch (RuntimeException e) {
1279                 receiver.propagateException(e);
1280             }
1281         }
serverConnect(int serverIf, String address, boolean isDirect, int transport, AttributionSource attributionSource)1282         private void serverConnect(int serverIf, String address, boolean isDirect, int transport,
1283                 AttributionSource attributionSource) {
1284             GattService service = getService();
1285             if (service == null) {
1286                 return;
1287             }
1288             service.serverConnect(serverIf, address, isDirect, transport, attributionSource);
1289         }
1290 
1291         @Override
serverDisconnect(int serverIf, String address, AttributionSource attributionSource, SynchronousResultReceiver receiver)1292         public void serverDisconnect(int serverIf, String address,
1293                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1294             try {
1295                 serverDisconnect(serverIf, address, attributionSource);
1296                 receiver.send(null);
1297             } catch (RuntimeException e) {
1298                 receiver.propagateException(e);
1299             }
1300         }
serverDisconnect(int serverIf, String address, AttributionSource attributionSource)1301         private void serverDisconnect(int serverIf, String address,
1302                 AttributionSource attributionSource) {
1303             GattService service = getService();
1304             if (service == null) {
1305                 return;
1306             }
1307             service.serverDisconnect(serverIf, address, attributionSource);
1308         }
1309 
1310         @Override
serverSetPreferredPhy(int serverIf, String address, int txPhy, int rxPhy, int phyOptions, AttributionSource attributionSource, SynchronousResultReceiver receiver)1311         public void serverSetPreferredPhy(int serverIf, String address, int txPhy, int rxPhy,
1312                 int phyOptions, AttributionSource attributionSource,
1313                 SynchronousResultReceiver receiver) {
1314             try {
1315                 serverSetPreferredPhy(serverIf, address, txPhy, rxPhy, phyOptions,
1316                         attributionSource);
1317                 receiver.send(null);
1318             } catch (RuntimeException e) {
1319                 receiver.propagateException(e);
1320             }
1321         }
serverSetPreferredPhy(int serverIf, String address, int txPhy, int rxPhy, int phyOptions, AttributionSource attributionSource)1322         private void serverSetPreferredPhy(int serverIf, String address, int txPhy, int rxPhy,
1323                 int phyOptions, AttributionSource attributionSource) {
1324             GattService service = getService();
1325             if (service == null) {
1326                 return;
1327             }
1328             service.serverSetPreferredPhy(
1329                     serverIf, address, txPhy, rxPhy, phyOptions, attributionSource);
1330         }
1331 
1332         @Override
serverReadPhy(int clientIf, String address, AttributionSource attributionSource, SynchronousResultReceiver receiver)1333         public void serverReadPhy(int clientIf, String address, AttributionSource attributionSource,
1334                 SynchronousResultReceiver receiver) {
1335             try {
1336                 serverReadPhy(clientIf, address, attributionSource);
1337                 receiver.send(null);
1338             } catch (RuntimeException e) {
1339                 receiver.propagateException(e);
1340             }
1341         }
serverReadPhy(int clientIf, String address, AttributionSource attributionSource)1342         private void serverReadPhy(int clientIf, String address,
1343                 AttributionSource attributionSource) {
1344             GattService service = getService();
1345             if (service == null) {
1346                 return;
1347             }
1348             service.serverReadPhy(clientIf, address, attributionSource);
1349         }
1350 
1351         @Override
addService(int serverIf, BluetoothGattService svc, AttributionSource attributionSource, SynchronousResultReceiver receiver)1352         public void addService(int serverIf, BluetoothGattService svc,
1353                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1354             try {
1355                 addService(serverIf, svc, attributionSource);
1356                 receiver.send(null);
1357             } catch (RuntimeException e) {
1358                 receiver.propagateException(e);
1359             }
1360         }
addService(int serverIf, BluetoothGattService svc, AttributionSource attributionSource)1361         private void addService(int serverIf, BluetoothGattService svc,
1362                 AttributionSource attributionSource) {
1363             GattService service = getService();
1364             if (service == null) {
1365                 return;
1366             }
1367 
1368             service.addService(serverIf, svc, attributionSource);
1369         }
1370 
1371         @Override
removeService(int serverIf, int handle, AttributionSource attributionSource, SynchronousResultReceiver receiver)1372         public void removeService(int serverIf, int handle, AttributionSource attributionSource,
1373                 SynchronousResultReceiver receiver) {
1374             try {
1375                 removeService(serverIf, handle, attributionSource);
1376                 receiver.send(null);
1377             } catch (RuntimeException e) {
1378                 receiver.propagateException(e);
1379             }
1380         }
removeService(int serverIf, int handle, AttributionSource attributionSource)1381         private void removeService(int serverIf, int handle, AttributionSource attributionSource) {
1382             GattService service = getService();
1383             if (service == null) {
1384                 return;
1385             }
1386             service.removeService(serverIf, handle, attributionSource);
1387         }
1388 
1389         @Override
clearServices(int serverIf, AttributionSource attributionSource, SynchronousResultReceiver receiver)1390         public void clearServices(int serverIf, AttributionSource attributionSource,
1391                 SynchronousResultReceiver receiver) {
1392             try {
1393                 clearServices(serverIf, attributionSource);
1394                 receiver.send(null);
1395             } catch (RuntimeException e) {
1396                 receiver.propagateException(e);
1397             }
1398         }
clearServices(int serverIf, AttributionSource attributionSource)1399         private void clearServices(int serverIf, AttributionSource attributionSource) {
1400             GattService service = getService();
1401             if (service == null) {
1402                 return;
1403             }
1404             service.clearServices(serverIf, attributionSource);
1405         }
1406 
1407         @Override
sendResponse(int serverIf, String address, int requestId, int status, int offset, byte[] value, AttributionSource attributionSource, SynchronousResultReceiver receiver)1408         public void sendResponse(int serverIf, String address, int requestId, int status,
1409                 int offset, byte[] value, AttributionSource attributionSource,
1410                 SynchronousResultReceiver receiver) {
1411             try {
1412                 sendResponse(serverIf, address, requestId, status, offset, value,
1413                         attributionSource);
1414                 receiver.send(null);
1415             } catch (RuntimeException e) {
1416                 receiver.propagateException(e);
1417             }
1418         }
sendResponse(int serverIf, String address, int requestId, int status, int offset, byte[] value, AttributionSource attributionSource)1419         private void sendResponse(int serverIf, String address, int requestId, int status,
1420                 int offset, byte[] value, AttributionSource attributionSource) {
1421             GattService service = getService();
1422             if (service == null) {
1423                 return;
1424             }
1425             service.sendResponse(
1426                     serverIf, address, requestId, status, offset, value, attributionSource);
1427         }
1428 
1429         @Override
sendNotification(int serverIf, String address, int handle, boolean confirm, byte[] value, AttributionSource attributionSource, SynchronousResultReceiver receiver)1430         public void sendNotification(int serverIf, String address, int handle, boolean confirm,
1431                 byte[] value, AttributionSource attributionSource,
1432                 SynchronousResultReceiver receiver) {
1433             try {
1434                 receiver.send(sendNotification(serverIf, address, handle, confirm, value,
1435                             attributionSource));
1436             } catch (RuntimeException e) {
1437                 receiver.propagateException(e);
1438             }
1439         }
sendNotification(int serverIf, String address, int handle, boolean confirm, byte[] value, AttributionSource attributionSource)1440         private int sendNotification(int serverIf, String address, int handle, boolean confirm,
1441                 byte[] value, AttributionSource attributionSource) {
1442             GattService service = getService();
1443             if (service == null) {
1444                 return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
1445             }
1446             return service.sendNotification(serverIf, address, handle, confirm, value,
1447                 attributionSource);
1448         }
1449 
1450         @Override
startAdvertisingSet(AdvertisingSetParameters parameters, AdvertiseData advertiseData, AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData, int duration, int maxExtAdvEvents, int serverIf, IAdvertisingSetCallback callback, AttributionSource attributionSource, SynchronousResultReceiver receiver)1451         public void startAdvertisingSet(AdvertisingSetParameters parameters,
1452                 AdvertiseData advertiseData, AdvertiseData scanResponse,
1453                 PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData,
1454                 int duration, int maxExtAdvEvents, int serverIf, IAdvertisingSetCallback callback,
1455                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1456             try {
1457                 startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
1458                         periodicData, duration, maxExtAdvEvents, serverIf, callback,
1459                         attributionSource);
1460                 receiver.send(null);
1461             } catch (RuntimeException e) {
1462                 receiver.propagateException(e);
1463             }
1464         }
startAdvertisingSet(AdvertisingSetParameters parameters, AdvertiseData advertiseData, AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData, int duration, int maxExtAdvEvents, int serverIf, IAdvertisingSetCallback callback, AttributionSource attributionSource)1465         private void startAdvertisingSet(AdvertisingSetParameters parameters,
1466                 AdvertiseData advertiseData, AdvertiseData scanResponse,
1467                 PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData,
1468                 int duration, int maxExtAdvEvents, int serverIf, IAdvertisingSetCallback callback,
1469                 AttributionSource attributionSource) {
1470             GattService service = getService();
1471             if (service == null) {
1472                 return;
1473             }
1474             service.startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
1475                     periodicData, duration, maxExtAdvEvents, serverIf, callback, attributionSource);
1476         }
1477 
1478         @Override
stopAdvertisingSet(IAdvertisingSetCallback callback, AttributionSource attributionSource, SynchronousResultReceiver receiver)1479         public void stopAdvertisingSet(IAdvertisingSetCallback callback,
1480                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1481             try {
1482                 stopAdvertisingSet(callback, attributionSource);
1483                 receiver.send(null);
1484             } catch (RuntimeException e) {
1485                 receiver.propagateException(e);
1486             }
1487         }
stopAdvertisingSet(IAdvertisingSetCallback callback, AttributionSource attributionSource)1488         private void stopAdvertisingSet(IAdvertisingSetCallback callback,
1489                 AttributionSource attributionSource) {
1490             GattService service = getService();
1491             if (service == null) {
1492                 return;
1493             }
1494             service.stopAdvertisingSet(callback, attributionSource);
1495         }
1496 
1497         @Override
getOwnAddress(int advertiserId, AttributionSource attributionSource, SynchronousResultReceiver receiver)1498         public void getOwnAddress(int advertiserId, AttributionSource attributionSource,
1499                 SynchronousResultReceiver receiver) {
1500             try {
1501                 getOwnAddress(advertiserId, attributionSource);
1502                 receiver.send(null);
1503             } catch (RuntimeException e) {
1504                 receiver.propagateException(e);
1505             }
1506         }
getOwnAddress(int advertiserId, AttributionSource attributionSource)1507         private void getOwnAddress(int advertiserId, AttributionSource attributionSource) {
1508             GattService service = getService();
1509             if (service == null) {
1510                 return;
1511             }
1512             service.getOwnAddress(advertiserId, attributionSource);
1513         }
1514 
1515         @Override
enableAdvertisingSet(int advertiserId, boolean enable, int duration, int maxExtAdvEvents, AttributionSource attributionSource, SynchronousResultReceiver receiver)1516         public void enableAdvertisingSet(int advertiserId, boolean enable, int duration,
1517                 int maxExtAdvEvents, AttributionSource attributionSource,
1518                 SynchronousResultReceiver receiver) {
1519             try {
1520                 enableAdvertisingSet(advertiserId, enable, duration, maxExtAdvEvents,
1521                         attributionSource);
1522                 receiver.send(null);
1523             } catch (RuntimeException e) {
1524                 receiver.propagateException(e);
1525             }
1526         }
enableAdvertisingSet(int advertiserId, boolean enable, int duration, int maxExtAdvEvents, AttributionSource attributionSource)1527         private void enableAdvertisingSet(int advertiserId, boolean enable, int duration,
1528                 int maxExtAdvEvents, AttributionSource attributionSource) {
1529             GattService service = getService();
1530             if (service == null) {
1531                 return;
1532             }
1533             service.enableAdvertisingSet(
1534                     advertiserId, enable, duration, maxExtAdvEvents, attributionSource);
1535         }
1536 
1537         @Override
setAdvertisingData(int advertiserId, AdvertiseData data, AttributionSource attributionSource, SynchronousResultReceiver receiver)1538         public void setAdvertisingData(int advertiserId, AdvertiseData data,
1539                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1540             try {
1541                 setAdvertisingData(advertiserId, data, attributionSource);
1542                 receiver.send(null);
1543             } catch (RuntimeException e) {
1544                 receiver.propagateException(e);
1545             }
1546         }
setAdvertisingData(int advertiserId, AdvertiseData data, AttributionSource attributionSource)1547         private void setAdvertisingData(int advertiserId, AdvertiseData data,
1548                 AttributionSource attributionSource) {
1549             GattService service = getService();
1550             if (service == null) {
1551                 return;
1552             }
1553             service.setAdvertisingData(advertiserId, data, attributionSource);
1554         }
1555 
1556         @Override
setScanResponseData(int advertiserId, AdvertiseData data, AttributionSource attributionSource, SynchronousResultReceiver receiver)1557         public void setScanResponseData(int advertiserId, AdvertiseData data,
1558                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1559             try {
1560                 setScanResponseData(advertiserId, data, attributionSource);
1561                 receiver.send(null);
1562             } catch (RuntimeException e) {
1563                 receiver.propagateException(e);
1564             }
1565         }
setScanResponseData(int advertiserId, AdvertiseData data, AttributionSource attributionSource)1566         private void setScanResponseData(int advertiserId, AdvertiseData data,
1567                 AttributionSource attributionSource) {
1568             GattService service = getService();
1569             if (service == null) {
1570                 return;
1571             }
1572             service.setScanResponseData(advertiserId, data, attributionSource);
1573         }
1574 
1575         @Override
setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters, AttributionSource attributionSource, SynchronousResultReceiver receiver)1576         public void setAdvertisingParameters(int advertiserId,
1577                 AdvertisingSetParameters parameters, AttributionSource attributionSource,
1578                 SynchronousResultReceiver receiver) {
1579             try {
1580                 setAdvertisingParameters(advertiserId, parameters, attributionSource);
1581                 receiver.send(null);
1582             } catch (RuntimeException e) {
1583                 receiver.propagateException(e);
1584             }
1585         }
setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters, AttributionSource attributionSource)1586         private void setAdvertisingParameters(int advertiserId,
1587                 AdvertisingSetParameters parameters, AttributionSource attributionSource) {
1588             GattService service = getService();
1589             if (service == null) {
1590                 return;
1591             }
1592             service.setAdvertisingParameters(advertiserId, parameters, attributionSource);
1593         }
1594 
1595         @Override
setPeriodicAdvertisingParameters(int advertiserId, PeriodicAdvertisingParameters parameters, AttributionSource attributionSource, SynchronousResultReceiver receiver)1596         public void setPeriodicAdvertisingParameters(int advertiserId,
1597                 PeriodicAdvertisingParameters parameters, AttributionSource attributionSource,
1598                 SynchronousResultReceiver receiver) {
1599             try {
1600                 setPeriodicAdvertisingParameters(advertiserId, parameters, attributionSource);
1601                 receiver.send(null);
1602             } catch (RuntimeException e) {
1603                 receiver.propagateException(e);
1604             }
1605         }
setPeriodicAdvertisingParameters(int advertiserId, PeriodicAdvertisingParameters parameters, AttributionSource attributionSource)1606         private void setPeriodicAdvertisingParameters(int advertiserId,
1607                 PeriodicAdvertisingParameters parameters, AttributionSource attributionSource) {
1608             GattService service = getService();
1609             if (service == null) {
1610                 return;
1611             }
1612             service.setPeriodicAdvertisingParameters(advertiserId, parameters, attributionSource);
1613         }
1614 
1615         @Override
setPeriodicAdvertisingData(int advertiserId, AdvertiseData data, AttributionSource attributionSource, SynchronousResultReceiver receiver)1616         public void setPeriodicAdvertisingData(int advertiserId, AdvertiseData data,
1617                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1618             try {
1619                 setPeriodicAdvertisingData(advertiserId, data, attributionSource);
1620                 receiver.send(null);
1621             } catch (RuntimeException e) {
1622                 receiver.propagateException(e);
1623             }
1624         }
setPeriodicAdvertisingData(int advertiserId, AdvertiseData data, AttributionSource attributionSource)1625         private void setPeriodicAdvertisingData(int advertiserId, AdvertiseData data,
1626                 AttributionSource attributionSource) {
1627             GattService service = getService();
1628             if (service == null) {
1629                 return;
1630             }
1631             service.setPeriodicAdvertisingData(advertiserId, data, attributionSource);
1632         }
1633 
1634         @Override
setPeriodicAdvertisingEnable(int advertiserId, boolean enable, AttributionSource attributionSource, SynchronousResultReceiver receiver)1635         public void setPeriodicAdvertisingEnable(int advertiserId, boolean enable,
1636                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1637             try {
1638                 setPeriodicAdvertisingEnable(advertiserId, enable, attributionSource);
1639                 receiver.send(null);
1640             } catch (RuntimeException e) {
1641                 receiver.propagateException(e);
1642             }
1643         }
setPeriodicAdvertisingEnable(int advertiserId, boolean enable, AttributionSource attributionSource)1644         private void setPeriodicAdvertisingEnable(int advertiserId, boolean enable,
1645                 AttributionSource attributionSource) {
1646             GattService service = getService();
1647             if (service == null) {
1648                 return;
1649             }
1650             service.setPeriodicAdvertisingEnable(advertiserId, enable, attributionSource);
1651         }
1652 
1653         @Override
registerSync(ScanResult scanResult, int skip, int timeout, IPeriodicAdvertisingCallback callback, AttributionSource attributionSource, SynchronousResultReceiver receiver)1654         public void registerSync(ScanResult scanResult, int skip, int timeout,
1655                 IPeriodicAdvertisingCallback callback, AttributionSource attributionSource,
1656                 SynchronousResultReceiver receiver) {
1657             try {
1658                 registerSync(scanResult, skip, timeout, callback, attributionSource);
1659                 receiver.send(null);
1660             } catch (RuntimeException e) {
1661                 receiver.propagateException(e);
1662             }
1663         }
registerSync(ScanResult scanResult, int skip, int timeout, IPeriodicAdvertisingCallback callback, AttributionSource attributionSource)1664         private void registerSync(ScanResult scanResult, int skip, int timeout,
1665                 IPeriodicAdvertisingCallback callback, AttributionSource attributionSource) {
1666             GattService service = getService();
1667             if (service == null) {
1668                 return;
1669             }
1670             service.registerSync(scanResult, skip, timeout, callback, attributionSource);
1671         }
1672 
1673         @Override
transferSync(BluetoothDevice bda, int serviceData , int syncHandle, AttributionSource attributionSource, SynchronousResultReceiver receiver)1674         public void transferSync(BluetoothDevice bda, int serviceData , int syncHandle,
1675                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1676             try {
1677                 transferSync(bda, serviceData , syncHandle, attributionSource);
1678                 receiver.send(null);
1679             } catch (RuntimeException e) {
1680                 receiver.propagateException(e);
1681             }
1682         }
transferSync(BluetoothDevice bda, int serviceData , int syncHandle, AttributionSource attributionSource)1683         public void transferSync(BluetoothDevice bda, int serviceData , int syncHandle,
1684                 AttributionSource attributionSource) {
1685             GattService service = getService();
1686             if (service == null) {
1687                 return;
1688             }
1689             service.transferSync(bda, serviceData , syncHandle, attributionSource);
1690         }
1691 
1692         @Override
transferSetInfo(BluetoothDevice bda, int serviceData , int advHandle, IPeriodicAdvertisingCallback callback, AttributionSource attributionSource, SynchronousResultReceiver receiver)1693         public void transferSetInfo(BluetoothDevice bda, int serviceData , int advHandle,
1694                 IPeriodicAdvertisingCallback callback, AttributionSource attributionSource,
1695                 SynchronousResultReceiver receiver) {
1696             try {
1697                 transferSetInfo(bda, serviceData , advHandle, callback, attributionSource);
1698                 receiver.send(null);
1699             } catch (RuntimeException e) {
1700                 receiver.propagateException(e);
1701             }
1702         }
transferSetInfo(BluetoothDevice bda, int serviceData , int advHandle, IPeriodicAdvertisingCallback callback, AttributionSource attributionSource)1703         public void transferSetInfo(BluetoothDevice bda, int serviceData , int advHandle,
1704                 IPeriodicAdvertisingCallback callback, AttributionSource attributionSource) {
1705             GattService service = getService();
1706             if (service == null) {
1707                 return;
1708             }
1709             service.transferSetInfo(bda, serviceData , advHandle, callback, attributionSource);
1710         }
1711 
1712         @Override
unregisterSync(IPeriodicAdvertisingCallback callback, AttributionSource attributionSource, SynchronousResultReceiver receiver)1713         public void unregisterSync(IPeriodicAdvertisingCallback callback,
1714                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1715             try {
1716                 unregisterSync(callback, attributionSource);
1717                 receiver.send(null);
1718             } catch (RuntimeException e) {
1719                 receiver.propagateException(e);
1720             }
1721         }
unregisterSync(IPeriodicAdvertisingCallback callback, AttributionSource attributionSource)1722         public void unregisterSync(IPeriodicAdvertisingCallback callback,
1723                 AttributionSource attributionSource) {
1724             GattService service = getService();
1725             if (service == null) {
1726                 return;
1727             }
1728             service.unregisterSync(callback, attributionSource);
1729         }
1730 
1731         @Override
disconnectAll(AttributionSource attributionSource, SynchronousResultReceiver receiver)1732         public void disconnectAll(AttributionSource attributionSource,
1733                 SynchronousResultReceiver receiver) {
1734             try {
1735                 disconnectAll(attributionSource);
1736                 receiver.send(null);
1737             } catch (RuntimeException e) {
1738                 receiver.propagateException(e);
1739             }
1740         }
disconnectAll(AttributionSource attributionSource)1741         private void disconnectAll(AttributionSource attributionSource) {
1742             GattService service = getService();
1743             if (service == null) {
1744                 return;
1745             }
1746             service.disconnectAll(attributionSource);
1747         }
1748 
1749         @Override
unregAll(AttributionSource source, SynchronousResultReceiver receiver)1750         public void unregAll(AttributionSource source, SynchronousResultReceiver receiver) {
1751             try {
1752                 unregAll(source);
1753                 receiver.send(null);
1754             } catch (RuntimeException e) {
1755                 receiver.propagateException(e);
1756             }
1757         }
unregAll(AttributionSource attributionSource)1758         private void unregAll(AttributionSource attributionSource) {
1759             GattService service = getService();
1760             if (service == null) {
1761                 return;
1762             }
1763             service.unregAll(attributionSource);
1764         }
1765 
1766         @Override
numHwTrackFiltersAvailable(AttributionSource attributionSource, SynchronousResultReceiver receiver)1767         public void numHwTrackFiltersAvailable(AttributionSource attributionSource,
1768                 SynchronousResultReceiver receiver) {
1769             try {
1770                 receiver.send(numHwTrackFiltersAvailable(attributionSource));
1771             } catch (RuntimeException e) {
1772                 receiver.propagateException(e);
1773             }
1774         }
numHwTrackFiltersAvailable(AttributionSource attributionSource)1775         private int numHwTrackFiltersAvailable(AttributionSource attributionSource) {
1776             GattService service = getService();
1777             if (service == null) {
1778                 return 0;
1779             }
1780             return service.numHwTrackFiltersAvailable(attributionSource);
1781         }
1782 
1783         @Override
getSupportedDistanceMeasurementMethods(AttributionSource attributionSource, SynchronousResultReceiver receiver)1784         public void getSupportedDistanceMeasurementMethods(AttributionSource attributionSource,
1785                 SynchronousResultReceiver receiver) {
1786             try {
1787                 receiver.send(getSupportedDistanceMeasurementMethods(attributionSource));
1788             } catch (RuntimeException e) {
1789                 receiver.propagateException(e);
1790             }
1791         }
1792 
getSupportedDistanceMeasurementMethods( AttributionSource attributionSource)1793         private List<DistanceMeasurementMethod> getSupportedDistanceMeasurementMethods(
1794                 AttributionSource attributionSource) {
1795             GattService service = getService();
1796             if (service == null || !callerIsSystemOrActiveOrManagedUser(service, TAG,
1797                     "GattService getSupportedDistanceMeasurementMethods")
1798                     || !Utils.checkConnectPermissionForDataDelivery(
1799                     service, attributionSource,
1800                     "GattService getSupportedDistanceMeasurementMethods")) {
1801                 return new ArrayList<>();
1802             }
1803             enforceBluetoothPrivilegedPermission(service);
1804             return Arrays.asList(service.getSupportedDistanceMeasurementMethods());
1805         }
1806 
1807         @Override
startDistanceMeasurement(ParcelUuid uuid, DistanceMeasurementParams distanceMeasurementParams, IDistanceMeasurementCallback callback, AttributionSource attributionSource, SynchronousResultReceiver receiver)1808         public void startDistanceMeasurement(ParcelUuid uuid,
1809                 DistanceMeasurementParams distanceMeasurementParams,
1810                 IDistanceMeasurementCallback callback, AttributionSource attributionSource,
1811                 SynchronousResultReceiver receiver) {
1812             try {
1813                 startDistanceMeasurement(uuid, distanceMeasurementParams, callback,
1814                         attributionSource);
1815                 receiver.send(null);
1816             } catch (RuntimeException e) {
1817                 receiver.propagateException(e);
1818             }
1819         }
1820 
startDistanceMeasurement(ParcelUuid uuid, DistanceMeasurementParams distanceMeasurementParams, IDistanceMeasurementCallback callback, AttributionSource attributionSource)1821         private void startDistanceMeasurement(ParcelUuid uuid,
1822                 DistanceMeasurementParams distanceMeasurementParams,
1823                 IDistanceMeasurementCallback callback, AttributionSource attributionSource) {
1824             GattService service = getService();
1825             if (service == null || !callerIsSystemOrActiveOrManagedUser(service, TAG,
1826                     "startDistanceMeasurement") || !Utils.checkConnectPermissionForDataDelivery(
1827                     service, attributionSource, "GattService startDistanceMeasurement")) {
1828                 return;
1829             }
1830             enforceBluetoothPrivilegedPermission(service);
1831             service.startDistanceMeasurement(uuid.getUuid(), distanceMeasurementParams, callback);
1832         }
1833 
1834         @Override
stopDistanceMeasurement(ParcelUuid uuid, BluetoothDevice device, int method, AttributionSource attributionSource, SynchronousResultReceiver receiver)1835         public void stopDistanceMeasurement(ParcelUuid uuid, BluetoothDevice device, int method,
1836                 AttributionSource attributionSource, SynchronousResultReceiver receiver) {
1837             try {
1838                 receiver.send(stopDistanceMeasurement(uuid, device, method, attributionSource));
1839             } catch (RuntimeException e) {
1840                 receiver.propagateException(e);
1841             }
1842         }
1843 
stopDistanceMeasurement(ParcelUuid uuid, BluetoothDevice device, int method, AttributionSource attributionSource)1844         private int stopDistanceMeasurement(ParcelUuid uuid, BluetoothDevice device, int method,
1845                 AttributionSource attributionSource) {
1846             GattService service = getService();
1847             if (service == null) {
1848                 return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
1849             } else if (!callerIsSystemOrActiveOrManagedUser(service, TAG,
1850                     "stopDistanceMeasurement")) {
1851                 return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED;
1852             } else if (!Utils.checkConnectPermissionForDataDelivery(
1853                     service, attributionSource, "GattService stopDistanceMeasurement")) {
1854                 return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION;
1855             }
1856             enforceBluetoothPrivilegedPermission(service);
1857             return service.stopDistanceMeasurement(uuid.getUuid(), device, method);
1858         }
1859     };
1860 
1861     /**************************************************************************
1862      * Callback functions - CLIENT
1863      *************************************************************************/
1864 
1865     // EN format defined here:
1866     // https://blog.google/documents/70/Exposure_Notification_-_Bluetooth_Specification_v1.2.2.pdf
1867     private static final byte[] EXPOSURE_NOTIFICATION_FLAGS_PREAMBLE = new byte[] {
1868         // size 2, flag field, flags byte (value is not important)
1869         (byte) 0x02, (byte) 0x01
1870     };
1871     private static final int EXPOSURE_NOTIFICATION_FLAGS_LENGTH = 0x2 + 1;
1872     private static final byte[] EXPOSURE_NOTIFICATION_PAYLOAD_PREAMBLE = new byte[] {
1873         // size 3, complete 16 bit UUID, EN UUID
1874         (byte) 0x03, (byte) 0x03, (byte) 0x6F, (byte) 0xFD,
1875         // size 23, data for 16 bit UUID, EN UUID
1876         (byte) 0x17, (byte) 0x16, (byte) 0x6F, (byte) 0xFD,
1877         // ...payload
1878     };
1879     private static final int EXPOSURE_NOTIFICATION_PAYLOAD_LENGTH = 0x03 + 0x17 + 2;
1880 
arrayStartsWith(byte[] array, byte[] prefix)1881     private static boolean arrayStartsWith(byte[] array, byte[] prefix) {
1882         if (array.length < prefix.length) {
1883             return false;
1884         }
1885         for (int i = 0; i < prefix.length; i++) {
1886             if (prefix[i] != array[i]) {
1887                 return false;
1888             }
1889         }
1890         return true;
1891     }
1892 
getSanitizedExposureNotification(ScanResult result)1893     ScanResult getSanitizedExposureNotification(ScanResult result) {
1894         ScanRecord record = result.getScanRecord();
1895         // Remove the flags part of the payload, if present
1896         if (record.getBytes().length > EXPOSURE_NOTIFICATION_FLAGS_LENGTH
1897                 && arrayStartsWith(record.getBytes(), EXPOSURE_NOTIFICATION_FLAGS_PREAMBLE)) {
1898             record = ScanRecord.parseFromBytes(
1899                     Arrays.copyOfRange(
1900                             record.getBytes(),
1901                             EXPOSURE_NOTIFICATION_FLAGS_LENGTH,
1902                             record.getBytes().length));
1903         }
1904 
1905         if (record.getBytes().length != EXPOSURE_NOTIFICATION_PAYLOAD_LENGTH) {
1906             return null;
1907         }
1908         if (!arrayStartsWith(record.getBytes(), EXPOSURE_NOTIFICATION_PAYLOAD_PREAMBLE)) {
1909             return null;
1910         }
1911 
1912         return new ScanResult(null, 0, 0, 0, 0, 0, result.getRssi(), 0, record, 0);
1913     }
1914 
onScanResult(int eventType, int addressType, String address, int primaryPhy, int secondaryPhy, int advertisingSid, int txPower, int rssi, int periodicAdvInt, byte[] advData, String originalAddress)1915     void onScanResult(int eventType, int addressType, String address, int primaryPhy,
1916             int secondaryPhy, int advertisingSid, int txPower, int rssi, int periodicAdvInt,
1917             byte[] advData, String originalAddress) {
1918         // When in testing mode, ignore all real-world events
1919         if (isTestModeEnabled()) return;
1920 
1921         AppScanStats.recordScanRadioResultCount();
1922         onScanResultInternal(eventType, addressType, address, primaryPhy, secondaryPhy,
1923                 advertisingSid, txPower, rssi, periodicAdvInt, advData, originalAddress);
1924     }
1925 
onScanResultInternal(int eventType, int addressType, String address, int primaryPhy, int secondaryPhy, int advertisingSid, int txPower, int rssi, int periodicAdvInt, byte[] advData, String originalAddress)1926     void onScanResultInternal(int eventType, int addressType, String address, int primaryPhy,
1927             int secondaryPhy, int advertisingSid, int txPower, int rssi, int periodicAdvInt,
1928             byte[] advData, String originalAddress) {
1929         if (VDBG) {
1930             Log.d(TAG, "onScanResult() - eventType=0x" + Integer.toHexString(eventType)
1931                     + ", addressType=" + addressType + ", address=" + address + ", primaryPhy="
1932                     + primaryPhy + ", secondaryPhy=" + secondaryPhy + ", advertisingSid=0x"
1933                     + Integer.toHexString(advertisingSid) + ", txPower=" + txPower + ", rssi="
1934                     + rssi + ", periodicAdvInt=0x" + Integer.toHexString(periodicAdvInt)
1935                     + ", originalAddress=" + originalAddress);
1936         }
1937 
1938         String identityAddress = mAdapterService.getIdentityAddress(address);
1939         if (!address.equals(identityAddress)) {
1940             if (VDBG) {
1941                 Log.d(TAG, "found identityAddress of " + address + ", replace originalAddress as "
1942                         + identityAddress);
1943             }
1944             originalAddress = identityAddress;
1945         }
1946 
1947 
1948         byte[] legacyAdvData = Arrays.copyOfRange(advData, 0, 62);
1949 
1950         for (ScanClient client : mScanManager.getRegularScanQueue()) {
1951             ScannerMap.App app = mScannerMap.getById(client.scannerId);
1952             if (app == null) {
1953                 if (VDBG) {
1954                     Log.d(TAG, "App is null; skip.");
1955                 }
1956                 continue;
1957             }
1958 
1959             BluetoothDevice device =
1960                 BluetoothAdapter.getDefaultAdapter().getRemoteLeDevice(address, addressType);
1961 
1962             ScanSettings settings = client.settings;
1963             byte[] scanRecordData;
1964             // This is for compability with applications that assume fixed size scan data.
1965             if (settings.getLegacy()) {
1966                 if ((eventType & ET_LEGACY_MASK) == 0) {
1967                     // If this is legacy scan, but nonlegacy result - skip.
1968                     if (VDBG) {
1969                         Log.d(TAG, "Legacy scan, non legacy result; skip.");
1970                     }
1971                     continue;
1972                 } else {
1973                     // Some apps are used to fixed-size advertise data.
1974                     scanRecordData = legacyAdvData;
1975                 }
1976             } else {
1977                 scanRecordData = advData;
1978             }
1979 
1980             ScanRecord scanRecord = ScanRecord.parseFromBytes(scanRecordData);
1981             ScanResult result =
1982                     new ScanResult(device, eventType, primaryPhy, secondaryPhy, advertisingSid,
1983                             txPower, rssi, periodicAdvInt, scanRecord,
1984                             SystemClock.elapsedRealtimeNanos());
1985 
1986             if (client.hasDisavowedLocation) {
1987                 if (mLocationDenylistPredicate.test(result)) {
1988                     Log.i(TAG, "Skipping client for location deny list");
1989                     continue;
1990                 }
1991             }
1992 
1993             boolean hasPermission = hasScanResultPermission(client);
1994             if (!hasPermission) {
1995                 for (String associatedDevice : client.associatedDevices) {
1996                     if (associatedDevice.equalsIgnoreCase(address)) {
1997                         hasPermission = true;
1998                         break;
1999                     }
2000                 }
2001             }
2002             if (!hasPermission && client.eligibleForSanitizedExposureNotification) {
2003                 ScanResult sanitized = getSanitizedExposureNotification(result);
2004                 if (sanitized != null) {
2005                     hasPermission = true;
2006                     result = sanitized;
2007                 }
2008             }
2009             MatchResult matchResult = matchesFilters(client, result, originalAddress);
2010             if (!hasPermission || !matchResult.getMatches()) {
2011                 if (VDBG) {
2012                     Log.d(TAG, "Skipping client: permission="
2013                             + hasPermission + " matches=" + matchResult.getMatches());
2014                 }
2015                 continue;
2016             }
2017 
2018             int callbackType = settings.getCallbackType();
2019             if (!(callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES
2020                     || callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES_AUTO_BATCH)) {
2021                 if (VDBG) {
2022                     Log.d(TAG, "Skipping client: CALLBACK_TYPE_ALL_MATCHES");
2023                 }
2024                 continue;
2025             }
2026 
2027             try {
2028                 app.appScanStats.addResult(client.scannerId);
2029                 if (app.callback != null) {
2030                     app.callback.onScanResult(result);
2031                 } else {
2032                     // Send the PendingIntent
2033                     ArrayList<ScanResult> results = new ArrayList<>();
2034                     results.add(result);
2035                     sendResultsByPendingIntent(app.info, results,
2036                             ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
2037                 }
2038             } catch (RemoteException | PendingIntent.CanceledException e) {
2039                 Log.e(TAG, "Exception: " + e);
2040                 mScannerMap.remove(client.scannerId);
2041                 mScanManager.stopScan(client.scannerId);
2042             }
2043         }
2044     }
2045 
sendResultByPendingIntent(PendingIntentInfo pii, ScanResult result, int callbackType, ScanClient client)2046     private void sendResultByPendingIntent(PendingIntentInfo pii, ScanResult result,
2047             int callbackType, ScanClient client) {
2048         ArrayList<ScanResult> results = new ArrayList<>();
2049         results.add(result);
2050         try {
2051             sendResultsByPendingIntent(pii, results, callbackType);
2052         } catch (PendingIntent.CanceledException e) {
2053             final long token = Binder.clearCallingIdentity();
2054             try {
2055                 stopScan(client.scannerId, getAttributionSource());
2056                 unregisterScanner(client.scannerId, getAttributionSource());
2057             } finally {
2058                 Binder.restoreCallingIdentity(token);
2059             }
2060         }
2061     }
2062 
sendResultsByPendingIntent(PendingIntentInfo pii, ArrayList<ScanResult> results, int callbackType)2063     private void sendResultsByPendingIntent(PendingIntentInfo pii, ArrayList<ScanResult> results,
2064             int callbackType) throws PendingIntent.CanceledException {
2065         Intent extrasIntent = new Intent();
2066         extrasIntent.putParcelableArrayListExtra(BluetoothLeScanner.EXTRA_LIST_SCAN_RESULT,
2067                 results);
2068         extrasIntent.putExtra(BluetoothLeScanner.EXTRA_CALLBACK_TYPE, callbackType);
2069         pii.intent.send(this, 0, extrasIntent);
2070     }
2071 
sendErrorByPendingIntent(PendingIntentInfo pii, int errorCode)2072     private void sendErrorByPendingIntent(PendingIntentInfo pii, int errorCode)
2073             throws PendingIntent.CanceledException {
2074         Intent extrasIntent = new Intent();
2075         extrasIntent.putExtra(BluetoothLeScanner.EXTRA_ERROR_CODE, errorCode);
2076         pii.intent.send(this, 0, extrasIntent);
2077     }
2078 
onScannerRegistered(int status, int scannerId, long uuidLsb, long uuidMsb)2079     void onScannerRegistered(int status, int scannerId, long uuidLsb, long uuidMsb)
2080             throws RemoteException {
2081         UUID uuid = new UUID(uuidMsb, uuidLsb);
2082         if (DBG) {
2083             Log.d(TAG, "onScannerRegistered() - UUID=" + uuid + ", scannerId=" + scannerId
2084                     + ", status=" + status);
2085         }
2086 
2087         // First check the callback map
2088         ScannerMap.App cbApp = mScannerMap.getByUuid(uuid);
2089         if (cbApp != null) {
2090             if (status == 0) {
2091                 cbApp.id = scannerId;
2092                 // If app is callback based, setup a death recipient. App will initiate the start.
2093                 // Otherwise, if PendingIntent based, start the scan directly.
2094                 if (cbApp.callback != null) {
2095                     cbApp.linkToDeath(new ScannerDeathRecipient(scannerId));
2096                 } else {
2097                     continuePiStartScan(scannerId, cbApp);
2098                 }
2099             } else {
2100                 mScannerMap.remove(scannerId);
2101             }
2102             if (cbApp.callback != null) {
2103                 cbApp.callback.onScannerRegistered(status, scannerId);
2104             }
2105         }
2106     }
2107 
2108     /** Determines if the given scan client has the appropriate permissions to receive callbacks. */
hasScanResultPermission(final ScanClient client)2109     private boolean hasScanResultPermission(final ScanClient client) {
2110         if (client.hasNetworkSettingsPermission
2111                 || client.hasNetworkSetupWizardPermission
2112                 || client.hasScanWithoutLocationPermission) {
2113             return true;
2114         }
2115         if (client.hasDisavowedLocation) {
2116             return true;
2117         }
2118         return client.hasLocationPermission && !Utils.blockedByLocationOff(this, client.userHandle);
2119     }
2120 
2121     // Check if a scan record matches a specific filters.
matchesFilters(ScanClient client, ScanResult scanResult)2122     private MatchResult matchesFilters(ScanClient client, ScanResult scanResult) {
2123         return matchesFilters(client, scanResult, null);
2124     }
2125 
2126     // Check if a scan record matches a specific filters or original address
matchesFilters(ScanClient client, ScanResult scanResult, String originalAddress)2127     private MatchResult matchesFilters(ScanClient client, ScanResult scanResult,
2128             String originalAddress) {
2129         if (client.filters == null || client.filters.isEmpty()) {
2130             // TODO: Do we really wanna return true here?
2131             return new MatchResult(true, MatchOrigin.PSEUDO_ADDRESS);
2132         }
2133         for (ScanFilter filter : client.filters) {
2134             // Need to check the filter matches, and the original address without changing the API
2135             if (filter.matches(scanResult)) {
2136                 return new MatchResult(true, MatchOrigin.PSEUDO_ADDRESS);
2137             }
2138             if (originalAddress != null
2139                     && originalAddress.equalsIgnoreCase(filter.getDeviceAddress())) {
2140                 return new MatchResult(true, MatchOrigin.ORIGINAL_ADDRESS);
2141             }
2142         }
2143         return new MatchResult(false, MatchOrigin.PSEUDO_ADDRESS);
2144     }
2145 
onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb)2146     void onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb)
2147             throws RemoteException {
2148         UUID uuid = new UUID(uuidMsb, uuidLsb);
2149         if (DBG) {
2150             Log.d(TAG, "onClientRegistered() - UUID=" + uuid + ", clientIf=" + clientIf);
2151         }
2152         ClientMap.App app = mClientMap.getByUuid(uuid);
2153         if (app != null) {
2154             if (status == 0) {
2155                 app.id = clientIf;
2156                 app.linkToDeath(new ClientDeathRecipient(clientIf));
2157             } else {
2158                 mClientMap.remove(uuid);
2159             }
2160             app.callback.onClientRegistered(status, clientIf);
2161         }
2162     }
2163 
onConnected(int clientIf, int connId, int status, String address)2164     void onConnected(int clientIf, int connId, int status, String address) throws RemoteException {
2165         if (DBG) {
2166             Log.d(TAG, "onConnected() - clientIf=" + clientIf + ", connId=" + connId + ", address="
2167                     + address);
2168         }
2169         int connectionState = BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED;
2170         if (status == 0) {
2171             mClientMap.addConnection(clientIf, connId, address);
2172 
2173             // Allow one writeCharacteristic operation at a time for each connected remote device.
2174             synchronized (mPermits) {
2175                 Log.d(TAG, "onConnected() - adding permit for address="
2176                     + address);
2177                 mPermits.putIfAbsent(address, -1);
2178             }
2179             connectionState = BluetoothProtoEnums.CONNECTION_STATE_CONNECTED;
2180 
2181         }
2182         ClientMap.App app = mClientMap.getById(clientIf);
2183         if (app != null) {
2184             app.callback.onClientConnectionState(status, clientIf,
2185                     (status == BluetoothGatt.GATT_SUCCESS), address);
2186         }
2187         statsLogGattConnectionStateChange(
2188                 BluetoothProfile.GATT, address, clientIf, connectionState, status);
2189     }
2190 
onDisconnected(int clientIf, int connId, int status, String address)2191     void onDisconnected(int clientIf, int connId, int status, String address)
2192             throws RemoteException {
2193         if (DBG) {
2194             Log.d(TAG,
2195                     "onDisconnected() - clientIf=" + clientIf + ", connId=" + connId + ", address="
2196                             + address);
2197         }
2198 
2199         mClientMap.removeConnection(clientIf, connId);
2200         ClientMap.App app = mClientMap.getById(clientIf);
2201 
2202         // Remove AtomicBoolean representing permit if no other connections rely on this remote device.
2203         if (!mClientMap.getConnectedDevices().contains(address)) {
2204             synchronized (mPermits) {
2205                 Log.d(TAG, "onDisconnected() - removing permit for address="
2206                     + address);
2207                 mPermits.remove(address);
2208             }
2209         } else {
2210             synchronized (mPermits) {
2211                 if (mPermits.get(address) == connId) {
2212                     Log.d(TAG, "onDisconnected() - set permit -1 for address=" + address);
2213                     mPermits.put(address, -1);
2214                 }
2215             }
2216         }
2217 
2218         if (app != null) {
2219             app.callback.onClientConnectionState(status, clientIf, false, address);
2220         }
2221         statsLogGattConnectionStateChange(
2222                 BluetoothProfile.GATT, address, clientIf,
2223                 BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED, status);
2224     }
2225 
onClientPhyUpdate(int connId, int txPhy, int rxPhy, int status)2226     void onClientPhyUpdate(int connId, int txPhy, int rxPhy, int status) throws RemoteException {
2227         if (DBG) {
2228             Log.d(TAG, "onClientPhyUpdate() - connId=" + connId + ", status=" + status);
2229         }
2230 
2231         String address = mClientMap.addressByConnId(connId);
2232         if (address == null) {
2233             return;
2234         }
2235 
2236         ClientMap.App app = mClientMap.getByConnId(connId);
2237         if (app == null) {
2238             return;
2239         }
2240 
2241         app.callback.onPhyUpdate(address, txPhy, rxPhy, status);
2242     }
2243 
onClientPhyRead(int clientIf, String address, int txPhy, int rxPhy, int status)2244     void onClientPhyRead(int clientIf, String address, int txPhy, int rxPhy, int status)
2245             throws RemoteException {
2246         if (DBG) {
2247             Log.d(TAG,
2248                     "onClientPhyRead() - address=" + address + ", status=" + status + ", clientIf="
2249                             + clientIf);
2250         }
2251 
2252         Integer connId = mClientMap.connIdByAddress(clientIf, address);
2253         if (connId == null) {
2254             Log.d(TAG, "onClientPhyRead() - no connection to " + address);
2255             return;
2256         }
2257 
2258         ClientMap.App app = mClientMap.getByConnId(connId);
2259         if (app == null) {
2260             return;
2261         }
2262 
2263         app.callback.onPhyRead(address, txPhy, rxPhy, status);
2264     }
2265 
onClientConnUpdate(int connId, int interval, int latency, int timeout, int status)2266     void onClientConnUpdate(int connId, int interval, int latency, int timeout, int status)
2267             throws RemoteException {
2268         if (DBG) {
2269             Log.d(TAG, "onClientConnUpdate() - connId=" + connId + ", status=" + status);
2270         }
2271 
2272         String address = mClientMap.addressByConnId(connId);
2273         if (address == null) {
2274             return;
2275         }
2276 
2277         ClientMap.App app = mClientMap.getByConnId(connId);
2278         if (app == null) {
2279             return;
2280         }
2281 
2282         app.callback.onConnectionUpdated(address, interval, latency, timeout, status);
2283     }
2284 
onServiceChanged(int connId)2285     void onServiceChanged(int connId) throws RemoteException {
2286         if (DBG) {
2287             Log.d(TAG, "onServiceChanged - connId=" + connId);
2288         }
2289 
2290         String address = mClientMap.addressByConnId(connId);
2291         if (address == null) {
2292             return;
2293         }
2294 
2295         ClientMap.App app = mClientMap.getByConnId(connId);
2296         if (app == null) {
2297             return;
2298         }
2299 
2300         app.callback.onServiceChanged(address);
2301     }
2302 
onClientSubrateChange(int connId, int subrateFactor, int latency, int contNum, int timeout, int status)2303     void onClientSubrateChange(int connId, int subrateFactor, int latency, int contNum,
2304             int timeout, int status) throws RemoteException {
2305         if (DBG) {
2306             Log.d(TAG, "onClientSubrateChange() - connId=" + connId + ", status=" + status);
2307         }
2308 
2309         String address = mClientMap.addressByConnId(connId);
2310         if (address == null) {
2311             return;
2312         }
2313 
2314         ClientMap.App app = mClientMap.getByConnId(connId);
2315         if (app == null) {
2316             return;
2317         }
2318 
2319         app.callback.onSubrateChange(address, subrateFactor, latency, contNum, timeout, status);
2320     }
2321 
onServerPhyUpdate(int connId, int txPhy, int rxPhy, int status)2322     void onServerPhyUpdate(int connId, int txPhy, int rxPhy, int status) throws RemoteException {
2323         if (DBG) {
2324             Log.d(TAG, "onServerPhyUpdate() - connId=" + connId + ", status=" + status);
2325         }
2326 
2327         String address = mServerMap.addressByConnId(connId);
2328         if (address == null) {
2329             return;
2330         }
2331 
2332         ServerMap.App app = mServerMap.getByConnId(connId);
2333         if (app == null) {
2334             return;
2335         }
2336 
2337         app.callback.onPhyUpdate(address, txPhy, rxPhy, status);
2338     }
2339 
onServerPhyRead(int serverIf, String address, int txPhy, int rxPhy, int status)2340     void onServerPhyRead(int serverIf, String address, int txPhy, int rxPhy, int status)
2341             throws RemoteException {
2342         if (DBG) {
2343             Log.d(TAG, "onServerPhyRead() - address=" + address + ", status=" + status);
2344         }
2345 
2346         Integer connId = mServerMap.connIdByAddress(serverIf, address);
2347         if (connId == null) {
2348             Log.d(TAG, "onServerPhyRead() - no connection to " + address);
2349             return;
2350         }
2351 
2352         ServerMap.App app = mServerMap.getByConnId(connId);
2353         if (app == null) {
2354             return;
2355         }
2356 
2357         app.callback.onPhyRead(address, txPhy, rxPhy, status);
2358     }
2359 
onServerConnUpdate(int connId, int interval, int latency, int timeout, int status)2360     void onServerConnUpdate(int connId, int interval, int latency, int timeout, int status)
2361             throws RemoteException {
2362         if (DBG) {
2363             Log.d(TAG, "onServerConnUpdate() - connId=" + connId + ", status=" + status);
2364         }
2365 
2366         String address = mServerMap.addressByConnId(connId);
2367         if (address == null) {
2368             return;
2369         }
2370 
2371         ServerMap.App app = mServerMap.getByConnId(connId);
2372         if (app == null) {
2373             return;
2374         }
2375 
2376         app.callback.onConnectionUpdated(address, interval, latency, timeout, status);
2377     }
2378 
onServerSubrateChange(int connId, int subrateFactor, int latency, int contNum, int timeout, int status)2379     void onServerSubrateChange(int connId, int subrateFactor, int latency, int contNum,
2380             int timeout, int status)
2381             throws RemoteException {
2382         if (DBG) {
2383             Log.d(TAG, "onServerSubrateChange() - connId=" + connId + ", status=" + status);
2384         }
2385 
2386         String address = mServerMap.addressByConnId(connId);
2387         if (address == null) {
2388             return;
2389         }
2390 
2391         ServerMap.App app = mServerMap.getByConnId(connId);
2392         if (app == null) {
2393             return;
2394         }
2395 
2396         app.callback.onSubrateChange(address, subrateFactor, latency, contNum, timeout, status);
2397     }
2398 
onSearchCompleted(int connId, int status)2399     void onSearchCompleted(int connId, int status) throws RemoteException {
2400         if (DBG) {
2401             Log.d(TAG, "onSearchCompleted() - connId=" + connId + ", status=" + status);
2402         }
2403         // Gatt DB is ready!
2404 
2405         // This callback was called from the jni_workqueue thread. If we make request to the stack
2406         // on the same thread, it might cause deadlock. Schedule request on a new thread instead.
2407         Thread t = new Thread(new Runnable() {
2408             @Override
2409             public void run() {
2410                 mNativeInterface.gattClientGetGattDb(connId);
2411             }
2412         });
2413         t.start();
2414     }
2415 
getSampleGattDbElement()2416     GattDbElement getSampleGattDbElement() {
2417         return new GattDbElement();
2418     }
2419 
onGetGattDb(int connId, ArrayList<GattDbElement> db)2420     void onGetGattDb(int connId, ArrayList<GattDbElement> db) throws RemoteException {
2421         String address = mClientMap.addressByConnId(connId);
2422 
2423         if (DBG) {
2424             Log.d(TAG, "onGetGattDb() - address=" + address);
2425         }
2426 
2427         ClientMap.App app = mClientMap.getByConnId(connId);
2428         if (app == null || app.callback == null) {
2429             Log.e(TAG, "app or callback is null");
2430             return;
2431         }
2432 
2433         List<BluetoothGattService> dbOut = new ArrayList<BluetoothGattService>();
2434         Set<Integer> restrictedIds = new HashSet<>();
2435 
2436         BluetoothGattService currSrvc = null;
2437         BluetoothGattCharacteristic currChar = null;
2438         boolean isRestrictedSrvc = false;
2439         boolean isHidSrvc = false;
2440         boolean isRestrictedChar = false;
2441 
2442         for (GattDbElement el : db) {
2443             switch (el.type) {
2444                 case GattDbElement.TYPE_PRIMARY_SERVICE:
2445                 case GattDbElement.TYPE_SECONDARY_SERVICE:
2446                     if (DBG) {
2447                         Log.d(TAG, "got service with UUID=" + el.uuid + " id: " + el.id);
2448                     }
2449 
2450                     currSrvc = new BluetoothGattService(el.uuid, el.id, el.type);
2451                     dbOut.add(currSrvc);
2452                     isRestrictedSrvc = isRestrictedSrvcUuid(el.uuid);
2453                     isHidSrvc = isHidSrvcUuid(el.uuid);
2454                     if (isRestrictedSrvc) {
2455                         restrictedIds.add(el.id);
2456                     }
2457                     break;
2458 
2459                 case GattDbElement.TYPE_CHARACTERISTIC:
2460                     if (DBG) {
2461                         Log.d(TAG, "got characteristic with UUID=" + el.uuid + " id: " + el.id);
2462                     }
2463 
2464                     currChar = new BluetoothGattCharacteristic(el.uuid, el.id, el.properties, 0);
2465                     currSrvc.addCharacteristic(currChar);
2466                     isRestrictedChar = isRestrictedSrvc || (isHidSrvc && isHidCharUuid(el.uuid));
2467                     if (isRestrictedChar) {
2468                         restrictedIds.add(el.id);
2469                     }
2470                     break;
2471 
2472                 case GattDbElement.TYPE_DESCRIPTOR:
2473                     if (DBG) {
2474                         Log.d(TAG, "got descriptor with UUID=" + el.uuid + " id: " + el.id);
2475                     }
2476 
2477                     currChar.addDescriptor(new BluetoothGattDescriptor(el.uuid, el.id, 0));
2478                     if (isRestrictedChar) {
2479                         restrictedIds.add(el.id);
2480                     }
2481                     break;
2482 
2483                 case GattDbElement.TYPE_INCLUDED_SERVICE:
2484                     if (DBG) {
2485                         Log.d(TAG, "got included service with UUID=" + el.uuid + " id: " + el.id
2486                                 + " startHandle: " + el.startHandle);
2487                     }
2488 
2489                     currSrvc.addIncludedService(
2490                             new BluetoothGattService(el.uuid, el.startHandle, el.type));
2491                     break;
2492 
2493                 default:
2494                     Log.e(TAG, "got unknown element with type=" + el.type + " and UUID=" + el.uuid
2495                             + " id: " + el.id);
2496             }
2497         }
2498 
2499         if (!restrictedIds.isEmpty()) {
2500             mRestrictedHandles.put(connId, restrictedIds);
2501         }
2502         // Search is complete when there was error, or nothing more to process
2503         app.callback.onSearchComplete(address, dbOut, 0 /* status */);
2504     }
2505 
onRegisterForNotifications(int connId, int status, int registered, int handle)2506     void onRegisterForNotifications(int connId, int status, int registered, int handle) {
2507         String address = mClientMap.addressByConnId(connId);
2508 
2509         if (DBG) {
2510             Log.d(TAG, "onRegisterForNotifications() - address=" + address + ", status=" + status
2511                     + ", registered=" + registered + ", handle=" + handle);
2512         }
2513     }
2514 
onNotify(int connId, String address, int handle, boolean isNotify, byte[] data)2515     void onNotify(int connId, String address, int handle, boolean isNotify, byte[] data)
2516             throws RemoteException {
2517 
2518         if (VDBG) {
2519             Log.d(TAG, "onNotify() - address=" + address + ", handle=" + handle + ", length="
2520                     + data.length);
2521         }
2522 
2523         ClientMap.App app = mClientMap.getByConnId(connId);
2524         if (app != null) {
2525             try {
2526                 permissionCheck(connId, handle);
2527             } catch (SecurityException ex) {
2528                 // Only throws on apps with target SDK T+ as this old API did not throw prior to T
2529                 if (checkCallerTargetSdk(this, app.name, Build.VERSION_CODES.TIRAMISU)) {
2530                     throw ex;
2531                 }
2532                 Log.w(TAG, "onNotify() - permission check failed!");
2533                 return;
2534             }
2535             app.callback.onNotify(address, handle, data);
2536         }
2537     }
2538 
onReadCharacteristic(int connId, int status, int handle, byte[] data)2539     void onReadCharacteristic(int connId, int status, int handle, byte[] data)
2540             throws RemoteException {
2541         String address = mClientMap.addressByConnId(connId);
2542 
2543         if (VDBG) {
2544             Log.d(TAG, "onReadCharacteristic() - address=" + address + ", status=" + status
2545                     + ", length=" + data.length);
2546         }
2547 
2548         ClientMap.App app = mClientMap.getByConnId(connId);
2549         if (app != null) {
2550             app.callback.onCharacteristicRead(address, status, handle, data);
2551         }
2552     }
2553 
onWriteCharacteristic(int connId, int status, int handle, byte[] data)2554     void onWriteCharacteristic(int connId, int status, int handle, byte[] data)
2555             throws RemoteException {
2556         String address = mClientMap.addressByConnId(connId);
2557         synchronized (mPermits) {
2558             Log.d(TAG, "onWriteCharacteristic() - increasing permit for address="
2559                     + address);
2560             mPermits.put(address, -1);
2561         }
2562 
2563         if (VDBG) {
2564             Log.d(TAG, "onWriteCharacteristic() - address=" + address + ", status=" + status
2565                     + ", length=" + data.length);
2566         }
2567 
2568         ClientMap.App app = mClientMap.getByConnId(connId);
2569         if (app == null) {
2570             return;
2571         }
2572 
2573         if (!app.isCongested) {
2574             app.callback.onCharacteristicWrite(address, status, handle, data);
2575         } else {
2576             if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) {
2577                 status = BluetoothGatt.GATT_SUCCESS;
2578             }
2579             CallbackInfo callbackInfo = new CallbackInfo.Builder(address, status)
2580                     .setHandle(handle)
2581                     .setValue(data)
2582                     .build();
2583             app.queueCallback(callbackInfo);
2584         }
2585     }
2586 
onExecuteCompleted(int connId, int status)2587     void onExecuteCompleted(int connId, int status) throws RemoteException {
2588         String address = mClientMap.addressByConnId(connId);
2589         if (VDBG) {
2590             Log.d(TAG, "onExecuteCompleted() - address=" + address + ", status=" + status);
2591         }
2592 
2593         ClientMap.App app = mClientMap.getByConnId(connId);
2594         if (app != null) {
2595             app.callback.onExecuteWrite(address, status);
2596         }
2597     }
2598 
onReadDescriptor(int connId, int status, int handle, byte[] data)2599     void onReadDescriptor(int connId, int status, int handle, byte[] data) throws RemoteException {
2600         String address = mClientMap.addressByConnId(connId);
2601 
2602         if (VDBG) {
2603             Log.d(TAG,
2604                     "onReadDescriptor() - address=" + address + ", status=" + status + ", length="
2605                             + data.length);
2606         }
2607 
2608         ClientMap.App app = mClientMap.getByConnId(connId);
2609         if (app != null) {
2610             app.callback.onDescriptorRead(address, status, handle, data);
2611         }
2612     }
2613 
onWriteDescriptor(int connId, int status, int handle, byte[] data)2614     void onWriteDescriptor(int connId, int status, int handle, byte[] data)
2615             throws RemoteException {
2616         String address = mClientMap.addressByConnId(connId);
2617 
2618         if (VDBG) {
2619             Log.d(TAG, "onWriteDescriptor() - address=" + address + ", status=" + status
2620                     + ", length=" + data.length);
2621         }
2622 
2623         ClientMap.App app = mClientMap.getByConnId(connId);
2624         if (app != null) {
2625             app.callback.onDescriptorWrite(address, status, handle, data);
2626         }
2627     }
2628 
onReadRemoteRssi(int clientIf, String address, int rssi, int status)2629     void onReadRemoteRssi(int clientIf, String address, int rssi, int status)
2630             throws RemoteException {
2631         if (DBG) {
2632             Log.d(TAG,
2633                     "onReadRemoteRssi() - clientIf=" + clientIf + " address=" + address + ", rssi="
2634                             + rssi + ", status=" + status);
2635         }
2636 
2637         ClientMap.App app = mClientMap.getById(clientIf);
2638         if (app != null) {
2639             app.callback.onReadRemoteRssi(address, rssi, status);
2640         }
2641     }
2642 
onScanFilterEnableDisabled(int action, int status, int clientIf)2643     void onScanFilterEnableDisabled(int action, int status, int clientIf) {
2644         if (DBG) {
2645             Log.d(TAG, "onScanFilterEnableDisabled() - clientIf=" + clientIf + ", status=" + status
2646                     + ", action=" + action);
2647         }
2648         mScanManager.callbackDone(clientIf, status);
2649     }
2650 
onScanFilterParamsConfigured(int action, int status, int clientIf, int availableSpace)2651     void onScanFilterParamsConfigured(int action, int status, int clientIf, int availableSpace) {
2652         if (DBG) {
2653             Log.d(TAG,
2654                     "onScanFilterParamsConfigured() - clientIf=" + clientIf + ", status=" + status
2655                             + ", action=" + action + ", availableSpace=" + availableSpace);
2656         }
2657         mScanManager.callbackDone(clientIf, status);
2658     }
2659 
onScanFilterConfig(int action, int status, int clientIf, int filterType, int availableSpace)2660     void onScanFilterConfig(int action, int status, int clientIf, int filterType,
2661             int availableSpace) {
2662         if (DBG) {
2663             Log.d(TAG, "onScanFilterConfig() - clientIf=" + clientIf + ", action = " + action
2664                     + " status = " + status + ", filterType=" + filterType + ", availableSpace="
2665                     + availableSpace);
2666         }
2667 
2668         mScanManager.callbackDone(clientIf, status);
2669     }
2670 
onBatchScanStorageConfigured(int status, int clientIf)2671     void onBatchScanStorageConfigured(int status, int clientIf) {
2672         if (DBG) {
2673             Log.d(TAG,
2674                     "onBatchScanStorageConfigured() - clientIf=" + clientIf + ", status=" + status);
2675         }
2676         mScanManager.callbackDone(clientIf, status);
2677     }
2678 
2679     // TODO: split into two different callbacks : onBatchScanStarted and onBatchScanStopped.
onBatchScanStartStopped(int startStopAction, int status, int clientIf)2680     void onBatchScanStartStopped(int startStopAction, int status, int clientIf) {
2681         if (DBG) {
2682             Log.d(TAG, "onBatchScanStartStopped() - clientIf=" + clientIf + ", status=" + status
2683                     + ", startStopAction=" + startStopAction);
2684         }
2685         mScanManager.callbackDone(clientIf, status);
2686     }
2687 
findBatchScanClientById(int scannerId)2688     ScanClient findBatchScanClientById(int scannerId) {
2689         for (ScanClient client : mScanManager.getBatchScanQueue()) {
2690             if (client.scannerId == scannerId) {
2691                 return client;
2692             }
2693         }
2694         return null;
2695     }
2696 
onBatchScanReports(int status, int scannerId, int reportType, int numRecords, byte[] recordData)2697     void onBatchScanReports(int status, int scannerId, int reportType, int numRecords,
2698             byte[] recordData) throws RemoteException {
2699         // When in testing mode, ignore all real-world events
2700         if (isTestModeEnabled()) return;
2701 
2702         onBatchScanReportsInternal(status, scannerId, reportType, numRecords, recordData);
2703     }
2704 
onBatchScanReportsInternal(int status, int scannerId, int reportType, int numRecords, byte[] recordData)2705     void onBatchScanReportsInternal(int status, int scannerId, int reportType, int numRecords,
2706             byte[] recordData) throws RemoteException {
2707         if (DBG) {
2708             Log.d(TAG, "onBatchScanReports() - scannerId=" + scannerId + ", status=" + status
2709                     + ", reportType=" + reportType + ", numRecords=" + numRecords);
2710         }
2711 
2712         Set<ScanResult> results = parseBatchScanResults(numRecords, reportType, recordData);
2713         if (reportType == ScanManager.SCAN_RESULT_TYPE_TRUNCATED) {
2714             // We only support single client for truncated mode.
2715             ScannerMap.App app = mScannerMap.getById(scannerId);
2716             if (app == null) {
2717                 return;
2718             }
2719 
2720             ScanClient client = findBatchScanClientById(scannerId);
2721             if (client == null) {
2722                 return;
2723             }
2724 
2725             ArrayList<ScanResult> permittedResults;
2726             if (hasScanResultPermission(client)) {
2727                 permittedResults = new ArrayList<ScanResult>(results);
2728             } else {
2729                 permittedResults = new ArrayList<ScanResult>();
2730                 for (ScanResult scanResult : results) {
2731                     for (String associatedDevice : client.associatedDevices) {
2732                         if (associatedDevice.equalsIgnoreCase(scanResult.getDevice()
2733                                     .getAddress())) {
2734                             permittedResults.add(scanResult);
2735                         }
2736                     }
2737                 }
2738                 if (permittedResults.isEmpty()) {
2739                     return;
2740                 }
2741             }
2742 
2743             if (client.hasDisavowedLocation) {
2744                 permittedResults.removeIf(mLocationDenylistPredicate);
2745             }
2746 
2747             if (app.callback != null) {
2748                 app.callback.onBatchScanResults(permittedResults);
2749             } else {
2750                 // PendingIntent based
2751                 try {
2752                     sendResultsByPendingIntent(app.info, permittedResults,
2753                             ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
2754                 } catch (PendingIntent.CanceledException e) {
2755                 }
2756             }
2757         } else {
2758             for (ScanClient client : mScanManager.getFullBatchScanQueue()) {
2759                 // Deliver results for each client.
2760                 deliverBatchScan(client, results);
2761             }
2762         }
2763         mScanManager.callbackDone(scannerId, status);
2764     }
2765 
sendBatchScanResults(ScannerMap.App app, ScanClient client, ArrayList<ScanResult> results)2766     private void sendBatchScanResults(ScannerMap.App app, ScanClient client,
2767             ArrayList<ScanResult> results) {
2768         try {
2769             if (app.callback != null) {
2770                 if (mScanManager.isAutoBatchScanClientEnabled(client)) {
2771                     if (DBG) {
2772                         Log.d(TAG, "sendBatchScanResults() to onScanResult()" + client);
2773                     }
2774                     for (ScanResult result : results) {
2775                         app.appScanStats.addResult(client.scannerId);
2776                         app.callback.onScanResult(result);
2777                     }
2778                 } else {
2779                     if (DBG) {
2780                         Log.d(TAG, "sendBatchScanResults() to onBatchScanResults()" + client);
2781                     }
2782                     app.callback.onBatchScanResults(results);
2783                 }
2784             } else {
2785                 sendResultsByPendingIntent(app.info, results,
2786                         ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
2787             }
2788         } catch (RemoteException | PendingIntent.CanceledException e) {
2789             Log.e(TAG, "Exception: " + e);
2790             mScannerMap.remove(client.scannerId);
2791             mScanManager.stopScan(client.scannerId);
2792         }
2793     }
2794 
2795     // Check and deliver scan results for different scan clients.
deliverBatchScan(ScanClient client, Set<ScanResult> allResults)2796     private void deliverBatchScan(ScanClient client, Set<ScanResult> allResults)
2797             throws RemoteException {
2798         ScannerMap.App app = mScannerMap.getById(client.scannerId);
2799         if (app == null) {
2800             return;
2801         }
2802 
2803         ArrayList<ScanResult> permittedResults;
2804         if (hasScanResultPermission(client)) {
2805             permittedResults = new ArrayList<ScanResult>(allResults);
2806         } else {
2807             permittedResults = new ArrayList<ScanResult>();
2808             for (ScanResult scanResult : allResults) {
2809                 for (String associatedDevice : client.associatedDevices) {
2810                     if (associatedDevice.equalsIgnoreCase(scanResult.getDevice().getAddress())) {
2811                         permittedResults.add(scanResult);
2812                     }
2813                 }
2814             }
2815             if (permittedResults.isEmpty()) {
2816                 return;
2817             }
2818         }
2819 
2820         if (client.filters == null || client.filters.isEmpty()) {
2821             sendBatchScanResults(app, client, permittedResults);
2822             // TODO: Question to reviewer: Shouldn't there be a return here?
2823         }
2824         // Reconstruct the scan results.
2825         ArrayList<ScanResult> results = new ArrayList<ScanResult>();
2826         for (ScanResult scanResult : permittedResults) {
2827             if (matchesFilters(client, scanResult).getMatches()) {
2828                 results.add(scanResult);
2829             }
2830         }
2831         sendBatchScanResults(app, client, results);
2832     }
2833 
parseBatchScanResults(int numRecords, int reportType, byte[] batchRecord)2834     private Set<ScanResult> parseBatchScanResults(int numRecords, int reportType,
2835             byte[] batchRecord) {
2836         if (numRecords == 0) {
2837             return Collections.emptySet();
2838         }
2839         if (DBG) {
2840             Log.d(TAG, "current time is " + SystemClock.elapsedRealtimeNanos());
2841         }
2842         if (reportType == ScanManager.SCAN_RESULT_TYPE_TRUNCATED) {
2843             return parseTruncatedResults(numRecords, batchRecord);
2844         } else {
2845             return parseFullResults(numRecords, batchRecord);
2846         }
2847     }
2848 
parseTruncatedResults(int numRecords, byte[] batchRecord)2849     private Set<ScanResult> parseTruncatedResults(int numRecords, byte[] batchRecord) {
2850         if (DBG) {
2851             Log.d(TAG, "batch record " + Arrays.toString(batchRecord));
2852         }
2853         Set<ScanResult> results = new HashSet<ScanResult>(numRecords);
2854         long now = SystemClock.elapsedRealtimeNanos();
2855         for (int i = 0; i < numRecords; ++i) {
2856             byte[] record =
2857                     extractBytes(batchRecord, i * TRUNCATED_RESULT_SIZE, TRUNCATED_RESULT_SIZE);
2858             byte[] address = extractBytes(record, 0, 6);
2859             reverse(address);
2860             BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
2861             int rssi = record[8];
2862             long timestampNanos = now - parseTimestampNanos(extractBytes(record, 9, 2));
2863             results.add(new ScanResult(device, ScanRecord.parseFromBytes(new byte[0]), rssi,
2864                     timestampNanos));
2865         }
2866         return results;
2867     }
2868 
2869     @VisibleForTesting
parseTimestampNanos(byte[] data)2870     long parseTimestampNanos(byte[] data) {
2871         long timestampUnit = NumberUtils.littleEndianByteArrayToInt(data);
2872         // Timestamp is in every 50 ms.
2873         return TimeUnit.MILLISECONDS.toNanos(timestampUnit * 50);
2874     }
2875 
parseFullResults(int numRecords, byte[] batchRecord)2876     private Set<ScanResult> parseFullResults(int numRecords, byte[] batchRecord) {
2877         if (DBG) {
2878             Log.d(TAG, "Batch record : " + Arrays.toString(batchRecord));
2879         }
2880         Set<ScanResult> results = new HashSet<ScanResult>(numRecords);
2881         int position = 0;
2882         long now = SystemClock.elapsedRealtimeNanos();
2883         while (position < batchRecord.length) {
2884             byte[] address = extractBytes(batchRecord, position, 6);
2885             // TODO: remove temp hack.
2886             reverse(address);
2887             BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
2888             position += 6;
2889             // Skip address type.
2890             position++;
2891             // Skip tx power level.
2892             position++;
2893             int rssi = batchRecord[position++];
2894             long timestampNanos = now - parseTimestampNanos(extractBytes(batchRecord, position, 2));
2895             position += 2;
2896 
2897             // Combine advertise packet and scan response packet.
2898             int advertisePacketLen = batchRecord[position++];
2899             byte[] advertiseBytes = extractBytes(batchRecord, position, advertisePacketLen);
2900             position += advertisePacketLen;
2901             int scanResponsePacketLen = batchRecord[position++];
2902             byte[] scanResponseBytes = extractBytes(batchRecord, position, scanResponsePacketLen);
2903             position += scanResponsePacketLen;
2904             byte[] scanRecord = new byte[advertisePacketLen + scanResponsePacketLen];
2905             System.arraycopy(advertiseBytes, 0, scanRecord, 0, advertisePacketLen);
2906             System.arraycopy(scanResponseBytes, 0, scanRecord, advertisePacketLen,
2907                     scanResponsePacketLen);
2908             if (DBG) {
2909                 Log.d(TAG, "ScanRecord : " + Arrays.toString(scanRecord));
2910             }
2911             results.add(new ScanResult(device, ScanRecord.parseFromBytes(scanRecord), rssi,
2912                     timestampNanos));
2913         }
2914         return results;
2915     }
2916 
2917     // Reverse byte array.
reverse(byte[] address)2918     private void reverse(byte[] address) {
2919         int len = address.length;
2920         for (int i = 0; i < len / 2; ++i) {
2921             byte b = address[i];
2922             address[i] = address[len - 1 - i];
2923             address[len - 1 - i] = b;
2924         }
2925     }
2926 
2927     // Helper method to extract bytes from byte array.
extractBytes(byte[] scanRecord, int start, int length)2928     private static byte[] extractBytes(byte[] scanRecord, int start, int length) {
2929         byte[] bytes = new byte[length];
2930         System.arraycopy(scanRecord, start, bytes, 0, length);
2931         return bytes;
2932     }
2933 
2934     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
onBatchScanThresholdCrossed(int clientIf)2935     void onBatchScanThresholdCrossed(int clientIf) {
2936         if (DBG) {
2937             Log.d(TAG, "onBatchScanThresholdCrossed() - clientIf=" + clientIf);
2938         }
2939         flushPendingBatchResults(clientIf, getAttributionSource());
2940     }
2941 
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)2942     AdvtFilterOnFoundOnLostInfo createOnTrackAdvFoundLostObject(int clientIf, int advPktLen,
2943             byte[] advPkt, int scanRspLen, byte[] scanRsp, int filtIndex, int advState,
2944             int advInfoPresent, String address, int addrType, int txPower, int rssiValue,
2945             int timeStamp) {
2946 
2947         return new AdvtFilterOnFoundOnLostInfo(clientIf, advPktLen, advPkt, scanRspLen, scanRsp,
2948                 filtIndex, advState, advInfoPresent, address, addrType, txPower, rssiValue,
2949                 timeStamp);
2950     }
2951 
onTrackAdvFoundLost(AdvtFilterOnFoundOnLostInfo trackingInfo)2952     void onTrackAdvFoundLost(AdvtFilterOnFoundOnLostInfo trackingInfo) throws RemoteException {
2953         if (DBG) {
2954             Log.d(TAG, "onTrackAdvFoundLost() - scannerId= " + trackingInfo.getClientIf()
2955                     + " address = " + trackingInfo.getAddress() + " adv_state = "
2956                     + trackingInfo.getAdvState());
2957         }
2958 
2959         ScannerMap.App app = mScannerMap.getById(trackingInfo.getClientIf());
2960         if (app == null || (app.callback == null && app.info == null)) {
2961             Log.e(TAG, "app or callback is null");
2962             return;
2963         }
2964 
2965         BluetoothDevice device = BluetoothAdapter.getDefaultAdapter()
2966                 .getRemoteDevice(trackingInfo.getAddress());
2967         int advertiserState = trackingInfo.getAdvState();
2968         ScanResult result =
2969                 new ScanResult(device, ScanRecord.parseFromBytes(trackingInfo.getResult()),
2970                         trackingInfo.getRSSIValue(), SystemClock.elapsedRealtimeNanos());
2971 
2972         for (ScanClient client : mScanManager.getRegularScanQueue()) {
2973             if (client.scannerId == trackingInfo.getClientIf()) {
2974                 ScanSettings settings = client.settings;
2975                 if ((advertiserState == ADVT_STATE_ONFOUND) && (
2976                         (settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH)
2977                                 != 0)) {
2978                     if (app.callback != null) {
2979                         app.callback.onFoundOrLost(true, result);
2980                     } else {
2981                         sendResultByPendingIntent(app.info, result,
2982                                 ScanSettings.CALLBACK_TYPE_FIRST_MATCH, client);
2983                     }
2984                 } else if ((advertiserState == ADVT_STATE_ONLOST) && (
2985                         (settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_MATCH_LOST)
2986                                 != 0)) {
2987                     if (app.callback != null) {
2988                         app.callback.onFoundOrLost(false, result);
2989                     } else {
2990                         sendResultByPendingIntent(app.info, result,
2991                                 ScanSettings.CALLBACK_TYPE_MATCH_LOST, client);
2992                     }
2993                 } else {
2994                     if (DBG) {
2995                         Log.d(TAG, "Not reporting onlost/onfound : " + advertiserState
2996                                 + " scannerId = " + client.scannerId + " callbackType "
2997                                 + settings.getCallbackType());
2998                     }
2999                 }
3000             }
3001         }
3002     }
3003 
onScanParamSetupCompleted(int status, int scannerId)3004     void onScanParamSetupCompleted(int status, int scannerId) throws RemoteException {
3005         ScannerMap.App app = mScannerMap.getById(scannerId);
3006         if (app == null || app.callback == null) {
3007             Log.e(TAG, "Advertise app or callback is null");
3008             return;
3009         }
3010         if (DBG) {
3011             Log.d(TAG, "onScanParamSetupCompleted : " + status);
3012         }
3013     }
3014 
3015     // callback from ScanManager for dispatch of errors apps.
onScanManagerErrorCallback(int scannerId, int errorCode)3016     void onScanManagerErrorCallback(int scannerId, int errorCode) throws RemoteException {
3017         ScannerMap.App app = mScannerMap.getById(scannerId);
3018         if (app == null || (app.callback == null && app.info == null)) {
3019             Log.e(TAG, "App or callback is null");
3020             return;
3021         }
3022         if (app.callback != null) {
3023             app.callback.onScanManagerErrorCallback(errorCode);
3024         } else {
3025             try {
3026                 sendErrorByPendingIntent(app.info, errorCode);
3027             } catch (PendingIntent.CanceledException e) {
3028                 Log.e(TAG, "Error sending error code via PendingIntent:" + e);
3029             }
3030         }
3031     }
3032 
onConfigureMTU(int connId, int status, int mtu)3033     void onConfigureMTU(int connId, int status, int mtu) throws RemoteException {
3034         String address = mClientMap.addressByConnId(connId);
3035 
3036         if (DBG) {
3037             Log.d(TAG,
3038                     "onConfigureMTU() address=" + address + ", status=" + status + ", mtu=" + mtu);
3039         }
3040 
3041         ClientMap.App app = mClientMap.getByConnId(connId);
3042         if (app != null) {
3043             app.callback.onConfigureMTU(address, mtu, status);
3044         }
3045     }
3046 
onClientCongestion(int connId, boolean congested)3047     void onClientCongestion(int connId, boolean congested) throws RemoteException {
3048         if (VDBG) {
3049             Log.d(TAG, "onClientCongestion() - connId=" + connId + ", congested=" + congested);
3050         }
3051 
3052         ClientMap.App app = mClientMap.getByConnId(connId);
3053 
3054         if (app != null) {
3055             app.isCongested = congested;
3056             while (!app.isCongested) {
3057                 CallbackInfo callbackInfo = app.popQueuedCallback();
3058                 if (callbackInfo == null) {
3059                     return;
3060                 }
3061                 app.callback.onCharacteristicWrite(callbackInfo.address, callbackInfo.status,
3062                         callbackInfo.handle, callbackInfo.value);
3063             }
3064         }
3065     }
3066 
3067     /**************************************************************************
3068      * GATT Service functions - Shared CLIENT/SERVER
3069      *************************************************************************/
3070 
3071     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getDevicesMatchingConnectionStates( int[] states, AttributionSource attributionSource)3072     List<BluetoothDevice> getDevicesMatchingConnectionStates(
3073             int[] states, AttributionSource attributionSource) {
3074         if (!Utils.checkConnectPermissionForDataDelivery(
3075                 this, attributionSource,
3076                 "GattService getDevicesMatchingConnectionStates")) {
3077             return new ArrayList<>(0);
3078         }
3079 
3080         Map<BluetoothDevice, Integer> deviceStates = new HashMap<BluetoothDevice, Integer>();
3081 
3082         // Add paired LE devices
3083 
3084         BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
3085         for (BluetoothDevice device : bondedDevices) {
3086             if (getDeviceType(device) != AbstractionLayer.BT_DEVICE_TYPE_BREDR) {
3087                 deviceStates.put(device, BluetoothProfile.STATE_DISCONNECTED);
3088             }
3089         }
3090 
3091         // Add connected deviceStates
3092 
3093         Set<String> connectedDevices = new HashSet<String>();
3094         connectedDevices.addAll(mClientMap.getConnectedDevices());
3095         connectedDevices.addAll(mServerMap.getConnectedDevices());
3096 
3097         for (String address : connectedDevices) {
3098             BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
3099             if (device != null) {
3100                 deviceStates.put(device, BluetoothProfile.STATE_CONNECTED);
3101             }
3102         }
3103 
3104         // Create matching device sub-set
3105 
3106         List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>();
3107 
3108         for (Map.Entry<BluetoothDevice, Integer> entry : deviceStates.entrySet()) {
3109             for (int state : states) {
3110                 if (entry.getValue() == state) {
3111                     deviceList.add(entry.getKey());
3112                 }
3113             }
3114         }
3115 
3116         return deviceList;
3117     }
3118 
3119     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
registerScanner(IScannerCallback callback, WorkSource workSource, AttributionSource attributionSource)3120     void registerScanner(IScannerCallback callback, WorkSource workSource,
3121             AttributionSource attributionSource) throws RemoteException {
3122         if (!Utils.checkScanPermissionForDataDelivery(
3123                 this, attributionSource, "GattService registerScanner")) {
3124             return;
3125         }
3126 
3127         UUID uuid = UUID.randomUUID();
3128         if (DBG) {
3129             Log.d(TAG, "registerScanner() - UUID=" + uuid);
3130         }
3131 
3132         enforceImpersonatationPermissionIfNeeded(workSource);
3133 
3134         AppScanStats app = mScannerMap.getAppScanStatsByUid(Binder.getCallingUid());
3135         if (app != null && app.isScanningTooFrequently()
3136                 && !Utils.checkCallerHasPrivilegedPermission(this)) {
3137             Log.e(TAG, "App '" + app.appName + "' is scanning too frequently");
3138             callback.onScannerRegistered(ScanCallback.SCAN_FAILED_SCANNING_TOO_FREQUENTLY, -1);
3139             return;
3140         }
3141 
3142         mScannerMap.add(uuid, workSource, callback, null, this);
3143         mScanManager.registerScanner(uuid);
3144     }
3145 
3146     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
unregisterScanner(int scannerId, AttributionSource attributionSource)3147     void unregisterScanner(int scannerId, AttributionSource attributionSource) {
3148         if (!Utils.checkScanPermissionForDataDelivery(
3149                 this, attributionSource, "GattService unregisterScanner")) {
3150             return;
3151         }
3152 
3153         if (DBG) {
3154             Log.d(TAG, "unregisterScanner() - scannerId=" + scannerId);
3155         }
3156         mScannerMap.remove(scannerId);
3157         mScanManager.unregisterScanner(scannerId);
3158     }
3159 
getAssociatedDevices(String callingPackage)3160     private List<String> getAssociatedDevices(String callingPackage) {
3161         if (mCompanionManager == null) {
3162             return Collections.emptyList();
3163         }
3164 
3165         List<String> macAddresses = new ArrayList();
3166 
3167         final long identity = Binder.clearCallingIdentity();
3168         try {
3169             for (AssociationInfo info : Utils.getCdmAssociations(mCompanionManager)) {
3170                 if (info.getPackageName().equals(callingPackage) && !info.isSelfManaged()
3171                     && info.getDeviceMacAddress() != null) {
3172                     macAddresses.add(info.getDeviceMacAddress().toString());
3173                 }
3174             }
3175         } catch (SecurityException se) {
3176             // Not an app with associated devices
3177         } catch (Exception e) {
3178             Log.e(TAG, "Cannot check device associations for " + callingPackage, e);
3179         } finally {
3180             Binder.restoreCallingIdentity(identity);
3181         }
3182         return macAddresses;
3183     }
3184 
3185     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
startScan(int scannerId, ScanSettings settings, List<ScanFilter> filters, AttributionSource attributionSource)3186     void startScan(int scannerId, ScanSettings settings, List<ScanFilter> filters,
3187             AttributionSource attributionSource) {
3188         if (DBG) {
3189             Log.d(TAG, "start scan with filters");
3190         }
3191 
3192         if (!Utils.checkScanPermissionForDataDelivery(
3193                 this, attributionSource, "Starting GATT scan.")) {
3194             return;
3195         }
3196 
3197         enforcePrivilegedPermissionIfNeeded(settings);
3198         String callingPackage = attributionSource.getPackageName();
3199         settings = enforceReportDelayFloor(settings);
3200         enforcePrivilegedPermissionIfNeeded(filters);
3201         final ScanClient scanClient = new ScanClient(scannerId, settings, filters);
3202         scanClient.userHandle = Binder.getCallingUserHandle();
3203         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
3204         scanClient.eligibleForSanitizedExposureNotification =
3205                 callingPackage.equals(mExposureNotificationPackage);
3206 
3207         scanClient.hasDisavowedLocation =
3208                 Utils.hasDisavowedLocationForScan(this, attributionSource, isTestModeEnabled());
3209 
3210         scanClient.isQApp = checkCallerTargetSdk(this, callingPackage, Build.VERSION_CODES.Q);
3211         if (!scanClient.hasDisavowedLocation) {
3212             if (scanClient.isQApp) {
3213                 scanClient.hasLocationPermission = Utils.checkCallerHasFineLocation(
3214                         this, attributionSource, scanClient.userHandle);
3215             } else {
3216                 scanClient.hasLocationPermission = Utils.checkCallerHasCoarseOrFineLocation(
3217                         this, attributionSource, scanClient.userHandle);
3218             }
3219         }
3220         scanClient.hasNetworkSettingsPermission =
3221                 Utils.checkCallerHasNetworkSettingsPermission(this);
3222         scanClient.hasNetworkSetupWizardPermission =
3223                 Utils.checkCallerHasNetworkSetupWizardPermission(this);
3224         scanClient.hasScanWithoutLocationPermission =
3225                 Utils.checkCallerHasScanWithoutLocationPermission(this);
3226         scanClient.associatedDevices = getAssociatedDevices(callingPackage);
3227 
3228         AppScanStats app = mScannerMap.getAppScanStatsById(scannerId);
3229         ScannerMap.App cbApp = mScannerMap.getById(scannerId);
3230         if (app != null) {
3231             scanClient.stats = app;
3232             boolean isFilteredScan = (filters != null) && !filters.isEmpty();
3233             boolean isCallbackScan = false;
3234             if (cbApp != null) {
3235                 isCallbackScan = cbApp.callback != null;
3236             }
3237             app.recordScanStart(settings, filters, isFilteredScan, isCallbackScan, scannerId);
3238         }
3239 
3240         mScanManager.startScan(scanClient);
3241         mAdapterService.notifyActivityAttributionInfo(getAttributionSource(),
3242                 AdapterService.ACTIVITY_ATTRIBUTION_NO_ACTIVE_DEVICE_ADDRESS);
3243     }
3244 
3245     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
registerPiAndStartScan(PendingIntent pendingIntent, ScanSettings settings, List<ScanFilter> filters, AttributionSource attributionSource)3246     void registerPiAndStartScan(PendingIntent pendingIntent, ScanSettings settings,
3247             List<ScanFilter> filters, AttributionSource attributionSource) {
3248         if (DBG) {
3249             Log.d(TAG, "start scan with filters, for PendingIntent");
3250         }
3251 
3252         if (!Utils.checkScanPermissionForDataDelivery(
3253                 this, attributionSource, "Starting GATT scan.")) {
3254             return;
3255         }
3256         enforcePrivilegedPermissionIfNeeded(settings);
3257         settings = enforceReportDelayFloor(settings);
3258         enforcePrivilegedPermissionIfNeeded(filters);
3259         UUID uuid = UUID.randomUUID();
3260         if (DBG) {
3261             Log.d(TAG, "startScan(PI) - UUID=" + uuid);
3262         }
3263         String callingPackage = attributionSource.getPackageName();
3264         PendingIntentInfo piInfo = new PendingIntentInfo();
3265         piInfo.intent = pendingIntent;
3266         piInfo.settings = settings;
3267         piInfo.filters = filters;
3268         piInfo.callingPackage = callingPackage;
3269 
3270         // Don't start scan if the Pi scan already in mScannerMap.
3271         if (mScannerMap.getByContextInfo(piInfo) != null) {
3272             Log.d(TAG, "Don't startScan(PI) since the same Pi scan already in mScannerMap.");
3273             return;
3274         }
3275 
3276         ScannerMap.App app = mScannerMap.add(uuid, null, null, piInfo, this);
3277 
3278         app.mUserHandle = UserHandle.getUserHandleForUid(Binder.getCallingUid());
3279         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
3280         app.mEligibleForSanitizedExposureNotification =
3281                 callingPackage.equals(mExposureNotificationPackage);
3282 
3283         app.mHasDisavowedLocation =
3284                 Utils.hasDisavowedLocationForScan(this, attributionSource, isTestModeEnabled());
3285 
3286         if (!app.mHasDisavowedLocation) {
3287             try {
3288                 if (checkCallerTargetSdk(this, callingPackage, Build.VERSION_CODES.Q)) {
3289                     app.hasLocationPermission = Utils.checkCallerHasFineLocation(
3290                             this, attributionSource, app.mUserHandle);
3291                 } else {
3292                     app.hasLocationPermission = Utils.checkCallerHasCoarseOrFineLocation(
3293                             this, attributionSource, app.mUserHandle);
3294                 }
3295             } catch (SecurityException se) {
3296                 // No need to throw here. Just mark as not granted.
3297                 app.hasLocationPermission = false;
3298             }
3299         }
3300         app.mHasNetworkSettingsPermission =
3301                 Utils.checkCallerHasNetworkSettingsPermission(this);
3302         app.mHasNetworkSetupWizardPermission =
3303                 Utils.checkCallerHasNetworkSetupWizardPermission(this);
3304         app.mHasScanWithoutLocationPermission =
3305                 Utils.checkCallerHasScanWithoutLocationPermission(this);
3306         app.mAssociatedDevices = getAssociatedDevices(callingPackage);
3307         mScanManager.registerScanner(uuid);
3308 
3309         // If this fails, we should stop the scan immediately.
3310         if (!pendingIntent.addCancelListener(Runnable::run, mScanIntentCancelListener)) {
3311             Log.d(TAG, "scanning PendingIntent is already cancelled, stopping scan.");
3312             stopScan(pendingIntent, attributionSource);
3313         }
3314     }
3315 
continuePiStartScan(int scannerId, ScannerMap.App app)3316     void continuePiStartScan(int scannerId, ScannerMap.App app) {
3317         final PendingIntentInfo piInfo = app.info;
3318         final ScanClient scanClient =
3319                 new ScanClient(scannerId, piInfo.settings, piInfo.filters);
3320         scanClient.hasLocationPermission = app.hasLocationPermission;
3321         scanClient.userHandle = app.mUserHandle;
3322         scanClient.isQApp = checkCallerTargetSdk(this, app.name, Build.VERSION_CODES.Q);
3323         scanClient.eligibleForSanitizedExposureNotification =
3324                 app.mEligibleForSanitizedExposureNotification;
3325         scanClient.hasNetworkSettingsPermission = app.mHasNetworkSettingsPermission;
3326         scanClient.hasNetworkSetupWizardPermission = app.mHasNetworkSetupWizardPermission;
3327         scanClient.hasScanWithoutLocationPermission = app.mHasScanWithoutLocationPermission;
3328         scanClient.associatedDevices = app.mAssociatedDevices;
3329         scanClient.hasDisavowedLocation = app.mHasDisavowedLocation;
3330 
3331         AppScanStats scanStats = mScannerMap.getAppScanStatsById(scannerId);
3332         if (scanStats != null) {
3333             scanClient.stats = scanStats;
3334             boolean isFilteredScan = (piInfo.filters != null) && !piInfo.filters.isEmpty();
3335             scanStats.recordScanStart(
3336                     piInfo.settings, piInfo.filters, isFilteredScan, false, scannerId);
3337         }
3338 
3339         mScanManager.startScan(scanClient);
3340     }
3341 
3342     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
flushPendingBatchResults(int scannerId, AttributionSource attributionSource)3343     void flushPendingBatchResults(int scannerId, AttributionSource attributionSource) {
3344         if (!Utils.checkScanPermissionForDataDelivery(
3345                 this, attributionSource, "GattService flushPendingBatchResults")) {
3346             return;
3347         }
3348         if (DBG) {
3349             Log.d(TAG, "flushPendingBatchResults - scannerId=" + scannerId);
3350         }
3351         mScanManager.flushBatchScanResults(new ScanClient(scannerId));
3352     }
3353 
3354     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
stopScan(int scannerId, AttributionSource attributionSource)3355     void stopScan(int scannerId, AttributionSource attributionSource) {
3356         if (!Utils.checkScanPermissionForDataDelivery(
3357                 this, attributionSource, "GattService stopScan")) {
3358             return;
3359         }
3360         int scanQueueSize =
3361                 mScanManager.getBatchScanQueue().size() + mScanManager.getRegularScanQueue().size();
3362         if (DBG) {
3363             Log.d(TAG, "stopScan() - queue size =" + scanQueueSize);
3364         }
3365 
3366         AppScanStats app = null;
3367         app = mScannerMap.getAppScanStatsById(scannerId);
3368         if (app != null) {
3369             app.recordScanStop(scannerId);
3370         }
3371 
3372         mScanManager.stopScan(scannerId);
3373         mAdapterService.notifyActivityAttributionInfo(getAttributionSource(),
3374                 AdapterService.ACTIVITY_ATTRIBUTION_NO_ACTIVE_DEVICE_ADDRESS);
3375     }
3376 
3377     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
stopScan(PendingIntent intent, AttributionSource attributionSource)3378     void stopScan(PendingIntent intent, AttributionSource attributionSource) {
3379         if (!Utils.checkScanPermissionForDataDelivery(
3380                 this, attributionSource, "GattService stopScan")) {
3381             return;
3382         }
3383         PendingIntentInfo pii = new PendingIntentInfo();
3384         pii.intent = intent;
3385         ScannerMap.App app = mScannerMap.getByContextInfo(pii);
3386         if (VDBG) {
3387             Log.d(TAG, "stopScan(PendingIntent): app found = " + app);
3388         }
3389         if (app != null) {
3390             intent.removeCancelListener(mScanIntentCancelListener);
3391             final int scannerId = app.id;
3392             stopScan(scannerId, attributionSource);
3393             // Also unregister the scanner
3394             unregisterScanner(scannerId, attributionSource);
3395         }
3396     }
3397 
3398     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
disconnectAll(AttributionSource attributionSource)3399     void disconnectAll(AttributionSource attributionSource) {
3400         if (DBG) {
3401             Log.d(TAG, "disconnectAll()");
3402         }
3403         Map<Integer, String> connMap = mClientMap.getConnectedMap();
3404         for (Map.Entry<Integer, String> entry : connMap.entrySet()) {
3405             if (DBG) {
3406                 Log.d(TAG, "disconnecting addr:" + entry.getValue());
3407             }
3408             clientDisconnect(entry.getKey(), entry.getValue(), attributionSource);
3409             //clientDisconnect(int clientIf, String address)
3410         }
3411     }
3412 
3413     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
unregAll(AttributionSource attributionSource)3414     void unregAll(AttributionSource attributionSource) {
3415         for (Integer appId : mClientMap.getAllAppsIds()) {
3416             if (DBG) {
3417                 Log.d(TAG, "unreg:" + appId);
3418             }
3419             unregisterClient(appId, attributionSource);
3420         }
3421     }
3422 
3423     /**************************************************************************
3424      * PERIODIC SCANNING
3425      *************************************************************************/
3426     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
registerSync(ScanResult scanResult, int skip, int timeout, IPeriodicAdvertisingCallback callback, AttributionSource attributionSource)3427     void registerSync(ScanResult scanResult, int skip, int timeout,
3428             IPeriodicAdvertisingCallback callback, AttributionSource attributionSource) {
3429         if (!Utils.checkScanPermissionForDataDelivery(
3430                 this, attributionSource, "GattService registerSync")) {
3431             return;
3432         }
3433         mPeriodicScanManager.startSync(scanResult, skip, timeout, callback);
3434     }
3435 
3436     @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
unregisterSync( IPeriodicAdvertisingCallback callback, AttributionSource attributionSource)3437     void unregisterSync(
3438             IPeriodicAdvertisingCallback callback, AttributionSource attributionSource) {
3439         if (!Utils.checkScanPermissionForDataDelivery(
3440                 this, attributionSource, "GattService unregisterSync")) {
3441             return;
3442         }
3443         mPeriodicScanManager.stopSync(callback);
3444     }
3445 
transferSync(BluetoothDevice bda, int serviceData, int syncHandle, AttributionSource attributionSource)3446     void transferSync(BluetoothDevice bda, int serviceData, int syncHandle,
3447             AttributionSource attributionSource) {
3448         if (!Utils.checkScanPermissionForDataDelivery(
3449                 this, attributionSource, "GattService transferSync")) {
3450             return;
3451         }
3452         mPeriodicScanManager.transferSync(bda, serviceData, syncHandle);
3453     }
3454 
transferSetInfo(BluetoothDevice bda, int serviceData, int advHandle, IPeriodicAdvertisingCallback callback, AttributionSource attributionSource)3455     void transferSetInfo(BluetoothDevice bda, int serviceData,
3456                   int advHandle, IPeriodicAdvertisingCallback callback,
3457                   AttributionSource attributionSource) {
3458         if (!Utils.checkScanPermissionForDataDelivery(
3459                 this, attributionSource, "GattService transferSetInfo")) {
3460             return;
3461         }
3462         mPeriodicScanManager.transferSetInfo(bda, serviceData, advHandle, callback);
3463     }
3464 
3465     /**************************************************************************
3466      * ADVERTISING SET
3467      *************************************************************************/
3468     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
startAdvertisingSet(AdvertisingSetParameters parameters, AdvertiseData advertiseData, AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData, int duration, int maxExtAdvEvents, int serverIf, IAdvertisingSetCallback callback, AttributionSource attributionSource)3469     void startAdvertisingSet(AdvertisingSetParameters parameters, AdvertiseData advertiseData,
3470             AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters,
3471             AdvertiseData periodicData, int duration, int maxExtAdvEvents, int serverIf,
3472             IAdvertisingSetCallback callback, AttributionSource attributionSource) {
3473         if (!Utils.checkAdvertisePermissionForDataDelivery(
3474                 this, attributionSource, "GattService startAdvertisingSet")) {
3475             return;
3476         }
3477         if (parameters.getOwnAddressType() != AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT
3478                 || serverIf != 0) {
3479             Utils.enforceBluetoothPrivilegedPermission(this);
3480         }
3481         mAdvertiseManager.startAdvertisingSet(parameters, advertiseData, scanResponse,
3482                 periodicParameters, periodicData, duration, maxExtAdvEvents, serverIf, callback);
3483     }
3484 
3485     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
stopAdvertisingSet(IAdvertisingSetCallback callback, AttributionSource attributionSource)3486     void stopAdvertisingSet(IAdvertisingSetCallback callback, AttributionSource attributionSource) {
3487         if (!Utils.checkAdvertisePermissionForDataDelivery(
3488                 this, attributionSource, "GattService stopAdvertisingSet")) {
3489             return;
3490         }
3491         mAdvertiseManager.stopAdvertisingSet(callback);
3492     }
3493 
3494     @RequiresPermission(allOf = {
3495             android.Manifest.permission.BLUETOOTH_ADVERTISE,
3496             android.Manifest.permission.BLUETOOTH_PRIVILEGED,
3497     })
getOwnAddress(int advertiserId, AttributionSource attributionSource)3498     void getOwnAddress(int advertiserId, AttributionSource attributionSource) {
3499         if (!Utils.checkAdvertisePermissionForDataDelivery(
3500                 this, attributionSource, "GattService getOwnAddress")) {
3501             return;
3502         }
3503         enforceBluetoothPrivilegedPermission(this);
3504         mAdvertiseManager.getOwnAddress(advertiserId);
3505     }
3506 
3507     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
enableAdvertisingSet(int advertiserId, boolean enable, int duration, int maxExtAdvEvents, AttributionSource attributionSource)3508     void enableAdvertisingSet(int advertiserId, boolean enable, int duration, int maxExtAdvEvents,
3509             AttributionSource attributionSource) {
3510         if (!Utils.checkAdvertisePermissionForDataDelivery(
3511                 this, attributionSource, "GattService enableAdvertisingSet")) {
3512             return;
3513         }
3514         mAdvertiseManager.enableAdvertisingSet(advertiserId, enable, duration, maxExtAdvEvents);
3515     }
3516 
3517     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
setAdvertisingData( int advertiserId, AdvertiseData data, AttributionSource attributionSource)3518     void setAdvertisingData(
3519             int advertiserId, AdvertiseData data, AttributionSource attributionSource) {
3520         if (!Utils.checkAdvertisePermissionForDataDelivery(
3521                 this, attributionSource, "GattService setAdvertisingData")) {
3522             return;
3523         }
3524         mAdvertiseManager.setAdvertisingData(advertiserId, data);
3525     }
3526 
3527     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
setScanResponseData( int advertiserId, AdvertiseData data, AttributionSource attributionSource)3528     void setScanResponseData(
3529             int advertiserId, AdvertiseData data, AttributionSource attributionSource) {
3530         if (!Utils.checkAdvertisePermissionForDataDelivery(
3531                 this, attributionSource, "GattService setScanResponseData")) {
3532             return;
3533         }
3534         mAdvertiseManager.setScanResponseData(advertiserId, data);
3535     }
3536 
3537     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters, AttributionSource attributionSource)3538     void setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters,
3539             AttributionSource attributionSource) {
3540         if (!Utils.checkAdvertisePermissionForDataDelivery(
3541                 this, attributionSource, "GattService setAdvertisingParameters")) {
3542             return;
3543         }
3544         mAdvertiseManager.setAdvertisingParameters(advertiserId, parameters);
3545     }
3546 
3547     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
setPeriodicAdvertisingParameters(int advertiserId, PeriodicAdvertisingParameters parameters, AttributionSource attributionSource)3548     void setPeriodicAdvertisingParameters(int advertiserId,
3549             PeriodicAdvertisingParameters parameters, AttributionSource attributionSource) {
3550         if (!Utils.checkAdvertisePermissionForDataDelivery(
3551                 this, attributionSource, "GattService setPeriodicAdvertisingParameters")) {
3552             return;
3553         }
3554         mAdvertiseManager.setPeriodicAdvertisingParameters(advertiserId, parameters);
3555     }
3556 
3557     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
setPeriodicAdvertisingData( int advertiserId, AdvertiseData data, AttributionSource attributionSource)3558     void setPeriodicAdvertisingData(
3559             int advertiserId, AdvertiseData data, AttributionSource attributionSource) {
3560         if (!Utils.checkAdvertisePermissionForDataDelivery(
3561                 this, attributionSource, "GattService setPeriodicAdvertisingData")) {
3562             return;
3563         }
3564         mAdvertiseManager.setPeriodicAdvertisingData(advertiserId, data);
3565     }
3566 
3567     @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
setPeriodicAdvertisingEnable( int advertiserId, boolean enable, AttributionSource attributionSource)3568     void setPeriodicAdvertisingEnable(
3569             int advertiserId, boolean enable, AttributionSource attributionSource) {
3570         if (!Utils.checkAdvertisePermissionForDataDelivery(
3571                 this, attributionSource, "GattService setPeriodicAdvertisingEnable")) {
3572             return;
3573         }
3574         mAdvertiseManager.setPeriodicAdvertisingEnable(advertiserId, enable);
3575     }
3576 
3577     /**************************************************************************
3578      * Distance Measurement
3579      *************************************************************************/
3580 
getSupportedDistanceMeasurementMethods()3581     DistanceMeasurementMethod[] getSupportedDistanceMeasurementMethods() {
3582         return mDistanceMeasurementManager.getSupportedDistanceMeasurementMethods();
3583     }
3584 
3585 
startDistanceMeasurement(UUID uuid, DistanceMeasurementParams distanceMeasurementParams, IDistanceMeasurementCallback callback)3586     void startDistanceMeasurement(UUID uuid,
3587             DistanceMeasurementParams distanceMeasurementParams,
3588             IDistanceMeasurementCallback callback) {
3589         mDistanceMeasurementManager.startDistanceMeasurement(uuid, distanceMeasurementParams,
3590                 callback);
3591     }
3592 
stopDistanceMeasurement(UUID uuid, BluetoothDevice device, int method)3593     int stopDistanceMeasurement(UUID uuid, BluetoothDevice device, int method) {
3594         return mDistanceMeasurementManager.stopDistanceMeasurement(uuid, device, method, false);
3595     }
3596 
3597     /**************************************************************************
3598      * GATT Service functions - CLIENT
3599      *************************************************************************/
3600 
3601     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
registerClient(UUID uuid, IBluetoothGattCallback callback, boolean eatt_support, AttributionSource attributionSource)3602     void registerClient(UUID uuid, IBluetoothGattCallback callback, boolean eatt_support,
3603             AttributionSource attributionSource) {
3604         if (!Utils.checkConnectPermissionForDataDelivery(
3605                 this, attributionSource, "GattService registerClient")) {
3606             return;
3607         }
3608 
3609         if (DBG) {
3610             Log.d(TAG, "registerClient() - UUID=" + uuid);
3611         }
3612         mClientMap.add(uuid, null, callback, null, this);
3613         mNativeInterface.gattClientRegisterApp(uuid.getLeastSignificantBits(),
3614                 uuid.getMostSignificantBits(), eatt_support);
3615     }
3616 
3617     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
unregisterClient(int clientIf, AttributionSource attributionSource)3618     void unregisterClient(int clientIf, AttributionSource attributionSource) {
3619         if (!Utils.checkConnectPermissionForDataDelivery(
3620                 this, attributionSource, "GattService unregisterClient")) {
3621             return;
3622         }
3623 
3624         if (DBG) {
3625             Log.d(TAG, "unregisterClient() - clientIf=" + clientIf);
3626         }
3627         mClientMap.remove(clientIf);
3628         mNativeInterface.gattClientUnregisterApp(clientIf);
3629     }
3630 
3631     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
clientConnect(int clientIf, String address, int addressType, boolean isDirect, int transport, boolean opportunistic, int phy, AttributionSource attributionSource)3632     void clientConnect(int clientIf, String address, int addressType, boolean isDirect,
3633             int transport, boolean opportunistic, int phy, AttributionSource attributionSource) {
3634         if (!Utils.checkConnectPermissionForDataDelivery(
3635                 this, attributionSource, "GattService clientConnect")) {
3636             return;
3637         }
3638 
3639         if (DBG) {
3640             Log.d(TAG, "clientConnect() - address=" + address + ", addressType="
3641                     + addressType + ", isDirect=" + isDirect + ", opportunistic="
3642                     + opportunistic + ", phy=" + phy);
3643         }
3644         statsLogAppPackage(address, attributionSource.getUid(), clientIf);
3645         if (isDirect) {
3646           MetricsLogger.getInstance().count(BluetoothProtoEnums.GATT_CLIENT_CONNECT_IS_DIRECT, 1);
3647         } else {
3648           MetricsLogger.getInstance().count(BluetoothProtoEnums.GATT_CLIENT_CONNECT_IS_AUTOCONNECT, 1);
3649         }
3650         statsLogGattConnectionStateChange(
3651                 BluetoothProfile.GATT, address, clientIf,
3652                 BluetoothProtoEnums.CONNECTION_STATE_CONNECTING, -1);
3653         mNativeInterface.gattClientConnect(clientIf, address, addressType, isDirect, transport,
3654                 opportunistic, phy);
3655     }
3656 
3657     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
clientDisconnect(int clientIf, String address, AttributionSource attributionSource)3658     void clientDisconnect(int clientIf, String address, AttributionSource attributionSource) {
3659         if (!Utils.checkConnectPermissionForDataDelivery(
3660                 this, attributionSource, "GattService clientDisconnect")) {
3661             return;
3662         }
3663 
3664         Integer connId = mClientMap.connIdByAddress(clientIf, address);
3665         if (DBG) {
3666             Log.d(TAG, "clientDisconnect() - address=" + address + ", connId=" + connId);
3667         }
3668         statsLogGattConnectionStateChange(
3669                 BluetoothProfile.GATT, address, clientIf,
3670                 BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING, -1);
3671         mNativeInterface.gattClientDisconnect(clientIf, address, connId != null ? connId : 0);
3672     }
3673 
3674     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
clientSetPreferredPhy(int clientIf, String address, int txPhy, int rxPhy, int phyOptions, AttributionSource attributionSource)3675     void clientSetPreferredPhy(int clientIf, String address, int txPhy, int rxPhy, int phyOptions,
3676             AttributionSource attributionSource) {
3677         if (!Utils.checkConnectPermissionForDataDelivery(
3678                 this, attributionSource, "GattService clientSetPreferredPhy")) {
3679             return;
3680         }
3681 
3682         Integer connId = mClientMap.connIdByAddress(clientIf, address);
3683         if (connId == null) {
3684             if (DBG) {
3685                 Log.d(TAG, "clientSetPreferredPhy() - no connection to " + address);
3686             }
3687             return;
3688         }
3689 
3690         if (DBG) {
3691             Log.d(TAG, "clientSetPreferredPhy() - address=" + address + ", connId=" + connId);
3692         }
3693         mNativeInterface.gattClientSetPreferredPhy(clientIf, address, txPhy, rxPhy, phyOptions);
3694     }
3695 
3696     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
clientReadPhy(int clientIf, String address, AttributionSource attributionSource)3697     void clientReadPhy(int clientIf, String address, AttributionSource attributionSource) {
3698         if (!Utils.checkConnectPermissionForDataDelivery(
3699                 this, attributionSource, "GattService clientReadPhy")) {
3700             return;
3701         }
3702 
3703         Integer connId = mClientMap.connIdByAddress(clientIf, address);
3704         if (connId == null) {
3705             if (DBG) {
3706                 Log.d(TAG, "clientReadPhy() - no connection to " + address);
3707             }
3708             return;
3709         }
3710 
3711         if (DBG) {
3712             Log.d(TAG, "clientReadPhy() - address=" + address + ", connId=" + connId);
3713         }
3714         mNativeInterface.gattClientReadPhy(clientIf, address);
3715     }
3716 
3717     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
numHwTrackFiltersAvailable(AttributionSource attributionSource)3718     int numHwTrackFiltersAvailable(AttributionSource attributionSource) {
3719         if (!Utils.checkConnectPermissionForDataDelivery(
3720                 this, attributionSource, "GattService numHwTrackFiltersAvailable")) {
3721             return 0;
3722         }
3723         return (AdapterService.getAdapterService().getTotalNumOfTrackableAdvertisements()
3724                 - mScanManager.getCurrentUsedTrackingAdvertisement());
3725     }
3726 
3727     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getRegisteredServiceUuids(AttributionSource attributionSource)3728     synchronized List<ParcelUuid> getRegisteredServiceUuids(AttributionSource attributionSource) {
3729         if (!Utils.checkConnectPermissionForDataDelivery(
3730                 this, attributionSource, "GattService getRegisteredServiceUuids")) {
3731             return new ArrayList<>(0);
3732         }
3733         List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
3734         for (HandleMap.Entry entry : mHandleMap.getEntries()) {
3735             serviceUuids.add(new ParcelUuid(entry.uuid));
3736         }
3737         return serviceUuids;
3738     }
3739 
3740     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getConnectedDevices(AttributionSource attributionSource)3741     List<String> getConnectedDevices(AttributionSource attributionSource) {
3742         if (!Utils.checkConnectPermissionForDataDelivery(
3743                 this, attributionSource, "GattService getConnectedDevices")) {
3744             return new ArrayList<>(0);
3745         }
3746 
3747         Set<String> connectedDevAddress = new HashSet<String>();
3748         connectedDevAddress.addAll(mClientMap.getConnectedDevices());
3749         connectedDevAddress.addAll(mServerMap.getConnectedDevices());
3750         List<String> connectedDeviceList = new ArrayList<String>(connectedDevAddress);
3751         return connectedDeviceList;
3752     }
3753 
3754     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
refreshDevice(int clientIf, String address, AttributionSource attributionSource)3755     void refreshDevice(int clientIf, String address, AttributionSource attributionSource) {
3756         if (!Utils.checkConnectPermissionForDataDelivery(
3757                 this, attributionSource, "GattService refreshDevice")) {
3758             return;
3759         }
3760 
3761         if (DBG) {
3762             Log.d(TAG, "refreshDevice() - address=" + address);
3763         }
3764         mNativeInterface.gattClientRefresh(clientIf, address);
3765     }
3766 
3767     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
discoverServices(int clientIf, String address, AttributionSource attributionSource)3768     void discoverServices(int clientIf, String address, AttributionSource attributionSource) {
3769         if (!Utils.checkConnectPermissionForDataDelivery(
3770                 this, attributionSource, "GattService discoverServices")) {
3771             return;
3772         }
3773 
3774         Integer connId = mClientMap.connIdByAddress(clientIf, address);
3775         if (DBG) {
3776             Log.d(TAG, "discoverServices() - address=" + address + ", connId=" + connId);
3777         }
3778 
3779         if (connId != null) {
3780             mNativeInterface.gattClientSearchService(connId, true, 0, 0);
3781         } else {
3782             Log.e(TAG, "discoverServices() - No connection for " + address + "...");
3783         }
3784     }
3785 
3786     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
discoverServiceByUuid( int clientIf, String address, UUID uuid, AttributionSource attributionSource)3787     void discoverServiceByUuid(
3788             int clientIf, String address, UUID uuid, AttributionSource attributionSource) {
3789         if (!Utils.checkConnectPermissionForDataDelivery(
3790                 this, attributionSource, "GattService discoverServiceByUuid")) {
3791             return;
3792         }
3793 
3794         Integer connId = mClientMap.connIdByAddress(clientIf, address);
3795         if (connId != null) {
3796             mNativeInterface.gattClientDiscoverServiceByUuid(connId, uuid.getLeastSignificantBits(),
3797                     uuid.getMostSignificantBits());
3798         } else {
3799             Log.e(TAG, "discoverServiceByUuid() - No connection for " + address + "...");
3800         }
3801     }
3802 
3803     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
readCharacteristic(int clientIf, String address, int handle, int authReq, AttributionSource attributionSource)3804     void readCharacteristic(int clientIf, String address, int handle, int authReq,
3805             AttributionSource attributionSource) {
3806         if (!Utils.checkConnectPermissionForDataDelivery(
3807                 this, attributionSource, "GattService readCharacteristic")) {
3808             return;
3809         }
3810 
3811         if (VDBG) {
3812             Log.d(TAG, "readCharacteristic() - address=" + address);
3813         }
3814 
3815         Integer connId = mClientMap.connIdByAddress(clientIf, address);
3816         if (connId == null) {
3817             Log.e(TAG, "readCharacteristic() - No connection for " + address + "...");
3818             return;
3819         }
3820 
3821         try {
3822             permissionCheck(connId, handle);
3823         } catch (SecurityException ex) {
3824             String callingPackage = attributionSource.getPackageName();
3825             // Only throws on apps with target SDK T+ as this old API did not throw prior to T
3826             if (checkCallerTargetSdk(this, callingPackage, Build.VERSION_CODES.TIRAMISU)) {
3827                 throw ex;
3828             }
3829             Log.w(TAG, "readCharacteristic() - permission check failed!");
3830             return;
3831         }
3832 
3833         mNativeInterface.gattClientReadCharacteristic(connId, handle, authReq);
3834     }
3835 
3836     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
readUsingCharacteristicUuid(int clientIf, String address, UUID uuid, int startHandle, int endHandle, int authReq, AttributionSource attributionSource)3837     void readUsingCharacteristicUuid(int clientIf, String address, UUID uuid, int startHandle,
3838             int endHandle, int authReq, AttributionSource attributionSource) {
3839         if (!Utils.checkConnectPermissionForDataDelivery(
3840                 this, attributionSource, "GattService readUsingCharacteristicUuid")) {
3841             return;
3842         }
3843 
3844         if (VDBG) {
3845             Log.d(TAG, "readUsingCharacteristicUuid() - address=" + address);
3846         }
3847 
3848         Integer connId = mClientMap.connIdByAddress(clientIf, address);
3849         if (connId == null) {
3850             Log.e(TAG, "readUsingCharacteristicUuid() - No connection for " + address + "...");
3851             return;
3852         }
3853 
3854         try {
3855             permissionCheck(uuid);
3856         } catch (SecurityException ex) {
3857             String callingPackage = attributionSource.getPackageName();
3858             // Only throws on apps with target SDK T+ as this old API did not throw prior to T
3859             if (checkCallerTargetSdk(this, callingPackage, Build.VERSION_CODES.TIRAMISU)) {
3860                 throw ex;
3861             }
3862             Log.w(TAG, "readUsingCharacteristicUuid() - permission check failed!");
3863             return;
3864         }
3865 
3866         mNativeInterface.gattClientReadUsingCharacteristicUuid(connId,
3867                 uuid.getLeastSignificantBits(), uuid.getMostSignificantBits(), startHandle,
3868                 endHandle, authReq);
3869     }
3870 
3871     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
writeCharacteristic(int clientIf, String address, int handle, int writeType, int authReq, byte[] value, AttributionSource attributionSource)3872     int writeCharacteristic(int clientIf, String address, int handle, int writeType, int authReq,
3873             byte[] value, AttributionSource attributionSource) {
3874         if (!Utils.checkConnectPermissionForDataDelivery(
3875                 this, attributionSource, "GattService writeCharacteristic")) {
3876             return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION;
3877         }
3878 
3879         if (VDBG) {
3880             Log.d(TAG, "writeCharacteristic() - address=" + address);
3881         }
3882 
3883         if (mReliableQueue.contains(address)) {
3884             writeType = 3; // Prepared write
3885         }
3886 
3887         Integer connId = mClientMap.connIdByAddress(clientIf, address);
3888         if (connId == null) {
3889             Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
3890             return BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED;
3891         }
3892         permissionCheck(connId, handle);
3893 
3894         Log.d(TAG, "writeCharacteristic() - trying to acquire permit.");
3895         // Lock the thread until onCharacteristicWrite callback comes back.
3896         synchronized (mPermits) {
3897             Integer permit = mPermits.get(address);
3898             if (permit == null) {
3899                 Log.d(TAG, "writeCharacteristic() -  atomicBoolean uninitialized!");
3900                 return BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED;
3901             }
3902 
3903             boolean success = (permit == -1);
3904             if (!success) {
3905                 Log.d(TAG, "writeCharacteristic() - no permit available.");
3906                 return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY;
3907             }
3908             mPermits.put(address, connId);
3909         }
3910 
3911         mNativeInterface.gattClientWriteCharacteristic(connId, handle, writeType, authReq, value);
3912         return BluetoothStatusCodes.SUCCESS;
3913     }
3914 
3915     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
readDescriptor(int clientIf, String address, int handle, int authReq, AttributionSource attributionSource)3916     void readDescriptor(int clientIf, String address, int handle, int authReq,
3917             AttributionSource attributionSource) {
3918         if (!Utils.checkConnectPermissionForDataDelivery(
3919                 this, attributionSource, "GattService readDescriptor")) {
3920             return;
3921         }
3922 
3923         if (VDBG) {
3924             Log.d(TAG, "readDescriptor() - address=" + address);
3925         }
3926 
3927         Integer connId = mClientMap.connIdByAddress(clientIf, address);
3928         if (connId == null) {
3929             Log.e(TAG, "readDescriptor() - No connection for " + address + "...");
3930             return;
3931         }
3932 
3933         try {
3934             permissionCheck(connId, handle);
3935         } catch (SecurityException ex) {
3936             String callingPackage = attributionSource.getPackageName();
3937             // Only throws on apps with target SDK T+ as this old API did not throw prior to T
3938             if (checkCallerTargetSdk(this, callingPackage, Build.VERSION_CODES.TIRAMISU)) {
3939                 throw ex;
3940             }
3941             Log.w(TAG, "readDescriptor() - permission check failed!");
3942             return;
3943         }
3944 
3945         mNativeInterface.gattClientReadDescriptor(connId, handle, authReq);
3946     }
3947 
3948     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
writeDescriptor(int clientIf, String address, int handle, int authReq, byte[] value, AttributionSource attributionSource)3949     int writeDescriptor(int clientIf, String address, int handle, int authReq, byte[] value,
3950             AttributionSource attributionSource) {
3951         if (!Utils.checkConnectPermissionForDataDelivery(
3952                 this, attributionSource, "GattService writeDescriptor")) {
3953             return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION;
3954         }
3955         if (VDBG) {
3956             Log.d(TAG, "writeDescriptor() - address=" + address);
3957         }
3958 
3959         Integer connId = mClientMap.connIdByAddress(clientIf, address);
3960         if (connId == null) {
3961             Log.e(TAG, "writeDescriptor() - No connection for " + address + "...");
3962             return BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED;
3963         }
3964         permissionCheck(connId, handle);
3965 
3966         mNativeInterface.gattClientWriteDescriptor(connId, handle, authReq, value);
3967         return BluetoothStatusCodes.SUCCESS;
3968     }
3969 
3970     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
beginReliableWrite(int clientIf, String address, AttributionSource attributionSource)3971     void beginReliableWrite(int clientIf, String address, AttributionSource attributionSource) {
3972         if (!Utils.checkConnectPermissionForDataDelivery(
3973                 this, attributionSource, "GattService beginReliableWrite")) {
3974             return;
3975         }
3976 
3977         if (DBG) {
3978             Log.d(TAG, "beginReliableWrite() - address=" + address);
3979         }
3980         mReliableQueue.add(address);
3981     }
3982 
3983     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
endReliableWrite( int clientIf, String address, boolean execute, AttributionSource attributionSource)3984     void endReliableWrite(
3985             int clientIf, String address, boolean execute, AttributionSource attributionSource) {
3986         if (!Utils.checkConnectPermissionForDataDelivery(
3987                 this, attributionSource, "GattService endReliableWrite")) {
3988             return;
3989         }
3990 
3991         if (DBG) {
3992             Log.d(TAG, "endReliableWrite() - address=" + address + " execute: " + execute);
3993         }
3994         mReliableQueue.remove(address);
3995 
3996         Integer connId = mClientMap.connIdByAddress(clientIf, address);
3997         if (connId != null) {
3998             mNativeInterface.gattClientExecuteWrite(connId, execute);
3999         }
4000     }
4001 
4002     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
registerForNotification(int clientIf, String address, int handle, boolean enable, AttributionSource attributionSource)4003     void registerForNotification(int clientIf, String address, int handle, boolean enable,
4004             AttributionSource attributionSource) {
4005         if (!Utils.checkConnectPermissionForDataDelivery(
4006                 this, attributionSource, "GattService registerForNotification")) {
4007             return;
4008         }
4009 
4010         if (DBG) {
4011             Log.d(TAG, "registerForNotification() - address=" + address + " enable: " + enable);
4012         }
4013 
4014         Integer connId = mClientMap.connIdByAddress(clientIf, address);
4015         if (connId == null) {
4016             Log.e(TAG, "registerForNotification() - No connection for " + address + "...");
4017             return;
4018         }
4019 
4020         try {
4021             permissionCheck(connId, handle);
4022         } catch (SecurityException ex) {
4023             String callingPackage = attributionSource.getPackageName();
4024             // Only throws on apps with target SDK T+ as this old API did not throw prior to T
4025             if (checkCallerTargetSdk(this, callingPackage, Build.VERSION_CODES.TIRAMISU)) {
4026                 throw ex;
4027             }
4028             Log.w(TAG, "registerForNotification() - permission check failed!");
4029             return;
4030         }
4031 
4032         mNativeInterface.gattClientRegisterForNotifications(clientIf, address, handle, enable);
4033     }
4034 
4035     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
readRemoteRssi(int clientIf, String address, AttributionSource attributionSource)4036     void readRemoteRssi(int clientIf, String address, AttributionSource attributionSource) {
4037         if (!Utils.checkConnectPermissionForDataDelivery(
4038                 this, attributionSource, "GattService readRemoteRssi")) {
4039             return;
4040         }
4041 
4042         if (DBG) {
4043             Log.d(TAG, "readRemoteRssi() - address=" + address);
4044         }
4045         mNativeInterface.gattClientReadRemoteRssi(clientIf, address);
4046     }
4047 
4048     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
configureMTU(int clientIf, String address, int mtu, AttributionSource attributionSource)4049     void configureMTU(int clientIf, String address, int mtu, AttributionSource attributionSource) {
4050         if (!Utils.checkConnectPermissionForDataDelivery(
4051                 this, attributionSource, "GattService configureMTU")) {
4052             return;
4053         }
4054 
4055         if (DBG) {
4056             Log.d(TAG, "configureMTU() - address=" + address + " mtu=" + mtu);
4057         }
4058         Integer connId = mClientMap.connIdByAddress(clientIf, address);
4059         if (connId != null) {
4060             mNativeInterface.gattClientConfigureMTU(connId, mtu);
4061         } else {
4062             Log.e(TAG, "configureMTU() - No connection for " + address + "...");
4063         }
4064     }
4065 
4066     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
connectionParameterUpdate(int clientIf, String address, int connectionPriority, AttributionSource attributionSource)4067     void connectionParameterUpdate(int clientIf, String address, int connectionPriority,
4068             AttributionSource attributionSource) {
4069         if (!Utils.checkConnectPermissionForDataDelivery(
4070                 this, attributionSource, "GattService connectionParameterUpdate")) {
4071             return;
4072         }
4073 
4074         int minInterval;
4075         int maxInterval;
4076 
4077         // Peripheral latency
4078         int latency;
4079 
4080         // Link supervision timeout is measured in N * 10ms
4081         int timeout = 500; // 5s
4082 
4083 
4084         CompanionManager manager =
4085                 AdapterService.getAdapterService().getCompanionManager();
4086 
4087         minInterval = manager.getGattConnParameters(
4088                 address, CompanionManager.GATT_CONN_INTERVAL_MIN, connectionPriority);
4089         maxInterval = manager.getGattConnParameters(
4090                 address, CompanionManager.GATT_CONN_INTERVAL_MAX, connectionPriority);
4091         latency = manager.getGattConnParameters(
4092                 address, CompanionManager.GATT_CONN_LATENCY, connectionPriority);
4093 
4094         Log.d(TAG, "connectionParameterUpdate() - address=" + address + " params="
4095                 + connectionPriority + " interval=" + minInterval + "/" + maxInterval
4096                 + " timeout=" + timeout);
4097 
4098         mNativeInterface.gattConnectionParameterUpdate(clientIf, address, minInterval, maxInterval,
4099                 latency, timeout, 0, 0);
4100     }
4101 
4102     @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)4103     void leConnectionUpdate(int clientIf, String address, int minInterval,
4104                             int maxInterval, int peripheralLatency,
4105                             int supervisionTimeout, int minConnectionEventLen,
4106                             int maxConnectionEventLen, AttributionSource attributionSource) {
4107         if (!Utils.checkConnectPermissionForDataDelivery(
4108                 this, attributionSource, "GattService leConnectionUpdate")) {
4109             return;
4110         }
4111 
4112         Log.d(TAG, "leConnectionUpdate() - address=" + address + ", intervals="
4113                     + minInterval + "/" + maxInterval + ", latency=" + peripheralLatency
4114                     + ", timeout=" + supervisionTimeout + "msec" + ", min_ce="
4115                     + minConnectionEventLen + ", max_ce=" + maxConnectionEventLen);
4116 
4117         mNativeInterface.gattConnectionParameterUpdate(clientIf, address, minInterval, maxInterval,
4118                                             peripheralLatency, supervisionTimeout,
4119                                             minConnectionEventLen, maxConnectionEventLen);
4120     }
4121 
4122     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
subrateModeRequest(int clientIf, String address, int subrateMode, AttributionSource attributionSource)4123     void subrateModeRequest(int clientIf, String address, int subrateMode,
4124                                    AttributionSource attributionSource) {
4125         if (!Utils.checkConnectPermissionForDataDelivery(
4126                 this, attributionSource, "GattService subrateModeRequest")) {
4127             return;
4128         }
4129 
4130         int subrateMin;
4131         int subrateMax;
4132         int maxLatency;
4133         int contNumber;
4134         // Link supervision timeout is measured in N * 10ms
4135         int supervisionTimeout = 500; // 5s
4136 
4137         Resources res = getResources();
4138 
4139         switch (subrateMode) {
4140             case BluetoothGatt.SUBRATE_REQUEST_MODE_HIGH:
4141                 subrateMin = res.getInteger(R.integer.subrate_mode_high_priority_min_subrate);
4142                 subrateMax = res.getInteger(R.integer.subrate_mode_high_priority_max_subrate);
4143                 maxLatency = res.getInteger(R.integer.subrate_mode_high_priority_latency);
4144                 contNumber = res.getInteger(R.integer.subrate_mode_high_priority_cont_number);
4145                 break;
4146 
4147             case BluetoothGatt.SUBRATE_REQUEST_MODE_LOW_POWER:
4148                 subrateMin = res.getInteger(R.integer.subrate_mode_low_power_min_subrate);
4149                 subrateMax = res.getInteger(R.integer.subrate_mode_low_power_max_subrate);
4150                 maxLatency = res.getInteger(R.integer.subrate_mode_low_power_latency);
4151                 contNumber = res.getInteger(R.integer.subrate_mode_low_power_cont_number);
4152                 break;
4153 
4154             case BluetoothGatt.SUBRATE_REQUEST_MODE_BALANCED:
4155             default:
4156                 subrateMin = res.getInteger(R.integer.subrate_mode_balanced_min_subrate);
4157                 subrateMax = res.getInteger(R.integer.subrate_mode_balanced_max_subrate);
4158                 maxLatency = res.getInteger(R.integer.subrate_mode_balanced_latency);
4159                 contNumber = res.getInteger(R.integer.subrate_mode_balanced_cont_number);
4160                 break;
4161         }
4162 
4163         if (DBG) {
4164             Log.d(TAG, "subrateModeRequest() - "
4165                     + "address=" + BluetoothUtils.toAnonymizedAddress(address)
4166                     + ", subrate min/max=" + subrateMin + "/" + subrateMax
4167                     + ", maxLatency=" + maxLatency
4168                     + ", continuation Number=" + contNumber
4169                     + ", timeout=" + supervisionTimeout);
4170         }
4171 
4172         mNativeInterface.gattSubrateRequest(clientIf, address, subrateMin, subrateMax, maxLatency,
4173                                  contNumber, supervisionTimeout);
4174     }
4175 
4176     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
leSubrateRequest(int clientIf, String address, int subrateMin, int subrateMax, int maxLatency, int contNumber, int supervisionTimeout, AttributionSource attributionSource)4177     void leSubrateRequest(int clientIf, String address, int subrateMin, int subrateMax,
4178             int maxLatency, int contNumber, int supervisionTimeout,
4179             AttributionSource attributionSource) {
4180         if (!Utils.checkConnectPermissionForDataDelivery(
4181                 this, attributionSource, "GattService leSubrateRequest")) {
4182             return;
4183         }
4184 
4185         if (DBG) {
4186             Log.d(TAG, "leSubrateRequest() - "
4187                     + "address=" + BluetoothUtils.toAnonymizedAddress(address)
4188                     + ", subrate min/max=" + subrateMin + "/" + subrateMax
4189                     + ", maxLatency=" + maxLatency
4190                     + ", continuation Number=" + contNumber
4191                     + ", timeout=" + supervisionTimeout);
4192         }
4193 
4194         mNativeInterface.gattSubrateRequest(clientIf, address, subrateMin, subrateMax, maxLatency,
4195                 contNumber, supervisionTimeout);
4196     }
4197 
4198     /**************************************************************************
4199      * Callback functions - SERVER
4200      *************************************************************************/
4201 
onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb)4202     void onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb)
4203             throws RemoteException {
4204 
4205         UUID uuid = new UUID(uuidMsb, uuidLsb);
4206         if (DBG) {
4207             Log.d(TAG, "onServerRegistered() - UUID=" + uuid + ", serverIf=" + serverIf);
4208         }
4209         ServerMap.App app = mServerMap.getByUuid(uuid);
4210         if (app != null) {
4211             app.id = serverIf;
4212             app.linkToDeath(new ServerDeathRecipient(serverIf));
4213             app.callback.onServerRegistered(status, serverIf);
4214         }
4215     }
4216 
onServiceAdded(int status, int serverIf, List<GattDbElement> service)4217     void onServiceAdded(int status, int serverIf, List<GattDbElement> service)
4218             throws RemoteException {
4219         if (DBG) {
4220             Log.d(TAG, "onServiceAdded(), status=" + status);
4221         }
4222 
4223         if (status != 0) {
4224             return;
4225         }
4226 
4227         GattDbElement svcEl = service.get(0);
4228         int srvcHandle = svcEl.attributeHandle;
4229 
4230         BluetoothGattService svc = null;
4231 
4232         for (GattDbElement el : service) {
4233             if (el.type == GattDbElement.TYPE_PRIMARY_SERVICE) {
4234                 mHandleMap.addService(serverIf, el.attributeHandle, el.uuid,
4235                         BluetoothGattService.SERVICE_TYPE_PRIMARY, 0, false);
4236                 svc = new BluetoothGattService(svcEl.uuid, svcEl.attributeHandle,
4237                         BluetoothGattService.SERVICE_TYPE_PRIMARY);
4238             } else if (el.type == GattDbElement.TYPE_SECONDARY_SERVICE) {
4239                 mHandleMap.addService(serverIf, el.attributeHandle, el.uuid,
4240                         BluetoothGattService.SERVICE_TYPE_SECONDARY, 0, false);
4241                 svc = new BluetoothGattService(svcEl.uuid, svcEl.attributeHandle,
4242                         BluetoothGattService.SERVICE_TYPE_SECONDARY);
4243             } else if (el.type == GattDbElement.TYPE_CHARACTERISTIC) {
4244                 mHandleMap.addCharacteristic(serverIf, el.attributeHandle, el.uuid, srvcHandle);
4245                 svc.addCharacteristic(
4246                         new BluetoothGattCharacteristic(el.uuid, el.attributeHandle, el.properties,
4247                                 el.permissions));
4248             } else if (el.type == GattDbElement.TYPE_DESCRIPTOR) {
4249                 mHandleMap.addDescriptor(serverIf, el.attributeHandle, el.uuid, srvcHandle);
4250                 List<BluetoothGattCharacteristic> chars = svc.getCharacteristics();
4251                 chars.get(chars.size() - 1)
4252                         .addDescriptor(new BluetoothGattDescriptor(el.uuid, el.attributeHandle,
4253                                 el.permissions));
4254             }
4255         }
4256         mHandleMap.setStarted(serverIf, srvcHandle, true);
4257 
4258         ServerMap.App app = mServerMap.getById(serverIf);
4259         if (app != null) {
4260             app.callback.onServiceAdded(status, svc);
4261         }
4262     }
4263 
onServiceStopped(int status, int serverIf, int srvcHandle)4264     void onServiceStopped(int status, int serverIf, int srvcHandle) throws RemoteException {
4265         if (DBG) {
4266             Log.d(TAG, "onServiceStopped() srvcHandle=" + srvcHandle + ", status=" + status);
4267         }
4268         if (status == 0) {
4269             mHandleMap.setStarted(serverIf, srvcHandle, false);
4270         }
4271         stopNextService(serverIf, status);
4272     }
4273 
onServiceDeleted(int status, int serverIf, int srvcHandle)4274     void onServiceDeleted(int status, int serverIf, int srvcHandle) {
4275         if (DBG) {
4276             Log.d(TAG, "onServiceDeleted() srvcHandle=" + srvcHandle + ", status=" + status);
4277         }
4278         mHandleMap.deleteService(serverIf, srvcHandle);
4279     }
4280 
onClientConnected(String address, boolean connected, int connId, int serverIf)4281     void onClientConnected(String address, boolean connected, int connId, int serverIf)
4282             throws RemoteException {
4283 
4284         if (DBG) {
4285             Log.d(TAG,
4286                     "onClientConnected() connId=" + connId + ", address=" + address + ", connected="
4287                             + connected);
4288         }
4289 
4290         ServerMap.App app = mServerMap.getById(serverIf);
4291         if (app == null) {
4292             return;
4293         }
4294         int connectionState;
4295         if (connected) {
4296             mServerMap.addConnection(serverIf, connId, address);
4297             connectionState = BluetoothProtoEnums.CONNECTION_STATE_CONNECTED;
4298         } else {
4299             mServerMap.removeConnection(serverIf, connId);
4300             connectionState = BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED;
4301         }
4302 
4303         int applicationUid = -1;
4304 
4305         try {
4306           applicationUid = this.getPackageManager().getPackageUid(app.name, PackageInfoFlags.of(0));
4307 
4308         } catch (NameNotFoundException e) {
4309           Log.d(TAG, "onClientConnected() uid_not_found=" + app.name);
4310         }
4311 
4312         app.callback.onServerConnectionState((byte) 0, serverIf, connected, address);
4313         statsLogAppPackage(address, applicationUid, serverIf);
4314         statsLogGattConnectionStateChange(
4315                 BluetoothProfile.GATT_SERVER, address, serverIf, connectionState, -1);
4316     }
4317 
onServerReadCharacteristic(String address, int connId, int transId, int handle, int offset, boolean isLong)4318     void onServerReadCharacteristic(String address, int connId, int transId, int handle, int offset,
4319             boolean isLong) throws RemoteException {
4320         if (VDBG) {
4321             Log.d(TAG, "onServerReadCharacteristic() connId=" + connId + ", address=" + address
4322                     + ", handle=" + handle + ", requestId=" + transId + ", offset=" + offset);
4323         }
4324 
4325         HandleMap.Entry entry = mHandleMap.getByHandle(handle);
4326         if (entry == null) {
4327             return;
4328         }
4329 
4330         mHandleMap.addRequest(transId, handle);
4331 
4332         ServerMap.App app = mServerMap.getById(entry.serverIf);
4333         if (app == null) {
4334             return;
4335         }
4336 
4337         app.callback.onCharacteristicReadRequest(address, transId, offset, isLong, handle);
4338     }
4339 
onServerReadDescriptor(String address, int connId, int transId, int handle, int offset, boolean isLong)4340     void onServerReadDescriptor(String address, int connId, int transId, int handle, int offset,
4341             boolean isLong) throws RemoteException {
4342         if (VDBG) {
4343             Log.d(TAG, "onServerReadDescriptor() connId=" + connId + ", address=" + address
4344                     + ", handle=" + handle + ", requestId=" + transId + ", offset=" + offset);
4345         }
4346 
4347         HandleMap.Entry entry = mHandleMap.getByHandle(handle);
4348         if (entry == null) {
4349             return;
4350         }
4351 
4352         mHandleMap.addRequest(transId, handle);
4353 
4354         ServerMap.App app = mServerMap.getById(entry.serverIf);
4355         if (app == null) {
4356             return;
4357         }
4358 
4359         app.callback.onDescriptorReadRequest(address, transId, offset, isLong, handle);
4360     }
4361 
onServerWriteCharacteristic(String address, int connId, int transId, int handle, int offset, int length, boolean needRsp, boolean isPrep, byte[] data)4362     void onServerWriteCharacteristic(String address, int connId, int transId, int handle,
4363             int offset, int length, boolean needRsp, boolean isPrep, byte[] data)
4364             throws RemoteException {
4365         if (VDBG) {
4366             Log.d(TAG, "onServerWriteCharacteristic() connId=" + connId + ", address=" + address
4367                     + ", handle=" + handle + ", requestId=" + transId + ", isPrep=" + isPrep
4368                     + ", offset=" + offset);
4369         }
4370 
4371         HandleMap.Entry entry = mHandleMap.getByHandle(handle);
4372         if (entry == null) {
4373             return;
4374         }
4375 
4376         mHandleMap.addRequest(transId, handle);
4377 
4378         ServerMap.App app = mServerMap.getById(entry.serverIf);
4379         if (app == null) {
4380             return;
4381         }
4382 
4383         app.callback.onCharacteristicWriteRequest(address, transId, offset, length, isPrep, needRsp,
4384                 handle, data);
4385     }
4386 
onServerWriteDescriptor(String address, int connId, int transId, int handle, int offset, int length, boolean needRsp, boolean isPrep, byte[] data)4387     void onServerWriteDescriptor(String address, int connId, int transId, int handle, int offset,
4388             int length, boolean needRsp, boolean isPrep, byte[] data) throws RemoteException {
4389         if (VDBG) {
4390             Log.d(TAG, "onAttributeWrite() connId=" + connId + ", address=" + address + ", handle="
4391                     + handle + ", requestId=" + transId + ", isPrep=" + isPrep + ", offset="
4392                     + offset);
4393         }
4394 
4395         HandleMap.Entry entry = mHandleMap.getByHandle(handle);
4396         if (entry == null) {
4397             return;
4398         }
4399 
4400         mHandleMap.addRequest(transId, handle);
4401 
4402         ServerMap.App app = mServerMap.getById(entry.serverIf);
4403         if (app == null) {
4404             return;
4405         }
4406 
4407         app.callback.onDescriptorWriteRequest(address, transId, offset, length, isPrep, needRsp,
4408                 handle, data);
4409     }
4410 
onExecuteWrite(String address, int connId, int transId, int execWrite)4411     void onExecuteWrite(String address, int connId, int transId, int execWrite)
4412             throws RemoteException {
4413         if (DBG) {
4414             Log.d(TAG, "onExecuteWrite() connId=" + connId + ", address=" + address + ", transId="
4415                     + transId);
4416         }
4417 
4418         ServerMap.App app = mServerMap.getByConnId(connId);
4419         if (app == null) {
4420             return;
4421         }
4422 
4423         app.callback.onExecuteWrite(address, transId, execWrite == 1);
4424     }
4425 
onResponseSendCompleted(int status, int attrHandle)4426     void onResponseSendCompleted(int status, int attrHandle) {
4427         if (DBG) {
4428             Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle);
4429         }
4430     }
4431 
onNotificationSent(int connId, int status)4432     void onNotificationSent(int connId, int status) throws RemoteException {
4433         if (VDBG) {
4434             Log.d(TAG, "onNotificationSent() connId=" + connId + ", status=" + status);
4435         }
4436 
4437         String address = mServerMap.addressByConnId(connId);
4438         if (address == null) {
4439             return;
4440         }
4441 
4442         ServerMap.App app = mServerMap.getByConnId(connId);
4443         if (app == null) {
4444             return;
4445         }
4446 
4447         if (!app.isCongested) {
4448             app.callback.onNotificationSent(address, status);
4449         } else {
4450             if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) {
4451                 status = BluetoothGatt.GATT_SUCCESS;
4452             }
4453             app.queueCallback(new CallbackInfo.Builder(address, status).build());
4454         }
4455     }
4456 
onServerCongestion(int connId, boolean congested)4457     void onServerCongestion(int connId, boolean congested) throws RemoteException {
4458         if (DBG) {
4459             Log.d(TAG, "onServerCongestion() - connId=" + connId + ", congested=" + congested);
4460         }
4461 
4462         ServerMap.App app = mServerMap.getByConnId(connId);
4463         if (app == null) {
4464             return;
4465         }
4466 
4467         app.isCongested = congested;
4468         while (!app.isCongested) {
4469             CallbackInfo callbackInfo = app.popQueuedCallback();
4470             if (callbackInfo == null) {
4471                 return;
4472             }
4473             app.callback.onNotificationSent(callbackInfo.address, callbackInfo.status);
4474         }
4475     }
4476 
onMtuChanged(int connId, int mtu)4477     void onMtuChanged(int connId, int mtu) throws RemoteException {
4478         if (DBG) {
4479             Log.d(TAG, "onMtuChanged() - connId=" + connId + ", mtu=" + mtu);
4480         }
4481 
4482         String address = mServerMap.addressByConnId(connId);
4483         if (address == null) {
4484             return;
4485         }
4486 
4487         ServerMap.App app = mServerMap.getByConnId(connId);
4488         if (app == null) {
4489             return;
4490         }
4491 
4492         app.callback.onMtuChanged(address, mtu);
4493     }
4494 
4495     /**************************************************************************
4496      * GATT Service functions - SERVER
4497      *************************************************************************/
4498 
4499     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
registerServer(UUID uuid, IBluetoothGattServerCallback callback, boolean eatt_support, AttributionSource attributionSource)4500     void registerServer(UUID uuid, IBluetoothGattServerCallback callback, boolean eatt_support,
4501             AttributionSource attributionSource) {
4502         if (!Utils.checkConnectPermissionForDataDelivery(
4503                 this, attributionSource, "GattService registerServer")) {
4504             return;
4505         }
4506 
4507         if (DBG) {
4508             Log.d(TAG, "registerServer() - UUID=" + uuid);
4509         }
4510         mServerMap.add(uuid, null, callback, null, this);
4511         mNativeInterface.gattServerRegisterApp(uuid.getLeastSignificantBits(),
4512                 uuid.getMostSignificantBits(), eatt_support);
4513     }
4514 
4515     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
unregisterServer(int serverIf, AttributionSource attributionSource)4516     void unregisterServer(int serverIf, AttributionSource attributionSource) {
4517         if (!Utils.checkConnectPermissionForDataDelivery(
4518                 this, attributionSource, "GattService unregisterServer")) {
4519             return;
4520         }
4521 
4522         if (DBG) {
4523             Log.d(TAG, "unregisterServer() - serverIf=" + serverIf);
4524         }
4525 
4526         deleteServices(serverIf);
4527 
4528         mServerMap.remove(serverIf);
4529         mNativeInterface.gattServerUnregisterApp(serverIf);
4530     }
4531 
4532     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
serverConnect(int serverIf, String address, boolean isDirect, int transport, AttributionSource attributionSource)4533     void serverConnect(int serverIf, String address, boolean isDirect, int transport,
4534             AttributionSource attributionSource) {
4535         if (!Utils.checkConnectPermissionForDataDelivery(
4536                 this, attributionSource, "GattService serverConnect")) {
4537             return;
4538         }
4539 
4540         if (DBG) {
4541             Log.d(TAG, "serverConnect() - address=" + address);
4542         }
4543         mNativeInterface.gattServerConnect(serverIf, address, isDirect, transport);
4544     }
4545 
4546     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
serverDisconnect(int serverIf, String address, AttributionSource attributionSource)4547     void serverDisconnect(int serverIf, String address, AttributionSource attributionSource) {
4548         if (!Utils.checkConnectPermissionForDataDelivery(
4549                 this, attributionSource, "GattService serverDisconnect")) {
4550             return;
4551         }
4552 
4553         Integer connId = mServerMap.connIdByAddress(serverIf, address);
4554         if (DBG) {
4555             Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId);
4556         }
4557 
4558         mNativeInterface.gattServerDisconnect(serverIf, address, connId != null ? connId : 0);
4559     }
4560 
4561     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
serverSetPreferredPhy(int serverIf, String address, int txPhy, int rxPhy, int phyOptions, AttributionSource attributionSource)4562     void serverSetPreferredPhy(int serverIf, String address, int txPhy, int rxPhy, int phyOptions,
4563             AttributionSource attributionSource) {
4564         if (!Utils.checkConnectPermissionForDataDelivery(
4565                 this, attributionSource, "GattService serverSetPreferredPhy")) {
4566             return;
4567         }
4568 
4569         Integer connId = mServerMap.connIdByAddress(serverIf, address);
4570         if (connId == null) {
4571             if (DBG) {
4572                 Log.d(TAG, "serverSetPreferredPhy() - no connection to " + address);
4573             }
4574             return;
4575         }
4576 
4577         if (DBG) {
4578             Log.d(TAG, "serverSetPreferredPhy() - address=" + address + ", connId=" + connId);
4579         }
4580         mNativeInterface.gattServerSetPreferredPhy(serverIf, address, txPhy, rxPhy, phyOptions);
4581     }
4582 
4583     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
serverReadPhy(int serverIf, String address, AttributionSource attributionSource)4584     void serverReadPhy(int serverIf, String address, AttributionSource attributionSource) {
4585         if (!Utils.checkConnectPermissionForDataDelivery(
4586                 this, attributionSource, "GattService serverReadPhy")) {
4587             return;
4588         }
4589 
4590         Integer connId = mServerMap.connIdByAddress(serverIf, address);
4591         if (connId == null) {
4592             if (DBG) {
4593                 Log.d(TAG, "serverReadPhy() - no connection to " + address);
4594             }
4595             return;
4596         }
4597 
4598         if (DBG) {
4599             Log.d(TAG, "serverReadPhy() - address=" + address + ", connId=" + connId);
4600         }
4601         mNativeInterface.gattServerReadPhy(serverIf, address);
4602     }
4603 
4604     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
addService( int serverIf, BluetoothGattService service, AttributionSource attributionSource)4605     void addService(
4606             int serverIf, BluetoothGattService service, AttributionSource attributionSource) {
4607         if (!Utils.checkConnectPermissionForDataDelivery(
4608                 this, attributionSource, "GattService addService")) {
4609             return;
4610         }
4611 
4612         if (DBG) {
4613             Log.d(TAG, "addService() - uuid=" + service.getUuid());
4614         }
4615 
4616         List<GattDbElement> db = new ArrayList<GattDbElement>();
4617 
4618         if (service.getType() == BluetoothGattService.SERVICE_TYPE_PRIMARY) {
4619             db.add(GattDbElement.createPrimaryService(service.getUuid()));
4620         } else {
4621             db.add(GattDbElement.createSecondaryService(service.getUuid()));
4622         }
4623 
4624         for (BluetoothGattService includedService : service.getIncludedServices()) {
4625             int inclSrvcHandle = includedService.getInstanceId();
4626 
4627             if (mHandleMap.checkServiceExists(includedService.getUuid(), inclSrvcHandle)) {
4628                 db.add(GattDbElement.createIncludedService(inclSrvcHandle));
4629             } else {
4630                 Log.e(TAG,
4631                         "included service with UUID " + includedService.getUuid() + " not found!");
4632             }
4633         }
4634 
4635         for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
4636             int permission =
4637                     ((characteristic.getKeySize() - 7) << 12) + characteristic.getPermissions();
4638             db.add(GattDbElement.createCharacteristic(characteristic.getUuid(),
4639                     characteristic.getProperties(), permission));
4640 
4641             for (BluetoothGattDescriptor descriptor : characteristic.getDescriptors()) {
4642                 permission =
4643                         ((characteristic.getKeySize() - 7) << 12) + descriptor.getPermissions();
4644                 db.add(GattDbElement.createDescriptor(descriptor.getUuid(), permission));
4645             }
4646         }
4647 
4648         mNativeInterface.gattServerAddService(serverIf, db);
4649     }
4650 
4651     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
removeService(int serverIf, int handle, AttributionSource attributionSource)4652     void removeService(int serverIf, int handle, AttributionSource attributionSource) {
4653         if (!Utils.checkConnectPermissionForDataDelivery(
4654                 this, attributionSource, "GattService removeService")) {
4655             return;
4656         }
4657 
4658         if (DBG) {
4659             Log.d(TAG, "removeService() - handle=" + handle);
4660         }
4661 
4662         mNativeInterface.gattServerDeleteService(serverIf, handle);
4663     }
4664 
4665     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
clearServices(int serverIf, AttributionSource attributionSource)4666     void clearServices(int serverIf, AttributionSource attributionSource) {
4667         if (!Utils.checkConnectPermissionForDataDelivery(
4668                 this, attributionSource, "GattService clearServices")) {
4669             return;
4670         }
4671 
4672         if (DBG) {
4673             Log.d(TAG, "clearServices()");
4674         }
4675         deleteServices(serverIf);
4676     }
4677 
4678     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
sendResponse(int serverIf, String address, int requestId, int status, int offset, byte[] value, AttributionSource attributionSource)4679     void sendResponse(int serverIf, String address, int requestId, int status, int offset,
4680             byte[] value, AttributionSource attributionSource) {
4681         if (!Utils.checkConnectPermissionForDataDelivery(
4682                 this, attributionSource, "GattService sendResponse")) {
4683             return;
4684         }
4685 
4686         if (VDBG) {
4687             Log.d(TAG, "sendResponse() - address=" + address);
4688         }
4689 
4690         int handle = 0;
4691         HandleMap.Entry entry = mHandleMap.getByRequestId(requestId);
4692         if (entry != null) {
4693             handle = entry.handle;
4694         }
4695 
4696         Integer connId = mServerMap.connIdByAddress(serverIf, address);
4697         mNativeInterface.gattServerSendResponse(serverIf, connId != null ? connId : 0, requestId,
4698                 (byte) status, handle, offset, value, (byte) 0);
4699         mHandleMap.deleteRequest(requestId);
4700     }
4701 
4702     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
sendNotification(int serverIf, String address, int handle, boolean confirm, byte[] value, AttributionSource attributionSource)4703     int sendNotification(int serverIf, String address, int handle, boolean confirm, byte[] value,
4704             AttributionSource attributionSource) {
4705         if (!Utils.checkConnectPermissionForDataDelivery(
4706                 this, attributionSource, "GattService sendNotification")) {
4707             return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION;
4708         }
4709 
4710         if (VDBG) {
4711             Log.d(TAG, "sendNotification() - address=" + address + " handle=" + handle);
4712         }
4713 
4714         Integer connId = mServerMap.connIdByAddress(serverIf, address);
4715         if (connId == null || connId == 0) {
4716             return BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED;
4717         }
4718 
4719         if (confirm) {
4720             mNativeInterface.gattServerSendIndication(serverIf, handle, connId, value);
4721         } else {
4722             mNativeInterface.gattServerSendNotification(serverIf, handle, connId, value);
4723         }
4724 
4725         return BluetoothStatusCodes.SUCCESS;
4726     }
4727 
4728 
4729     /**************************************************************************
4730      * Private functions
4731      *************************************************************************/
4732 
isHidSrvcUuid(final UUID uuid)4733     private boolean isHidSrvcUuid(final UUID uuid) {
4734         return HID_SERVICE_UUID.equals(uuid);
4735     }
4736 
isHidCharUuid(final UUID uuid)4737     private boolean isHidCharUuid(final UUID uuid) {
4738         for (UUID hidUuid : HID_UUIDS) {
4739             if (hidUuid.equals(uuid)) {
4740                 return true;
4741             }
4742         }
4743         return false;
4744     }
4745 
isAndroidTvRemoteSrvcUuid(final UUID uuid)4746     private boolean isAndroidTvRemoteSrvcUuid(final UUID uuid) {
4747         return ANDROID_TV_REMOTE_SERVICE_UUID.equals(uuid);
4748     }
4749 
isFidoSrvcUuid(final UUID uuid)4750     private boolean isFidoSrvcUuid(final UUID uuid) {
4751         return FIDO_SERVICE_UUID.equals(uuid);
4752     }
4753 
isLeAudioSrvcUuid(final UUID uuid)4754     private boolean isLeAudioSrvcUuid(final UUID uuid) {
4755         for (UUID leAudioUuid : LE_AUDIO_SERVICE_UUIDS) {
4756             if (leAudioUuid.equals(uuid)) {
4757                 return true;
4758             }
4759         }
4760         return false;
4761     }
4762 
isRestrictedSrvcUuid(final UUID uuid)4763     private boolean isRestrictedSrvcUuid(final UUID uuid) {
4764         return isFidoSrvcUuid(uuid)
4765                 || isAndroidTvRemoteSrvcUuid(uuid)
4766                 || isLeAudioSrvcUuid(uuid);
4767     }
4768 
getDeviceType(BluetoothDevice device)4769     private int getDeviceType(BluetoothDevice device) {
4770         int type = mNativeInterface.gattClientGetDeviceType(device.getAddress());
4771         if (DBG) {
4772             Log.d(TAG, "getDeviceType() - device=" + device + ", type=" + type);
4773         }
4774         return type;
4775     }
4776 
needsPrivilegedPermissionForScan(ScanSettings settings)4777     private boolean needsPrivilegedPermissionForScan(ScanSettings settings) {
4778         // BLE scan only mode needs special permission.
4779         if (mAdapterService.getState() != BluetoothAdapter.STATE_ON) {
4780             return true;
4781         }
4782 
4783         // Regular scan, no special permission.
4784         if (settings == null) {
4785             return false;
4786         }
4787 
4788         // Ambient discovery mode, needs privileged permission.
4789         if (settings.getScanMode() == ScanSettings.SCAN_MODE_AMBIENT_DISCOVERY) {
4790             return true;
4791         }
4792 
4793         // Regular scan, no special permission.
4794         if (settings.getReportDelayMillis() == 0) {
4795             return false;
4796         }
4797 
4798         // Batch scan, truncated mode needs permission.
4799         return settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_ABBREVIATED;
4800     }
4801 
4802     /*
4803      * The {@link ScanFilter#setDeviceAddress} API overloads are @SystemApi access methods.  This
4804      * requires that the permissions be BLUETOOTH_PRIVILEGED.
4805      */
4806     @SuppressLint("AndroidFrameworkRequiresPermission")
enforcePrivilegedPermissionIfNeeded(List<ScanFilter> filters)4807     private void enforcePrivilegedPermissionIfNeeded(List<ScanFilter> filters) {
4808         if (DBG) {
4809             Log.d(TAG, "enforcePrivilegedPermissionIfNeeded(" + filters + ")");
4810         }
4811         // Some 3p API cases may have null filters, need to allow
4812         if (filters != null) {
4813             for (ScanFilter filter : filters) {
4814                 // The only case to enforce here is if there is an address
4815                 // If there is an address, enforce if the correct combination criteria is met.
4816                 if (filter.getDeviceAddress() != null) {
4817                     // At this point we have an address, that means a caller used the
4818                     // setDeviceAddress(address) public API for the ScanFilter
4819                     // We don't want to enforce if the type is PUBLIC and the IRK is null
4820                     // However, if we have a different type that means the caller used a new
4821                     // @SystemApi such as setDeviceAddress(address, type) or
4822                     // setDeviceAddress(address, type, irk) which are both @SystemApi and require
4823                     // permissions to be enforced
4824                     if (filter.getAddressType()
4825                             == BluetoothDevice.ADDRESS_TYPE_PUBLIC && filter.getIrk() == null) {
4826                         // Do not enforce
4827                     } else {
4828                         enforceBluetoothPrivilegedPermission(this);
4829                     }
4830                 }
4831             }
4832         }
4833     }
4834 
4835     @SuppressLint("AndroidFrameworkRequiresPermission")
enforcePrivilegedPermissionIfNeeded(ScanSettings settings)4836     private void enforcePrivilegedPermissionIfNeeded(ScanSettings settings) {
4837         if (needsPrivilegedPermissionForScan(settings)) {
4838             enforceBluetoothPrivilegedPermission(this);
4839         }
4840     }
4841 
4842     // Enforce caller has UPDATE_DEVICE_STATS permission, which allows the caller to blame other
4843     // apps for Bluetooth usage. A {@link SecurityException} will be thrown if the caller app does
4844     // not have UPDATE_DEVICE_STATS permission.
4845     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
enforceImpersonatationPermission()4846     private void enforceImpersonatationPermission() {
4847         enforceCallingOrSelfPermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
4848                 "Need UPDATE_DEVICE_STATS permission");
4849     }
4850 
4851     @SuppressLint("AndroidFrameworkRequiresPermission")
enforceImpersonatationPermissionIfNeeded(WorkSource workSource)4852     private void enforceImpersonatationPermissionIfNeeded(WorkSource workSource) {
4853         if (workSource != null) {
4854             enforceImpersonatationPermission();
4855         }
4856     }
4857 
4858     /**
4859      * Ensures the report delay is either 0 or at least the floor value (5000ms)
4860      *
4861      * @param  settings are the scan settings passed into a request to start le scanning
4862      * @return the passed in ScanSettings object if the report delay is 0 or above the floor value;
4863      *         a new ScanSettings object with the report delay being the floor value if the original
4864      *         report delay was between 0 and the floor value (exclusive of both)
4865      */
4866     @VisibleForTesting
enforceReportDelayFloor(ScanSettings settings)4867     ScanSettings enforceReportDelayFloor(ScanSettings settings) {
4868         if (settings.getReportDelayMillis() == 0) {
4869             return settings;
4870         }
4871 
4872         // Need to clear identity to pass device config permission check
4873         final long callerToken = Binder.clearCallingIdentity();
4874         try {
4875             long floor = DeviceConfig.getLong(DeviceConfig.NAMESPACE_BLUETOOTH, "report_delay",
4876                 DEFAULT_REPORT_DELAY_FLOOR);
4877 
4878             if (settings.getReportDelayMillis() > floor) {
4879                 return settings;
4880             } else {
4881                 return new ScanSettings.Builder()
4882                         .setCallbackType(settings.getCallbackType())
4883                         .setLegacy(settings.getLegacy())
4884                         .setMatchMode(settings.getMatchMode())
4885                         .setNumOfMatches(settings.getNumOfMatches())
4886                         .setPhy(settings.getPhy())
4887                         .setReportDelay(floor)
4888                         .setScanMode(settings.getScanMode())
4889                         .setScanResultType(settings.getScanResultType())
4890                         .build();
4891             }
4892         } finally {
4893             Binder.restoreCallingIdentity(callerToken);
4894         }
4895     }
4896 
stopNextService(int serverIf, int status)4897     private void stopNextService(int serverIf, int status) throws RemoteException {
4898         if (DBG) {
4899             Log.d(TAG, "stopNextService() - serverIf=" + serverIf + ", status=" + status);
4900         }
4901 
4902         if (status == 0) {
4903             List<HandleMap.Entry> entries = mHandleMap.getEntries();
4904             for (HandleMap.Entry entry : entries) {
4905                 if (entry.type != HandleMap.TYPE_SERVICE || entry.serverIf != serverIf
4906                         || !entry.started) {
4907                     continue;
4908                 }
4909 
4910                 mNativeInterface.gattServerStopService(serverIf, entry.handle);
4911                 return;
4912             }
4913         }
4914     }
4915 
deleteServices(int serverIf)4916     private void deleteServices(int serverIf) {
4917         if (DBG) {
4918             Log.d(TAG, "deleteServices() - serverIf=" + serverIf);
4919         }
4920 
4921         /*
4922          * Figure out which handles to delete.
4923          * The handles are copied into a new list to avoid race conditions.
4924          */
4925         List<Integer> handleList = new ArrayList<Integer>();
4926         List<HandleMap.Entry> entries = mHandleMap.getEntries();
4927         for (HandleMap.Entry entry : entries) {
4928             if (entry.type != HandleMap.TYPE_SERVICE || entry.serverIf != serverIf) {
4929                 continue;
4930             }
4931             handleList.add(entry.handle);
4932         }
4933 
4934         /* Now actually delete the services.... */
4935         for (Integer handle : handleList) {
4936             mNativeInterface.gattServerDeleteService(serverIf, handle);
4937         }
4938     }
4939 
dumpRegisterId(StringBuilder sb)4940     void dumpRegisterId(StringBuilder sb) {
4941         sb.append("  Scanner:\n");
4942         for (Integer appId : mScannerMap.getAllAppsIds()) {
4943             println(sb, "    app_if: " + appId + ", appName: " + mScannerMap.getById(appId).name);
4944         }
4945         sb.append("  Client:\n");
4946         for (Integer appId : mClientMap.getAllAppsIds()) {
4947             println(sb, "    app_if: " + appId + ", appName: " + mClientMap.getById(appId).name);
4948         }
4949         sb.append("  Server:\n");
4950         for (Integer appId : mServerMap.getAllAppsIds()) {
4951             println(sb, "    app_if: " + appId + ", appName: " + mServerMap.getById(appId).name);
4952         }
4953         sb.append("\n\n");
4954     }
4955 
4956     @Override
dump(StringBuilder sb)4957     public void dump(StringBuilder sb) {
4958         super.dump(sb);
4959         println(sb, "mAdvertisingServiceUuids:");
4960         for (UUID uuid : mAdvertisingServiceUuids) {
4961             println(sb, "  " + uuid);
4962         }
4963 
4964         println(sb, "mMaxScanFilters: " + mMaxScanFilters);
4965 
4966         sb.append("\nRegistered App\n");
4967         dumpRegisterId(sb);
4968 
4969         sb.append("GATT Scanner Map\n");
4970         mScannerMap.dump(sb);
4971 
4972         sb.append("GATT Advertiser Map\n");
4973         mAdvertiserMap.dumpAdvertiser(sb);
4974 
4975         sb.append("GATT Client Map\n");
4976         mClientMap.dump(sb);
4977 
4978         sb.append("GATT Server Map\n");
4979         mServerMap.dump(sb);
4980 
4981         sb.append("GATT Handle Map\n");
4982         mHandleMap.dump(sb);
4983     }
4984 
addScanEvent(BluetoothMetricsProto.ScanEvent event)4985     void addScanEvent(BluetoothMetricsProto.ScanEvent event) {
4986         synchronized (mScanEvents) {
4987             if (mScanEvents.size() == NUM_SCAN_EVENTS_KEPT) {
4988                 mScanEvents.remove();
4989             }
4990             mScanEvents.add(event);
4991         }
4992     }
4993 
statsLogAppPackage(String address, int applicationUid, int sessionIndex)4994     private void statsLogAppPackage(String address, int applicationUid, int sessionIndex) {
4995         BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
4996         BluetoothStatsLog.write(
4997                 BluetoothStatsLog.BLUETOOTH_GATT_APP_INFO,
4998                 sessionIndex, mAdapterService.getMetricId(device), applicationUid);
4999         if (DBG) {
5000             Log.d(TAG, "Gatt Logging: metric_id=" + mAdapterService.getMetricId(device)
5001                     + ", app_uid=" + applicationUid);
5002         }
5003     }
5004 
statsLogGattConnectionStateChange( int profile, String address, int sessionIndex, int connectionState, int connectionStatus)5005     private void statsLogGattConnectionStateChange(
5006             int profile, String address, int sessionIndex, int connectionState,
5007             int connectionStatus) {
5008         BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
5009         BluetoothStatsLog.write(
5010                 BluetoothStatsLog.BLUETOOTH_CONNECTION_STATE_CHANGED, connectionState,
5011                 0 /* deprecated */, profile, new byte[0],
5012                 mAdapterService.getMetricId(device), sessionIndex, connectionStatus);
5013         if (DBG) {
5014             Log.d(TAG, "Gatt Logging: metric_id=" + mAdapterService.getMetricId(device)
5015                     + ", session_index=" + sessionIndex
5016                     + ", connection state=" + connectionState
5017                     + ", connection status=" + connectionStatus);
5018         }
5019     }
5020 
5021     @Override
dumpProto(BluetoothMetricsProto.BluetoothLog.Builder builder)5022     public void dumpProto(BluetoothMetricsProto.BluetoothLog.Builder builder) {
5023         synchronized (mScanEvents) {
5024             builder.addAllScanEvent(mScanEvents);
5025         }
5026     }
5027 
5028     /**************************************************************************
5029      * GATT Test functions
5030      *************************************************************************/
gattTestCommand(int command, UUID uuid1, String bda1, int p1, int p2, int p3, int p4, int p5)5031     void gattTestCommand(int command, UUID uuid1, String bda1, int p1, int p2, int p3, int p4,
5032             int p5) {
5033         if (bda1 == null) {
5034             bda1 = "00:00:00:00:00:00";
5035         }
5036         if (uuid1 != null) {
5037             mNativeInterface.gattTest(command, uuid1.getLeastSignificantBits(),
5038                     uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5);
5039         } else {
5040             mNativeInterface.gattTest(command, 0, 0, bda1, p1, p2, p3, p4, p5);
5041         }
5042     }
5043 }
5044