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