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