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