GattService.java revision d03408c87f740be8d87e706d8f43db6870b2733a
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 17package com.android.bluetooth.gatt; 18 19import android.app.AppOpsManager; 20import android.app.PendingIntent; 21import android.app.Service; 22import android.bluetooth.BluetoothAdapter; 23import android.bluetooth.BluetoothDevice; 24import android.bluetooth.BluetoothGatt; 25import android.bluetooth.BluetoothGattCharacteristic; 26import android.bluetooth.BluetoothGattDescriptor; 27import android.bluetooth.BluetoothGattService; 28import android.bluetooth.BluetoothProfile; 29import android.bluetooth.IBluetoothGatt; 30import android.bluetooth.IBluetoothGattCallback; 31import android.bluetooth.IBluetoothGattServerCallback; 32import android.bluetooth.le.AdvertiseData; 33import android.bluetooth.le.AdvertisingSetParameters; 34import android.bluetooth.le.BluetoothLeScanner; 35import android.bluetooth.le.IAdvertisingSetCallback; 36import android.bluetooth.le.IPeriodicAdvertisingCallback; 37import android.bluetooth.le.IScannerCallback; 38import android.bluetooth.le.PeriodicAdvertisingParameters; 39import android.bluetooth.le.ResultStorageDescriptor; 40import android.bluetooth.le.ScanFilter; 41import android.bluetooth.le.ScanRecord; 42import android.bluetooth.le.ScanResult; 43import android.bluetooth.le.ScanSettings; 44import android.content.Intent; 45import android.os.Binder; 46import android.os.IBinder; 47import android.os.ParcelUuid; 48import android.os.RemoteException; 49import android.os.SystemClock; 50import android.os.WorkSource; 51import android.provider.Settings; 52import android.util.Log; 53 54import com.android.bluetooth.R; 55import com.android.bluetooth.Utils; 56import com.android.bluetooth.btservice.AdapterService; 57import com.android.bluetooth.btservice.BluetoothProto; 58import com.android.bluetooth.btservice.ProfileService; 59import com.android.bluetooth.util.NumberUtils; 60import com.android.internal.annotations.VisibleForTesting; 61 62import java.util.ArrayList; 63import java.util.Arrays; 64import java.util.Collections; 65import java.util.HashMap; 66import java.util.HashSet; 67import java.util.List; 68import java.util.Map; 69import java.util.Set; 70import java.util.UUID; 71import java.util.concurrent.TimeUnit; 72 73import static android.content.pm.PackageManager.PERMISSION_GRANTED; 74/** 75 * Provides Bluetooth Gatt profile, as a service in 76 * the Bluetooth application. 77 * @hide 78 */ 79public class GattService extends ProfileService { 80 private static final boolean DBG = GattServiceConfig.DBG; 81 private static final boolean VDBG = GattServiceConfig.VDBG; 82 private static final String TAG = GattServiceConfig.TAG_PREFIX + "GattService"; 83 84 static final int SCAN_FILTER_ENABLED = 1; 85 static final int SCAN_FILTER_MODIFIED = 2; 86 87 private static final int MAC_ADDRESS_LENGTH = 6; 88 // Batch scan related constants. 89 private static final int TRUNCATED_RESULT_SIZE = 11; 90 private static final int TIME_STAMP_LENGTH = 2; 91 92 // onFoundLost related constants 93 private static final int ADVT_STATE_ONFOUND = 0; 94 private static final int ADVT_STATE_ONLOST = 1; 95 96 private static final int ET_LEGACY_MASK = 0x10; 97 98 private static final UUID[] HID_UUIDS = { 99 UUID.fromString("00002A4A-0000-1000-8000-00805F9B34FB"), 100 UUID.fromString("00002A4B-0000-1000-8000-00805F9B34FB"), 101 UUID.fromString("00002A4C-0000-1000-8000-00805F9B34FB"), 102 UUID.fromString("00002A4D-0000-1000-8000-00805F9B34FB") 103 }; 104 105 private static final UUID[] FIDO_UUIDS = { 106 UUID.fromString("0000FFFD-0000-1000-8000-00805F9B34FB") // U2F 107 }; 108 109 /** 110 * Keep the arguments passed in for the PendingIntent. 111 */ 112 class PendingIntentInfo { 113 PendingIntent intent; 114 ScanSettings settings; 115 List<ScanFilter> filters; 116 WorkSource workSource; 117 String callingPackage; 118 119 @Override 120 public boolean equals(Object other) { 121 if (!(other instanceof PendingIntentInfo)) return false; 122 return intent.equals(((PendingIntentInfo) other).intent); 123 } 124 } 125 126 /** 127 * List of our registered scanners. 128 */ 129 class ScannerMap extends ContextMap<IScannerCallback, PendingIntentInfo> {} 130 ScannerMap mScannerMap = new ScannerMap(); 131 132 /** 133 * List of our registered clients. 134 */ 135 class ClientMap extends ContextMap<IBluetoothGattCallback, Void> {} 136 ClientMap mClientMap = new ClientMap(); 137 138 /** 139 * List of our registered server apps. 140 */ 141 class ServerMap extends ContextMap<IBluetoothGattServerCallback, Void> {} 142 ServerMap mServerMap = new ServerMap(); 143 144 /** 145 * Server handle map. 146 */ 147 HandleMap mHandleMap = new HandleMap(); 148 private List<UUID> mAdvertisingServiceUuids = new ArrayList<UUID>(); 149 150 private int mMaxScanFilters; 151 152 static final int NUM_SCAN_EVENTS_KEPT = 20; 153 /** 154 * Internal list of scan events to use with the proto 155 */ 156 ArrayList<BluetoothProto.ScanEvent> mScanEvents = 157 new ArrayList<BluetoothProto.ScanEvent>(NUM_SCAN_EVENTS_KEPT); 158 159 private Map<Integer, List<BluetoothGattService>> gattClientDatabases = 160 new HashMap<Integer, List<BluetoothGattService>>(); 161 162 private AdvertiseManager mAdvertiseManager; 163 private PeriodicScanManager mPeriodicScanManager; 164 private ScanManager mScanManager; 165 private AppOpsManager mAppOps; 166 167 /** 168 * Reliable write queue 169 */ 170 private Set<String> mReliableQueue = new HashSet<String>(); 171 172 static { 173 classInitNative(); 174 } 175 176 protected String getName() { 177 return TAG; 178 } 179 180 protected IProfileServiceBinder initBinder() { 181 return new BluetoothGattBinder(this); 182 } 183 184 protected boolean start() { 185 if (DBG) Log.d(TAG, "start()"); 186 initializeNative(); 187 mAppOps = getSystemService(AppOpsManager.class); 188 mAdvertiseManager = new AdvertiseManager(this, AdapterService.getAdapterService()); 189 mAdvertiseManager.start(); 190 191 mScanManager = new ScanManager(this); 192 mScanManager.start(); 193 194 mPeriodicScanManager = new PeriodicScanManager(AdapterService.getAdapterService()); 195 mPeriodicScanManager.start(); 196 197 return true; 198 } 199 200 protected boolean stop() { 201 if (DBG) Log.d(TAG, "stop()"); 202 mScannerMap.clear(); 203 mClientMap.clear(); 204 mServerMap.clear(); 205 mHandleMap.clear(); 206 mReliableQueue.clear(); 207 if (mAdvertiseManager != null) mAdvertiseManager.cleanup(); 208 if (mScanManager != null) mScanManager.cleanup(); 209 if (mPeriodicScanManager != null) mPeriodicScanManager.cleanup(); 210 return true; 211 } 212 213 protected boolean cleanup() { 214 if (DBG) Log.d(TAG, "cleanup()"); 215 cleanupNative(); 216 if (mAdvertiseManager != null) mAdvertiseManager.cleanup(); 217 if (mScanManager != null) mScanManager.cleanup(); 218 if (mPeriodicScanManager != null) mPeriodicScanManager.cleanup(); 219 return true; 220 } 221 222 boolean permissionCheck(int connId, int handle) { 223 List<BluetoothGattService> db = gattClientDatabases.get(connId); 224 if (db == null) return true; 225 226 for (BluetoothGattService service : db) { 227 for (BluetoothGattCharacteristic characteristic: service.getCharacteristics()) { 228 if (handle == characteristic.getInstanceId()) { 229 if ((isRestrictedCharUuid(characteristic.getUuid()) || 230 isRestrictedSrvcUuid(service.getUuid())) && 231 (0 != checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED))) 232 return false; 233 else 234 return true; 235 } 236 237 for (BluetoothGattDescriptor descriptor: characteristic.getDescriptors()) { 238 if (handle == descriptor.getInstanceId()) { 239 if ((isRestrictedCharUuid(characteristic.getUuid()) || 240 isRestrictedSrvcUuid(service.getUuid())) && 241 (0 != checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED))) 242 return false; 243 else 244 return true; 245 } 246 } 247 } 248 } 249 250 return true; 251 } 252 253 @Override 254 public int onStartCommand(Intent intent, int flags, int startId) { 255 if (GattDebugUtils.handleDebugAction(this, intent)) { 256 return Service.START_NOT_STICKY; 257 } 258 return super.onStartCommand(intent, flags, startId); 259 } 260 261 /** 262 * DeathReceipient handlers used to unregister applications that 263 * disconnect ungracefully (ie. crash or forced close). 264 */ 265 266 class ScannerDeathRecipient implements IBinder.DeathRecipient { 267 int mScannerId; 268 269 public ScannerDeathRecipient(int scannerId) { 270 mScannerId = scannerId; 271 } 272 273 @Override 274 public void binderDied() { 275 if (DBG) Log.d(TAG, "Binder is dead - unregistering scanner (" + mScannerId + ")!"); 276 277 if (isScanClient(mScannerId)) { 278 ScanClient client = new ScanClient(mScannerId); 279 client.appDied = true; 280 stopScan(client); 281 } 282 } 283 284 private boolean isScanClient(int clientIf) { 285 for (ScanClient client : mScanManager.getRegularScanQueue()) { 286 if (client.scannerId == clientIf) { 287 return true; 288 } 289 } 290 for (ScanClient client : mScanManager.getBatchScanQueue()) { 291 if (client.scannerId == clientIf) { 292 return true; 293 } 294 } 295 return false; 296 } 297 } 298 299 class ServerDeathRecipient implements IBinder.DeathRecipient { 300 int mAppIf; 301 302 public ServerDeathRecipient(int appIf) { 303 mAppIf = appIf; 304 } 305 306 public void binderDied() { 307 if (DBG) Log.d(TAG, "Binder is dead - unregistering server (" + mAppIf + ")!"); 308 unregisterServer(mAppIf); 309 } 310 } 311 312 class ClientDeathRecipient implements IBinder.DeathRecipient { 313 int mAppIf; 314 315 public ClientDeathRecipient(int appIf) { 316 mAppIf = appIf; 317 } 318 319 public void binderDied() { 320 if (DBG) Log.d(TAG, "Binder is dead - unregistering client (" + mAppIf + ")!"); 321 unregisterClient(mAppIf); 322 } 323 } 324 325 /** 326 * Handlers for incoming service calls 327 */ 328 private static class BluetoothGattBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder { 329 private GattService mService; 330 331 public BluetoothGattBinder(GattService svc) { 332 mService = svc; 333 } 334 335 public boolean cleanup() { 336 mService = null; 337 return true; 338 } 339 340 private GattService getService() { 341 if (mService != null && mService.isAvailable()) return mService; 342 Log.e(TAG, "getService() - Service requested, but not available!"); 343 return null; 344 } 345 346 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 347 GattService service = getService(); 348 if (service == null) return new ArrayList<BluetoothDevice>(); 349 return service.getDevicesMatchingConnectionStates(states); 350 } 351 352 public void registerClient(ParcelUuid uuid, IBluetoothGattCallback callback) { 353 GattService service = getService(); 354 if (service == null) return; 355 service.registerClient(uuid.getUuid(), callback); 356 } 357 358 public void unregisterClient(int clientIf) { 359 GattService service = getService(); 360 if (service == null) return; 361 service.unregisterClient(clientIf); 362 } 363 364 public void registerScanner(IScannerCallback callback) { 365 GattService service = getService(); 366 if (service == null) return; 367 service.registerScanner(callback); 368 } 369 370 public void unregisterScanner(int scannerId) { 371 GattService service = getService(); 372 if (service == null) return; 373 service.unregisterScanner(scannerId); 374 } 375 376 @Override 377 public void startScan(int scannerId, ScanSettings settings, 378 List<ScanFilter> filters, WorkSource workSource, List storages, 379 String callingPackage) { 380 GattService service = getService(); 381 if (service == null) return; 382 service.startScan(scannerId, settings, filters, workSource, storages, 383 callingPackage); 384 } 385 386 @Override 387 public void startScanForIntent(PendingIntent intent, ScanSettings settings, 388 List<ScanFilter> filters, String callingPackage) throws RemoteException { 389 GattService service = getService(); 390 if (service == null) return; 391 service.registerPiAndStartScan(intent, settings, filters, callingPackage); 392 } 393 394 @Override 395 public void stopScanForIntent(PendingIntent intent, String callingPackage) 396 throws RemoteException { 397 GattService service = getService(); 398 if (service == null) return; 399 service.stopScan(intent, callingPackage); 400 } 401 402 public void stopScan(int scannerId) { 403 GattService service = getService(); 404 if (service == null) return; 405 service.stopScan(new ScanClient(scannerId)); 406 } 407 408 @Override 409 public void flushPendingBatchResults(int scannerId) { 410 GattService service = getService(); 411 if (service == null) return; 412 service.flushPendingBatchResults(scannerId); 413 } 414 415 @Override 416 public void clientConnect( 417 int clientIf, String address, boolean isDirect, int transport, int phy) { 418 GattService service = getService(); 419 if (service == null) return; 420 service.clientConnect(clientIf, address, isDirect, transport, phy); 421 } 422 423 @Override 424 public void clientDisconnect(int clientIf, String address) { 425 GattService service = getService(); 426 if (service == null) return; 427 service.clientDisconnect(clientIf, address); 428 } 429 430 @Override 431 public void clientSetPreferredPhy( 432 int clientIf, String address, int txPhy, int rxPhy, int phyOptions) { 433 GattService service = getService(); 434 if (service == null) return; 435 service.clientSetPreferredPhy(clientIf, address, txPhy, rxPhy, phyOptions); 436 } 437 438 @Override 439 public void clientReadPhy(int clientIf, String address) { 440 GattService service = getService(); 441 if (service == null) return; 442 service.clientReadPhy(clientIf, address); 443 } 444 445 public void refreshDevice(int clientIf, String address) { 446 GattService service = getService(); 447 if (service == null) return; 448 service.refreshDevice(clientIf, address); 449 } 450 451 public void discoverServices(int clientIf, String address) { 452 GattService service = getService(); 453 if (service == null) return; 454 service.discoverServices(clientIf, address); 455 } 456 457 public void readCharacteristic(int clientIf, String address, int handle, int authReq) { 458 GattService service = getService(); 459 if (service == null) return; 460 service.readCharacteristic(clientIf, address, handle, authReq); 461 } 462 463 public void writeCharacteristic(int clientIf, String address, int handle, 464 int writeType, int authReq, byte[] value) { 465 GattService service = getService(); 466 if (service == null) return; 467 service.writeCharacteristic(clientIf, address, handle, writeType, authReq, value); 468 } 469 470 public void readDescriptor(int clientIf, String address, int handle, int authReq) { 471 GattService service = getService(); 472 if (service == null) return; 473 service.readDescriptor(clientIf, address, handle, authReq); 474 } 475 476 public void writeDescriptor(int clientIf, String address, int handle, 477 int authReq, byte[] value) { 478 GattService service = getService(); 479 if (service == null) return; 480 service.writeDescriptor(clientIf, address, handle, authReq, value); 481 } 482 483 public void beginReliableWrite(int clientIf, String address) { 484 GattService service = getService(); 485 if (service == null) return; 486 service.beginReliableWrite(clientIf, address); 487 } 488 489 public void endReliableWrite(int clientIf, String address, boolean execute) { 490 GattService service = getService(); 491 if (service == null) return; 492 service.endReliableWrite(clientIf, address, execute); 493 } 494 495 public void registerForNotification(int clientIf, String address, int handle, boolean enable) { 496 GattService service = getService(); 497 if (service == null) return; 498 service.registerForNotification(clientIf, address, handle, enable); 499 } 500 501 public void readRemoteRssi(int clientIf, String address) { 502 GattService service = getService(); 503 if (service == null) return; 504 service.readRemoteRssi(clientIf, address); 505 } 506 507 public void configureMTU(int clientIf, String address, int mtu) { 508 GattService service = getService(); 509 if (service == null) return; 510 service.configureMTU(clientIf, address, mtu); 511 } 512 513 public void connectionParameterUpdate(int clientIf, String address, 514 int connectionPriority) { 515 GattService service = getService(); 516 if (service == null) return; 517 service.connectionParameterUpdate(clientIf, address, connectionPriority); 518 } 519 520 public void registerServer(ParcelUuid uuid, IBluetoothGattServerCallback callback) { 521 GattService service = getService(); 522 if (service == null) return; 523 service.registerServer(uuid.getUuid(), callback); 524 } 525 526 public void unregisterServer(int serverIf) { 527 GattService service = getService(); 528 if (service == null) return; 529 service.unregisterServer(serverIf); 530 } 531 532 public void serverConnect(int serverIf, String address, boolean isDirect, int transport) { 533 GattService service = getService(); 534 if (service == null) return; 535 service.serverConnect(serverIf, address, isDirect, transport); 536 } 537 538 public void serverDisconnect(int serverIf, String address) { 539 GattService service = getService(); 540 if (service == null) return; 541 service.serverDisconnect(serverIf, address); 542 } 543 544 public void serverSetPreferredPhy( 545 int serverIf, String address, int txPhy, int rxPhy, int phyOptions) { 546 GattService service = getService(); 547 if (service == null) return; 548 service.serverSetPreferredPhy(serverIf, address, txPhy, rxPhy, phyOptions); 549 } 550 551 public void serverReadPhy(int clientIf, String address) { 552 GattService service = getService(); 553 if (service == null) return; 554 service.serverReadPhy(clientIf, address); 555 } 556 557 public void addService(int serverIf, BluetoothGattService svc) { 558 GattService service = getService(); 559 if (service == null) return; 560 561 service.addService(serverIf, svc); 562 } 563 564 public void removeService(int serverIf, int handle) { 565 GattService service = getService(); 566 if (service == null) return; 567 service.removeService(serverIf, handle); 568 } 569 570 public void clearServices(int serverIf) { 571 GattService service = getService(); 572 if (service == null) return; 573 service.clearServices(serverIf); 574 } 575 576 public void sendResponse(int serverIf, String address, int requestId, 577 int status, int offset, byte[] value) { 578 GattService service = getService(); 579 if (service == null) return; 580 service.sendResponse(serverIf, address, requestId, status, offset, value); 581 } 582 583 public void sendNotification(int serverIf, String address, int handle, 584 boolean confirm, byte[] value) { 585 GattService service = getService(); 586 if (service == null) return; 587 service.sendNotification(serverIf, address, handle, confirm, value); 588 } 589 590 public void startAdvertisingSet(AdvertisingSetParameters parameters, 591 AdvertiseData advertiseData, AdvertiseData scanResponse, 592 PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData, 593 int duration, int maxExtAdvEvents, IAdvertisingSetCallback callback) { 594 GattService service = getService(); 595 if (service == null) return; 596 service.startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, 597 periodicData, duration, maxExtAdvEvents, callback); 598 } 599 600 public void stopAdvertisingSet(IAdvertisingSetCallback callback) { 601 GattService service = getService(); 602 if (service == null) return; 603 service.stopAdvertisingSet(callback); 604 } 605 606 public void enableAdvertisingSet( 607 int advertiserId, boolean enable, int duration, int maxExtAdvEvents) { 608 GattService service = getService(); 609 if (service == null) return; 610 service.enableAdvertisingSet(advertiserId, enable, duration, maxExtAdvEvents); 611 } 612 613 public void setAdvertisingData(int advertiserId, AdvertiseData data) { 614 GattService service = getService(); 615 if (service == null) return; 616 service.setAdvertisingData(advertiserId, data); 617 } 618 619 public void setScanResponseData(int advertiserId, AdvertiseData data) { 620 GattService service = getService(); 621 if (service == null) return; 622 service.setScanResponseData(advertiserId, data); 623 } 624 625 public void setAdvertisingParameters( 626 int advertiserId, AdvertisingSetParameters parameters) { 627 GattService service = getService(); 628 if (service == null) return; 629 service.setAdvertisingParameters(advertiserId, parameters); 630 } 631 632 public void setPeriodicAdvertisingParameters( 633 int advertiserId, PeriodicAdvertisingParameters parameters) { 634 GattService service = getService(); 635 if (service == null) return; 636 service.setPeriodicAdvertisingParameters(advertiserId, parameters); 637 } 638 639 public void setPeriodicAdvertisingData(int advertiserId, AdvertiseData data) { 640 GattService service = getService(); 641 if (service == null) return; 642 service.setPeriodicAdvertisingData(advertiserId, data); 643 } 644 645 public void setPeriodicAdvertisingEnable(int advertiserId, boolean enable) { 646 GattService service = getService(); 647 if (service == null) return; 648 service.setPeriodicAdvertisingEnable(advertiserId, enable); 649 } 650 651 @Override 652 public void registerSync(ScanResult scanResult, int skip, int timeout, 653 IPeriodicAdvertisingCallback callback) { 654 GattService service = getService(); 655 if (service == null) return; 656 service.registerSync(scanResult, skip, timeout, callback); 657 } 658 659 @Override 660 public void unregisterSync(IPeriodicAdvertisingCallback callback) { 661 GattService service = getService(); 662 if (service == null) return; 663 service.unregisterSync(callback); 664 } 665 666 @Override 667 public void disconnectAll() { 668 GattService service = getService(); 669 if (service == null) return; 670 service.disconnectAll(); 671 } 672 673 @Override 674 public void unregAll() { 675 GattService service = getService(); 676 if (service == null) return; 677 service.unregAll(); 678 } 679 680 @Override 681 public int numHwTrackFiltersAvailable() { 682 GattService service = getService(); 683 if (service == null) return 0; 684 return service.numHwTrackFiltersAvailable(); 685 } 686 }; 687 688 /************************************************************************** 689 * Callback functions - CLIENT 690 *************************************************************************/ 691 692 void onScanResult(int event_type, int address_type, String address, int primary_phy, 693 int secondary_phy, int advertising_sid, int tx_power, int rssi, int periodic_adv_int, 694 byte[] adv_data) { 695 if (VDBG) 696 Log.d(TAG, "onScanResult() - event_type=0x" + Integer.toHexString(event_type) 697 + ", address_type=" + address_type + ", address=" + address 698 + ", primary_phy=" + primary_phy + ", secondary_phy=" + secondary_phy 699 + ", advertising_sid=0x" + Integer.toHexString(advertising_sid) 700 + ", tx_power=" + tx_power + ", rssi=" + rssi + ", periodic_adv_int=0x" 701 + Integer.toHexString(periodic_adv_int)); 702 List<UUID> remoteUuids = parseUuids(adv_data); 703 addScanResult(); 704 705 byte[] legacy_adv_data = Arrays.copyOfRange(adv_data, 0, 62); 706 707 for (ScanClient client : mScanManager.getRegularScanQueue()) { 708 if (client.uuids.length > 0) { 709 int matches = 0; 710 for (UUID search : client.uuids) { 711 for (UUID remote: remoteUuids) { 712 if (remote.equals(search)) { 713 ++matches; 714 break; // Only count 1st match in case of duplicates 715 } 716 } 717 } 718 719 if (matches < client.uuids.length) continue; 720 } 721 722 ScannerMap.App app = mScannerMap.getById(client.scannerId); 723 if (app == null) { 724 continue; 725 } 726 727 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 728 729 ScanSettings settings = client.settings; 730 byte[] scan_record_data; 731 // This is for compability with applications that assume fixed size scan data. 732 if (settings.getLegacy()) { 733 if ((event_type & ET_LEGACY_MASK) == 0) { 734 // If this is legacy scan, but nonlegacy result - skip. 735 continue; 736 } else { 737 // Some apps are used to fixed-size advertise data. 738 scan_record_data = legacy_adv_data; 739 } 740 } else { 741 scan_record_data = adv_data; 742 } 743 744 ScanResult result = new ScanResult(device, event_type, primary_phy, secondary_phy, 745 advertising_sid, tx_power, rssi, periodic_adv_int, 746 ScanRecord.parseFromBytes(scan_record_data), 747 SystemClock.elapsedRealtimeNanos()); 748 // Do no report if location mode is OFF or the client has no location permission 749 // PEERS_MAC_ADDRESS permission holders always get results 750 if (!hasScanResultPermission(client) || !matchesFilters(client, result)) { 751 continue; 752 } 753 754 if ((settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_ALL_MATCHES) == 0) { 755 continue; 756 } 757 758 try { 759 app.appScanStats.addResult(); 760 if (app.callback != null) { 761 app.callback.onScanResult(result); 762 } else { 763 // Send the PendingIntent 764 ArrayList<ScanResult> results = new ArrayList<>(); 765 results.add(result); 766 sendResultsByPendingIntent(app.info, results, 767 ScanSettings.CALLBACK_TYPE_ALL_MATCHES); 768 } 769 } catch (RemoteException | PendingIntent.CanceledException e) { 770 Log.e(TAG, "Exception: " + e); 771 mScannerMap.remove(client.scannerId); 772 mScanManager.stopScan(client); 773 } 774 } 775 } 776 777 private void sendResultByPendingIntent(PendingIntentInfo pii, ScanResult result, 778 int callbackType, ScanClient client) { 779 ArrayList<ScanResult> results = new ArrayList<>(); 780 results.add(result); 781 try { 782 sendResultsByPendingIntent(pii, results, callbackType); 783 } catch (PendingIntent.CanceledException e) { 784 stopScan(client); 785 unregisterScanner(client.scannerId); 786 } 787 } 788 789 private void sendResultsByPendingIntent(PendingIntentInfo pii, ArrayList<ScanResult> results, 790 int callbackType) throws PendingIntent.CanceledException { 791 Intent extrasIntent = new Intent(); 792 extrasIntent.putParcelableArrayListExtra( 793 BluetoothLeScanner.EXTRA_LIST_SCAN_RESULT, results); 794 extrasIntent.putExtra( 795 BluetoothLeScanner.EXTRA_CALLBACK_TYPE, callbackType); 796 pii.intent.send(this, 0, extrasIntent); 797 } 798 799 private void sendErrorByPendingIntent(PendingIntentInfo pii, int errorCode) 800 throws PendingIntent.CanceledException { 801 Intent extrasIntent = new Intent(); 802 extrasIntent.putExtra(BluetoothLeScanner.EXTRA_ERROR_CODE, errorCode); 803 pii.intent.send(this, 0, extrasIntent); 804 } 805 806 void onScannerRegistered(int status, int scannerId, long uuidLsb, long uuidMsb) 807 throws RemoteException { 808 UUID uuid = new UUID(uuidMsb, uuidLsb); 809 if (DBG) Log.d(TAG, "onScannerRegistered() - UUID=" + uuid 810 + ", scannerId=" + scannerId + ", status=" + status); 811 812 // First check the callback map 813 ScannerMap.App cbApp = mScannerMap.getByUuid(uuid); 814 if (cbApp != null) { 815 if (status == 0) { 816 cbApp.id = scannerId; 817 // If app is callback based, setup a death recipient. App will initiate the start. 818 // Otherwise, if PendingIntent based, start the scan directly. 819 if (cbApp.callback != null) { 820 cbApp.linkToDeath(new ScannerDeathRecipient(scannerId)); 821 } else { 822 continuePiStartScan(scannerId, cbApp.info); 823 } 824 } else { 825 mScannerMap.remove(scannerId); 826 } 827 if (cbApp.callback != null) { 828 cbApp.callback.onScannerRegistered(status, scannerId); 829 } 830 } 831 } 832 833 /** Determines if the given scan client has the appropriate permissions to receive callbacks. */ 834 private boolean hasScanResultPermission(final ScanClient client) { 835 final boolean requiresLocationEnabled = 836 getResources().getBoolean(R.bool.strict_location_check); 837 final boolean locationEnabledSetting = Settings.Secure.getInt(getContentResolver(), 838 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) 839 != Settings.Secure.LOCATION_MODE_OFF; 840 final boolean locationEnabled = !requiresLocationEnabled || locationEnabledSetting 841 || client.legacyForegroundApp; 842 return (client.hasPeersMacAddressPermission 843 || (client.hasLocationPermission && locationEnabled)); 844 } 845 846 // Check if a scan record matches a specific filters. 847 private boolean matchesFilters(ScanClient client, ScanResult scanResult) { 848 if (client.filters == null || client.filters.isEmpty()) { 849 return true; 850 } 851 for (ScanFilter filter : client.filters) { 852 if (filter.matches(scanResult)) { 853 return true; 854 } 855 } 856 return false; 857 } 858 859 void onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb) 860 throws RemoteException { 861 UUID uuid = new UUID(uuidMsb, uuidLsb); 862 if (DBG) Log.d(TAG, "onClientRegistered() - UUID=" + uuid + ", clientIf=" + clientIf); 863 ClientMap.App app = mClientMap.getByUuid(uuid); 864 if (app != null) { 865 if (status == 0) { 866 app.id = clientIf; 867 app.linkToDeath(new ClientDeathRecipient(clientIf)); 868 } else { 869 mClientMap.remove(uuid); 870 } 871 app.callback.onClientRegistered(status, clientIf); 872 } 873 } 874 875 void onConnected(int clientIf, int connId, int status, String address) 876 throws RemoteException { 877 if (DBG) Log.d(TAG, "onConnected() - clientIf=" + clientIf 878 + ", connId=" + connId + ", address=" + address); 879 880 if (status == 0) mClientMap.addConnection(clientIf, connId, address); 881 ClientMap.App app = mClientMap.getById(clientIf); 882 if (app != null) { 883 app.callback.onClientConnectionState(status, clientIf, 884 (status==BluetoothGatt.GATT_SUCCESS), address); 885 } 886 } 887 888 void onDisconnected(int clientIf, int connId, int status, String address) 889 throws RemoteException { 890 if (DBG) Log.d(TAG, "onDisconnected() - clientIf=" + clientIf 891 + ", connId=" + connId + ", address=" + address); 892 893 mClientMap.removeConnection(clientIf, connId); 894 ClientMap.App app = mClientMap.getById(clientIf); 895 if (app != null) { 896 app.callback.onClientConnectionState(status, clientIf, false, address); 897 } 898 } 899 900 void onClientPhyUpdate(int connId, int txPhy, int rxPhy, int status) throws RemoteException { 901 if (DBG) Log.d(TAG, "onClientPhyUpdate() - connId=" + connId + ", status=" + status); 902 903 String address = mClientMap.addressByConnId(connId); 904 if (address == null) return; 905 906 ClientMap.App app = mClientMap.getByConnId(connId); 907 if (app == null) return; 908 909 app.callback.onPhyUpdate(address, txPhy, rxPhy, status); 910 } 911 912 void onClientPhyRead(int connId, int txPhy, int rxPhy, int status) throws RemoteException { 913 if (DBG) Log.d(TAG, "onClientPhyRead() - connId=" + connId + ", status=" + status); 914 915 String address = mClientMap.addressByConnId(connId); 916 if (address == null) return; 917 918 ClientMap.App app = mClientMap.getByConnId(connId); 919 if (app == null) return; 920 921 app.callback.onPhyRead(address, txPhy, rxPhy, status); 922 } 923 924 void onClientConnUpdate(int connId, int interval, int latency, int timeout, int status) 925 throws RemoteException { 926 if (DBG) Log.d(TAG, "onClientConnUpdate() - connId=" + connId + ", status=" + status); 927 928 String address = mClientMap.addressByConnId(connId); 929 if (address == null) return; 930 931 ClientMap.App app = mClientMap.getByConnId(connId); 932 if (app == null) return; 933 934 app.callback.onConnectionUpdated(address, interval, latency, timeout, status); 935 } 936 937 void onServerPhyUpdate(int connId, int txPhy, int rxPhy, int status) throws RemoteException { 938 if (DBG) Log.d(TAG, "onServerPhyUpdate() - connId=" + connId + ", status=" + status); 939 940 String address = mServerMap.addressByConnId(connId); 941 if (address == null) return; 942 943 ServerMap.App app = mServerMap.getByConnId(connId); 944 if (app == null) return; 945 946 app.callback.onPhyUpdate(address, txPhy, rxPhy, status); 947 } 948 949 void onServerPhyRead(int connId, int txPhy, int rxPhy, int status) throws RemoteException { 950 if (DBG) Log.d(TAG, "onServerPhyRead() - connId=" + connId + ", status=" + status); 951 952 String address = mServerMap.addressByConnId(connId); 953 if (address == null) return; 954 955 ServerMap.App app = mServerMap.getByConnId(connId); 956 if (app == null) return; 957 958 app.callback.onPhyRead(address, txPhy, rxPhy, status); 959 } 960 961 void onServerConnUpdate(int connId, int interval, int latency, int timeout, int status) 962 throws RemoteException { 963 if (DBG) Log.d(TAG, "onServerConnUpdate() - connId=" + connId + ", status=" + status); 964 965 String address = mServerMap.addressByConnId(connId); 966 if (address == null) return; 967 968 ServerMap.App app = mServerMap.getByConnId(connId); 969 if (app == null) return; 970 971 app.callback.onConnectionUpdated(address, interval, latency, timeout, status); 972 } 973 974 void onSearchCompleted(int connId, int status) throws RemoteException { 975 if (DBG) Log.d(TAG, "onSearchCompleted() - connId=" + connId+ ", status=" + status); 976 // Gatt DB is ready! 977 978 // This callback was called from the jni_workqueue thread. If we make request to the stack 979 // on the same thread, it might cause deadlock. Schedule request on a new thread instead. 980 Thread t = new Thread(new Runnable() { 981 public void run() { 982 gattClientGetGattDbNative(connId); 983 } 984 }); 985 t.start(); 986 } 987 988 GattDbElement GetSampleGattDbElement() { 989 return new GattDbElement(); 990 } 991 992 void onGetGattDb(int connId, ArrayList<GattDbElement> db) throws RemoteException { 993 String address = mClientMap.addressByConnId(connId); 994 995 if (DBG) Log.d(TAG, "onGetGattDb() - address=" + address); 996 997 ClientMap.App app = mClientMap.getByConnId(connId); 998 if (app == null || app.callback == null) { 999 Log.e(TAG, "app or callback is null"); 1000 return; 1001 } 1002 1003 List<BluetoothGattService> db_out = new ArrayList<BluetoothGattService>(); 1004 1005 BluetoothGattService currSrvc = null; 1006 BluetoothGattCharacteristic currChar = null; 1007 1008 for (GattDbElement el: db) { 1009 switch (el.type) 1010 { 1011 case GattDbElement.TYPE_PRIMARY_SERVICE: 1012 case GattDbElement.TYPE_SECONDARY_SERVICE: 1013 if (DBG) Log.d(TAG, "got service with UUID=" + el.uuid); 1014 1015 currSrvc = new BluetoothGattService(el.uuid, el.id, el.type); 1016 db_out.add(currSrvc); 1017 break; 1018 1019 case GattDbElement.TYPE_CHARACTERISTIC: 1020 if (DBG) Log.d(TAG, "got characteristic with UUID=" + el.uuid); 1021 1022 currChar = new BluetoothGattCharacteristic(el.uuid, el.id, el.properties, 0); 1023 currSrvc.addCharacteristic(currChar); 1024 break; 1025 1026 case GattDbElement.TYPE_DESCRIPTOR: 1027 if (DBG) Log.d(TAG, "got descriptor with UUID=" + el.uuid); 1028 1029 currChar.addDescriptor(new BluetoothGattDescriptor(el.uuid, el.id, 0)); 1030 break; 1031 1032 case GattDbElement.TYPE_INCLUDED_SERVICE: 1033 if (DBG) Log.d(TAG, "got included service with UUID=" + el.uuid); 1034 1035 currSrvc.addIncludedService(new BluetoothGattService(el.uuid, el.id, el.type)); 1036 break; 1037 1038 default: 1039 Log.e(TAG, "got unknown element with type=" + el.type + " and UUID=" + el.uuid); 1040 } 1041 } 1042 1043 // Search is complete when there was error, or nothing more to process 1044 gattClientDatabases.put(connId, db_out); 1045 app.callback.onSearchComplete(address, db_out, 0 /* status */); 1046 } 1047 1048 void onRegisterForNotifications(int connId, int status, int registered, int handle) { 1049 String address = mClientMap.addressByConnId(connId); 1050 1051 if (DBG) Log.d(TAG, "onRegisterForNotifications() - address=" + address 1052 + ", status=" + status + ", registered=" + registered 1053 + ", handle=" + handle); 1054 } 1055 1056 void onNotify(int connId, String address, int handle, 1057 boolean isNotify, byte[] data) throws RemoteException { 1058 1059 if (VDBG) Log.d(TAG, "onNotify() - address=" + address 1060 + ", handle=" + handle + ", length=" + data.length); 1061 1062 if (!permissionCheck(connId, handle)) { 1063 Log.w(TAG, "onNotify() - permission check failed!"); 1064 return; 1065 } 1066 1067 ClientMap.App app = mClientMap.getByConnId(connId); 1068 if (app != null) { 1069 app.callback.onNotify(address, handle, data); 1070 } 1071 } 1072 1073 void onReadCharacteristic(int connId, int status, int handle, byte[] data) throws RemoteException { 1074 String address = mClientMap.addressByConnId(connId); 1075 1076 if (VDBG) Log.d(TAG, "onReadCharacteristic() - address=" + address 1077 + ", status=" + status + ", length=" + data.length); 1078 1079 ClientMap.App app = mClientMap.getByConnId(connId); 1080 if (app != null) { 1081 app.callback.onCharacteristicRead(address, status, handle, data); 1082 } 1083 } 1084 1085 void onWriteCharacteristic(int connId, int status, int handle) 1086 throws RemoteException { 1087 String address = mClientMap.addressByConnId(connId); 1088 1089 if (VDBG) Log.d(TAG, "onWriteCharacteristic() - address=" + address 1090 + ", status=" + status); 1091 1092 ClientMap.App app = mClientMap.getByConnId(connId); 1093 if (app == null) return; 1094 1095 if (!app.isCongested) { 1096 app.callback.onCharacteristicWrite(address, status, handle); 1097 } else { 1098 if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) { 1099 status = BluetoothGatt.GATT_SUCCESS; 1100 } 1101 CallbackInfo callbackInfo = new CallbackInfo(address, status, handle); 1102 app.queueCallback(callbackInfo); 1103 } 1104 } 1105 1106 void onExecuteCompleted(int connId, int status) throws RemoteException { 1107 String address = mClientMap.addressByConnId(connId); 1108 if (VDBG) Log.d(TAG, "onExecuteCompleted() - address=" + address 1109 + ", status=" + status); 1110 1111 ClientMap.App app = mClientMap.getByConnId(connId); 1112 if (app != null) { 1113 app.callback.onExecuteWrite(address, status); 1114 } 1115 } 1116 1117 void onReadDescriptor(int connId, int status, int handle, byte[] data) throws RemoteException { 1118 String address = mClientMap.addressByConnId(connId); 1119 1120 if (VDBG) Log.d(TAG, "onReadDescriptor() - address=" + address 1121 + ", status=" + status + ", length=" + data.length); 1122 1123 ClientMap.App app = mClientMap.getByConnId(connId); 1124 if (app != null) { 1125 app.callback.onDescriptorRead(address, status, handle, data); 1126 } 1127 } 1128 1129 void onWriteDescriptor(int connId, int status, int handle) throws RemoteException { 1130 String address = mClientMap.addressByConnId(connId); 1131 1132 if (VDBG) Log.d(TAG, "onWriteDescriptor() - address=" + address 1133 + ", status=" + status); 1134 1135 ClientMap.App app = mClientMap.getByConnId(connId); 1136 if (app != null) { 1137 app.callback.onDescriptorWrite(address, status, handle); 1138 } 1139 } 1140 1141 void onReadRemoteRssi(int clientIf, String address, 1142 int rssi, int status) throws RemoteException{ 1143 if (DBG) Log.d(TAG, "onReadRemoteRssi() - clientIf=" + clientIf + " address=" + 1144 address + ", rssi=" + rssi + ", status=" + status); 1145 1146 ClientMap.App app = mClientMap.getById(clientIf); 1147 if (app != null) { 1148 app.callback.onReadRemoteRssi(address, rssi, status); 1149 } 1150 } 1151 1152 void onScanFilterEnableDisabled(int action, int status, int clientIf) { 1153 if (DBG) { 1154 Log.d(TAG, "onScanFilterEnableDisabled() - clientIf=" + clientIf + ", status=" + status 1155 + ", action=" + action); 1156 } 1157 mScanManager.callbackDone(clientIf, status); 1158 } 1159 1160 void onScanFilterParamsConfigured(int action, int status, int clientIf, int availableSpace) { 1161 if (DBG) { 1162 Log.d(TAG, "onScanFilterParamsConfigured() - clientIf=" + clientIf 1163 + ", status=" + status + ", action=" + action 1164 + ", availableSpace=" + availableSpace); 1165 } 1166 mScanManager.callbackDone(clientIf, status); 1167 } 1168 1169 void onScanFilterConfig(int action, int status, int clientIf, int filterType, 1170 int availableSpace) { 1171 if (DBG) { 1172 Log.d(TAG, "onScanFilterConfig() - clientIf=" + clientIf + ", action = " + action 1173 + " status = " + status + ", filterType=" + filterType 1174 + ", availableSpace=" + availableSpace); 1175 } 1176 1177 mScanManager.callbackDone(clientIf, status); 1178 } 1179 1180 void onBatchScanStorageConfigured(int status, int clientIf) { 1181 if (DBG) { 1182 Log.d(TAG, "onBatchScanStorageConfigured() - clientIf="+ clientIf + ", status=" + status); 1183 } 1184 mScanManager.callbackDone(clientIf, status); 1185 } 1186 1187 // TODO: split into two different callbacks : onBatchScanStarted and onBatchScanStopped. 1188 void onBatchScanStartStopped(int startStopAction, int status, int clientIf) { 1189 if (DBG) { 1190 Log.d(TAG, "onBatchScanStartStopped() - clientIf=" + clientIf 1191 + ", status=" + status + ", startStopAction=" + startStopAction); 1192 } 1193 mScanManager.callbackDone(clientIf, status); 1194 } 1195 1196 void onBatchScanReports(int status, int scannerId, int reportType, int numRecords, 1197 byte[] recordData) throws RemoteException { 1198 if (DBG) { 1199 Log.d(TAG, "onBatchScanReports() - scannerId=" + scannerId + ", status=" + status 1200 + ", reportType=" + reportType + ", numRecords=" + numRecords); 1201 } 1202 mScanManager.callbackDone(scannerId, status); 1203 Set<ScanResult> results = parseBatchScanResults(numRecords, reportType, recordData); 1204 if (reportType == ScanManager.SCAN_RESULT_TYPE_TRUNCATED) { 1205 // We only support single client for truncated mode. 1206 ScannerMap.App app = mScannerMap.getById(scannerId); 1207 if (app == null) return; 1208 if (app.callback != null) { 1209 app.callback.onBatchScanResults(new ArrayList<ScanResult>(results)); 1210 } else { 1211 // PendingIntent based 1212 try { 1213 sendResultsByPendingIntent(app.info, new ArrayList<ScanResult>(results), 1214 ScanSettings.CALLBACK_TYPE_ALL_MATCHES); 1215 } catch (PendingIntent.CanceledException e) { 1216 } 1217 } 1218 } else { 1219 for (ScanClient client : mScanManager.getFullBatchScanQueue()) { 1220 // Deliver results for each client. 1221 deliverBatchScan(client, results); 1222 } 1223 } 1224 } 1225 1226 private void sendBatchScanResults( 1227 ScannerMap.App app, ScanClient client, ArrayList<ScanResult> results) { 1228 try { 1229 if (app.callback != null) { 1230 app.callback.onBatchScanResults(results); 1231 } else { 1232 sendResultsByPendingIntent(app.info, results, 1233 ScanSettings.CALLBACK_TYPE_ALL_MATCHES); 1234 } 1235 } catch (RemoteException | PendingIntent.CanceledException e) { 1236 Log.e(TAG, "Exception: " + e); 1237 mScannerMap.remove(client.scannerId); 1238 mScanManager.stopScan(client); 1239 } 1240 } 1241 1242 // Check and deliver scan results for different scan clients. 1243 private void deliverBatchScan(ScanClient client, Set<ScanResult> allResults) throws 1244 RemoteException { 1245 ScannerMap.App app = mScannerMap.getById(client.scannerId); 1246 if (app == null) return; 1247 if (client.filters == null || client.filters.isEmpty()) { 1248 sendBatchScanResults(app, client, new ArrayList<ScanResult>(allResults)); 1249 // TODO: Question to reviewer: Shouldn't there be a return here? 1250 } 1251 // Reconstruct the scan results. 1252 ArrayList<ScanResult> results = new ArrayList<ScanResult>(); 1253 for (ScanResult scanResult : allResults) { 1254 if (matchesFilters(client, scanResult)) { 1255 results.add(scanResult); 1256 } 1257 } 1258 sendBatchScanResults(app, client, results); 1259 } 1260 1261 private Set<ScanResult> parseBatchScanResults(int numRecords, int reportType, 1262 byte[] batchRecord) { 1263 if (numRecords == 0) { 1264 return Collections.emptySet(); 1265 } 1266 if (DBG) Log.d(TAG, "current time is " + SystemClock.elapsedRealtimeNanos()); 1267 if (reportType == ScanManager.SCAN_RESULT_TYPE_TRUNCATED) { 1268 return parseTruncatedResults(numRecords, batchRecord); 1269 } else { 1270 return parseFullResults(numRecords, batchRecord); 1271 } 1272 } 1273 1274 private Set<ScanResult> parseTruncatedResults(int numRecords, byte[] batchRecord) { 1275 if (DBG) Log.d(TAG, "batch record " + Arrays.toString(batchRecord)); 1276 Set<ScanResult> results = new HashSet<ScanResult>(numRecords); 1277 long now = SystemClock.elapsedRealtimeNanos(); 1278 for (int i = 0; i < numRecords; ++i) { 1279 byte[] record = extractBytes(batchRecord, i * TRUNCATED_RESULT_SIZE, 1280 TRUNCATED_RESULT_SIZE); 1281 byte[] address = extractBytes(record, 0, 6); 1282 reverse(address); 1283 BluetoothDevice device = mAdapter.getRemoteDevice(address); 1284 int rssi = record[8]; 1285 long timestampNanos = now - parseTimestampNanos(extractBytes(record, 9, 2)); 1286 results.add(new ScanResult(device, ScanRecord.parseFromBytes(new byte[0]), 1287 rssi, timestampNanos)); 1288 } 1289 return results; 1290 } 1291 1292 @VisibleForTesting 1293 long parseTimestampNanos(byte[] data) { 1294 long timestampUnit = NumberUtils.littleEndianByteArrayToInt(data); 1295 // Timestamp is in every 50 ms. 1296 return TimeUnit.MILLISECONDS.toNanos(timestampUnit * 50); 1297 } 1298 1299 private Set<ScanResult> parseFullResults(int numRecords, byte[] batchRecord) { 1300 Log.d(TAG, "Batch record : " + Arrays.toString(batchRecord)); 1301 Set<ScanResult> results = new HashSet<ScanResult>(numRecords); 1302 int position = 0; 1303 long now = SystemClock.elapsedRealtimeNanos(); 1304 while (position < batchRecord.length) { 1305 byte[] address = extractBytes(batchRecord, position, 6); 1306 // TODO: remove temp hack. 1307 reverse(address); 1308 BluetoothDevice device = mAdapter.getRemoteDevice(address); 1309 position += 6; 1310 // Skip address type. 1311 position++; 1312 // Skip tx power level. 1313 position++; 1314 int rssi = batchRecord[position++]; 1315 long timestampNanos = now - parseTimestampNanos(extractBytes(batchRecord, position, 2)); 1316 position += 2; 1317 1318 // Combine advertise packet and scan response packet. 1319 int advertisePacketLen = batchRecord[position++]; 1320 byte[] advertiseBytes = extractBytes(batchRecord, position, advertisePacketLen); 1321 position += advertisePacketLen; 1322 int scanResponsePacketLen = batchRecord[position++]; 1323 byte[] scanResponseBytes = extractBytes(batchRecord, position, scanResponsePacketLen); 1324 position += scanResponsePacketLen; 1325 byte[] scanRecord = new byte[advertisePacketLen + scanResponsePacketLen]; 1326 System.arraycopy(advertiseBytes, 0, scanRecord, 0, advertisePacketLen); 1327 System.arraycopy(scanResponseBytes, 0, scanRecord, 1328 advertisePacketLen, scanResponsePacketLen); 1329 Log.d(TAG, "ScanRecord : " + Arrays.toString(scanRecord)); 1330 results.add(new ScanResult(device, ScanRecord.parseFromBytes(scanRecord), 1331 rssi, timestampNanos)); 1332 } 1333 return results; 1334 } 1335 1336 // Reverse byte array. 1337 private void reverse(byte[] address) { 1338 int len = address.length; 1339 for (int i = 0; i < len / 2; ++i) { 1340 byte b = address[i]; 1341 address[i] = address[len - 1 - i]; 1342 address[len - 1 - i] = b; 1343 } 1344 } 1345 1346 // Helper method to extract bytes from byte array. 1347 private static byte[] extractBytes(byte[] scanRecord, int start, int length) { 1348 byte[] bytes = new byte[length]; 1349 System.arraycopy(scanRecord, start, bytes, 0, length); 1350 return bytes; 1351 } 1352 1353 void onBatchScanThresholdCrossed(int clientIf) { 1354 if (DBG) { 1355 Log.d(TAG, "onBatchScanThresholdCrossed() - clientIf=" + clientIf); 1356 } 1357 flushPendingBatchResults(clientIf); 1358 } 1359 1360 AdvtFilterOnFoundOnLostInfo CreateonTrackAdvFoundLostObject(int client_if, int adv_pkt_len, 1361 byte[] adv_pkt, int scan_rsp_len, byte[] scan_rsp, int filt_index, int adv_state, 1362 int adv_info_present, String address, int addr_type, int tx_power, int rssi_value, 1363 int time_stamp) { 1364 1365 return new AdvtFilterOnFoundOnLostInfo(client_if, adv_pkt_len, adv_pkt, 1366 scan_rsp_len, scan_rsp, filt_index, adv_state, 1367 adv_info_present, address, addr_type, tx_power, 1368 rssi_value, time_stamp); 1369 } 1370 1371 void onTrackAdvFoundLost(AdvtFilterOnFoundOnLostInfo trackingInfo) throws RemoteException { 1372 if (DBG) Log.d(TAG, "onTrackAdvFoundLost() - scannerId= " + trackingInfo.getClientIf() 1373 + " address = " + trackingInfo.getAddress() 1374 + " adv_state = " + trackingInfo.getAdvState()); 1375 1376 ScannerMap.App app = mScannerMap.getById(trackingInfo.getClientIf()); 1377 if (app == null || (app.callback == null && app.info == null)) { 1378 Log.e(TAG, "app or callback is null"); 1379 return; 1380 } 1381 1382 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter() 1383 .getRemoteDevice(trackingInfo.getAddress()); 1384 int advertiserState = trackingInfo.getAdvState(); 1385 ScanResult result = new ScanResult(device, 1386 ScanRecord.parseFromBytes(trackingInfo.getResult()), 1387 trackingInfo.getRSSIValue(), SystemClock.elapsedRealtimeNanos()); 1388 1389 for (ScanClient client : mScanManager.getRegularScanQueue()) { 1390 if (client.scannerId == trackingInfo.getClientIf()) { 1391 ScanSettings settings = client.settings; 1392 if ((advertiserState == ADVT_STATE_ONFOUND) 1393 && ((settings.getCallbackType() 1394 & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0)) { 1395 if (app.callback != null) { 1396 app.callback.onFoundOrLost(true, result); 1397 } else { 1398 sendResultByPendingIntent(app.info, result, 1399 ScanSettings.CALLBACK_TYPE_FIRST_MATCH, client); 1400 } 1401 } else if ((advertiserState == ADVT_STATE_ONLOST) 1402 && ((settings.getCallbackType() 1403 & ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0)) { 1404 if (app.callback != null) { 1405 app.callback.onFoundOrLost(false, result); 1406 } else { 1407 sendResultByPendingIntent(app.info, result, 1408 ScanSettings.CALLBACK_TYPE_MATCH_LOST, client); 1409 } 1410 } else { 1411 Log.d(TAG, "Not reporting onlost/onfound : " + advertiserState 1412 + " scannerId = " + client.scannerId 1413 + " callbackType " + settings.getCallbackType()); 1414 } 1415 } 1416 } 1417 } 1418 1419 void onScanParamSetupCompleted(int status, int scannerId) throws RemoteException { 1420 ScannerMap.App app = mScannerMap.getById(scannerId); 1421 if (app == null || app.callback == null) { 1422 Log.e(TAG, "Advertise app or callback is null"); 1423 return; 1424 } 1425 Log.d(TAG, "onScanParamSetupCompleted : " + status); 1426 } 1427 1428 // callback from ScanManager for dispatch of errors apps. 1429 void onScanManagerErrorCallback(int scannerId, int errorCode) throws RemoteException { 1430 ScannerMap.App app = mScannerMap.getById(scannerId); 1431 if (app == null || (app.callback == null && app.info == null)) { 1432 Log.e(TAG, "App or callback is null"); 1433 return; 1434 } 1435 if (app.callback != null) { 1436 app.callback.onScanManagerErrorCallback(errorCode); 1437 } else { 1438 try { 1439 sendErrorByPendingIntent(app.info, errorCode); 1440 } catch (PendingIntent.CanceledException e) { 1441 Log.e(TAG, "Error sending error code via PendingIntent:" + e); 1442 } 1443 } 1444 } 1445 1446 void onConfigureMTU(int connId, int status, int mtu) throws RemoteException { 1447 String address = mClientMap.addressByConnId(connId); 1448 1449 if (DBG) Log.d(TAG, "onConfigureMTU() address=" + address + ", status=" 1450 + status + ", mtu=" + mtu); 1451 1452 ClientMap.App app = mClientMap.getByConnId(connId); 1453 if (app != null) { 1454 app.callback.onConfigureMTU(address, mtu, status); 1455 } 1456 } 1457 1458 void onClientCongestion(int connId, boolean congested) throws RemoteException { 1459 if (VDBG) Log.d(TAG, "onClientCongestion() - connId=" + connId + ", congested=" + congested); 1460 1461 ClientMap.App app = mClientMap.getByConnId(connId); 1462 1463 if (app != null) { 1464 app.isCongested = congested; 1465 while(!app.isCongested) { 1466 CallbackInfo callbackInfo = app.popQueuedCallback(); 1467 if (callbackInfo == null) return; 1468 app.callback.onCharacteristicWrite(callbackInfo.address, 1469 callbackInfo.status, callbackInfo.handle); 1470 } 1471 } 1472 } 1473 1474 /************************************************************************** 1475 * GATT Service functions - Shared CLIENT/SERVER 1476 *************************************************************************/ 1477 1478 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 1479 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1480 1481 final int DEVICE_TYPE_BREDR = 0x1; 1482 1483 Map<BluetoothDevice, Integer> deviceStates = new HashMap<BluetoothDevice, 1484 Integer>(); 1485 1486 // Add paired LE devices 1487 1488 Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices(); 1489 for (BluetoothDevice device : bondedDevices) { 1490 if (getDeviceType(device) != DEVICE_TYPE_BREDR) { 1491 deviceStates.put(device, BluetoothProfile.STATE_DISCONNECTED); 1492 } 1493 } 1494 1495 // Add connected deviceStates 1496 1497 Set<String> connectedDevices = new HashSet<String>(); 1498 connectedDevices.addAll(mClientMap.getConnectedDevices()); 1499 connectedDevices.addAll(mServerMap.getConnectedDevices()); 1500 1501 for (String address : connectedDevices ) { 1502 BluetoothDevice device = mAdapter.getRemoteDevice(address); 1503 if (device != null) { 1504 deviceStates.put(device, BluetoothProfile.STATE_CONNECTED); 1505 } 1506 } 1507 1508 // Create matching device sub-set 1509 1510 List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>(); 1511 1512 for (Map.Entry<BluetoothDevice, Integer> entry : deviceStates.entrySet()) { 1513 for(int state : states) { 1514 if (entry.getValue() == state) { 1515 deviceList.add(entry.getKey()); 1516 } 1517 } 1518 } 1519 1520 return deviceList; 1521 } 1522 1523 void registerScanner(IScannerCallback callback) { 1524 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1525 1526 UUID uuid = UUID.randomUUID(); 1527 if (DBG) Log.d(TAG, "registerScanner() - UUID=" + uuid); 1528 mScannerMap.add(uuid, callback, null, this); 1529 mScanManager.registerScanner(uuid); 1530 } 1531 1532 void unregisterScanner(int scannerId) { 1533 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1534 1535 if (DBG) Log.d(TAG, "unregisterScanner() - scannerId=" + scannerId); 1536 mScannerMap.remove(scannerId); 1537 mScanManager.unregisterScanner(scannerId); 1538 } 1539 1540 void startScan(int scannerId, ScanSettings settings, 1541 List<ScanFilter> filters, WorkSource workSource, 1542 List<List<ResultStorageDescriptor>> storages, String callingPackage) { 1543 if (DBG) Log.d(TAG, "start scan with filters"); 1544 enforceAdminPermission(); 1545 if (needsPrivilegedPermissionForScan(settings)) { 1546 enforcePrivilegedPermission(); 1547 } 1548 if (workSource != null) { 1549 enforceImpersonatationPermission(); 1550 } else { 1551 // Blame the caller if the work source is unspecified. 1552 workSource = new WorkSource(Binder.getCallingUid(), callingPackage); 1553 } 1554 final ScanClient scanClient = new ScanClient(scannerId, settings, filters, workSource, 1555 storages); 1556 scanClient.hasLocationPermission = Utils.checkCallerHasLocationPermission(this, mAppOps, 1557 callingPackage); 1558 scanClient.hasPeersMacAddressPermission = Utils.checkCallerHasPeersMacAddressPermission( 1559 this); 1560 scanClient.legacyForegroundApp = Utils.isLegacyForegroundApp(this, callingPackage); 1561 1562 AppScanStats app = null; 1563 app = mScannerMap.getAppScanStatsById(scannerId); 1564 1565 if (app != null) { 1566 if (app.isScanningTooFrequently() && 1567 checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED) != PERMISSION_GRANTED) { 1568 Log.e(TAG, "App '" + app.appName + "' is scanning too frequently"); 1569 return; 1570 } 1571 scanClient.stats = app; 1572 1573 boolean isFilteredScan = (filters != null) && !filters.isEmpty(); 1574 app.recordScanStart(settings, isFilteredScan); 1575 } 1576 1577 mScanManager.startScan(scanClient); 1578 } 1579 1580 void registerPiAndStartScan(PendingIntent pendingIntent, ScanSettings settings, 1581 List<ScanFilter> filters, String callingPackage) { 1582 if (DBG) Log.d(TAG, "start scan with filters, for PendingIntent"); 1583 enforceAdminPermission(); 1584 if (needsPrivilegedPermissionForScan(settings)) { 1585 enforcePrivilegedPermission(); 1586 } 1587 // Blame the caller if the work source is unspecified. 1588 WorkSource workSource = new WorkSource(Binder.getCallingUid(), callingPackage); 1589 1590 UUID uuid = UUID.randomUUID(); 1591 if (DBG) Log.d(TAG, "startScan(PI) - UUID=" + uuid); 1592 PendingIntentInfo piInfo = new PendingIntentInfo(); 1593 piInfo.intent = pendingIntent; 1594 piInfo.settings = settings; 1595 piInfo.filters = filters; 1596 piInfo.workSource = workSource; 1597 piInfo.callingPackage = callingPackage; 1598 mScannerMap.add(uuid, null, piInfo, this); 1599 mScanManager.registerScanner(uuid); 1600 } 1601 1602 void continuePiStartScan(int scannerId, PendingIntentInfo piInfo) { 1603 final ScanClient scanClient = 1604 new ScanClient(scannerId, piInfo.settings, piInfo.filters, piInfo.workSource, null); 1605 scanClient.hasLocationPermission = 1606 true; // Utils.checkCallerHasLocationPermission(this, mAppOps, 1607 // piInfo.callingPackage); 1608 scanClient.hasPeersMacAddressPermission = 1609 true; // Utils.checkCallerHasPeersMacAddressPermission( 1610 // this); 1611 scanClient.legacyForegroundApp = Utils.isLegacyForegroundApp(this, piInfo.callingPackage); 1612 1613 AppScanStats app = null; 1614 app = mScannerMap.getAppScanStatsById(scannerId); 1615 1616 if (app != null) { 1617 if (app.isScanningTooFrequently() 1618 && checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED) != PERMISSION_GRANTED) { 1619 Log.e(TAG, "App '" + app.appName + "' is scanning too frequently"); 1620 return; 1621 } 1622 scanClient.stats = app; 1623 1624 boolean isFilteredScan = (piInfo.filters != null) && !piInfo.filters.isEmpty(); 1625 app.recordScanStart(piInfo.settings, isFilteredScan); 1626 } 1627 1628 mScanManager.startScan(scanClient); 1629 } 1630 1631 void flushPendingBatchResults(int scannerId) { 1632 if (DBG) Log.d(TAG, "flushPendingBatchResults - scannerId=" + scannerId); 1633 mScanManager.flushBatchScanResults(new ScanClient(scannerId)); 1634 } 1635 1636 void stopScan(ScanClient client) { 1637 enforceAdminPermission(); 1638 int scanQueueSize = mScanManager.getBatchScanQueue().size() + 1639 mScanManager.getRegularScanQueue().size(); 1640 if (DBG) Log.d(TAG, "stopScan() - queue size =" + scanQueueSize); 1641 1642 AppScanStats app = null; 1643 app = mScannerMap.getAppScanStatsById(client.scannerId); 1644 if (app != null) app.recordScanStop(); 1645 1646 mScanManager.stopScan(client); 1647 } 1648 1649 void stopScan(PendingIntent intent, String callingPackage) { 1650 enforceAdminPermission(); 1651 PendingIntentInfo pii = new PendingIntentInfo(); 1652 pii.intent = intent; 1653 ScannerMap.App app = mScannerMap.getByContextInfo(pii); 1654 if (VDBG) Log.d(TAG, "stopScan(PendingIntent): app found = " + app); 1655 if (app != null) { 1656 final int scannerId = app.id; 1657 stopScan(new ScanClient(scannerId)); 1658 // Also unregister the scanner 1659 unregisterScanner(scannerId); 1660 } 1661 } 1662 1663 void disconnectAll() { 1664 if (DBG) Log.d(TAG, "disconnectAll()"); 1665 Map<Integer, String> connMap = mClientMap.getConnectedMap(); 1666 for(Map.Entry<Integer, String> entry:connMap.entrySet()){ 1667 if (DBG) Log.d(TAG, "disconnecting addr:" + entry.getValue()); 1668 clientDisconnect(entry.getKey(), entry.getValue()); 1669 //clientDisconnect(int clientIf, String address) 1670 } 1671 } 1672 1673 void unregAll() { 1674 for (Integer appId : mClientMap.getAllAppsIds()) { 1675 if (DBG) Log.d(TAG, "unreg:" + appId); 1676 unregisterClient(appId); 1677 } 1678 } 1679 1680 /************************************************************************** 1681 * PERIODIC SCANNING 1682 *************************************************************************/ 1683 void registerSync( 1684 ScanResult scanResult, int skip, int timeout, IPeriodicAdvertisingCallback callback) { 1685 enforceAdminPermission(); 1686 mPeriodicScanManager.startSync(scanResult, skip, timeout, callback); 1687 } 1688 1689 void unregisterSync(IPeriodicAdvertisingCallback callback) { 1690 enforceAdminPermission(); 1691 mPeriodicScanManager.stopSync(callback); 1692 } 1693 1694 /************************************************************************** 1695 * ADVERTISING SET 1696 *************************************************************************/ 1697 void startAdvertisingSet(AdvertisingSetParameters parameters, AdvertiseData advertiseData, 1698 AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters, 1699 AdvertiseData periodicData, int duration, int maxExtAdvEvents, 1700 IAdvertisingSetCallback callback) { 1701 enforceAdminPermission(); 1702 mAdvertiseManager.startAdvertisingSet(parameters, advertiseData, scanResponse, 1703 periodicParameters, periodicData, duration, maxExtAdvEvents, callback); 1704 } 1705 1706 void stopAdvertisingSet(IAdvertisingSetCallback callback) { 1707 enforceAdminPermission(); 1708 mAdvertiseManager.stopAdvertisingSet(callback); 1709 } 1710 1711 void enableAdvertisingSet(int advertiserId, boolean enable, int duration, int maxExtAdvEvents) { 1712 enforceAdminPermission(); 1713 mAdvertiseManager.enableAdvertisingSet(advertiserId, enable, duration, maxExtAdvEvents); 1714 } 1715 1716 void setAdvertisingData(int advertiserId, AdvertiseData data) { 1717 enforceAdminPermission(); 1718 mAdvertiseManager.setAdvertisingData(advertiserId, data); 1719 } 1720 1721 void setScanResponseData(int advertiserId, AdvertiseData data) { 1722 enforceAdminPermission(); 1723 mAdvertiseManager.setScanResponseData(advertiserId, data); 1724 } 1725 1726 void setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters) { 1727 enforceAdminPermission(); 1728 mAdvertiseManager.setAdvertisingParameters(advertiserId, parameters); 1729 } 1730 1731 void setPeriodicAdvertisingParameters( 1732 int advertiserId, PeriodicAdvertisingParameters parameters) { 1733 enforceAdminPermission(); 1734 mAdvertiseManager.setPeriodicAdvertisingParameters(advertiserId, parameters); 1735 } 1736 1737 void setPeriodicAdvertisingData(int advertiserId, AdvertiseData data) { 1738 enforceAdminPermission(); 1739 mAdvertiseManager.setPeriodicAdvertisingData(advertiserId, data); 1740 } 1741 1742 void setPeriodicAdvertisingEnable(int advertiserId, boolean enable) { 1743 enforceAdminPermission(); 1744 mAdvertiseManager.setPeriodicAdvertisingEnable(advertiserId, enable); 1745 } 1746 1747 /************************************************************************** 1748 * GATT Service functions - CLIENT 1749 *************************************************************************/ 1750 1751 void registerClient(UUID uuid, IBluetoothGattCallback callback) { 1752 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1753 1754 if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid); 1755 mClientMap.add(uuid, callback, null, this); 1756 gattClientRegisterAppNative(uuid.getLeastSignificantBits(), 1757 uuid.getMostSignificantBits()); 1758 } 1759 1760 void unregisterClient(int clientIf) { 1761 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1762 1763 if (DBG) Log.d(TAG, "unregisterClient() - clientIf=" + clientIf); 1764 mClientMap.remove(clientIf); 1765 gattClientUnregisterAppNative(clientIf); 1766 } 1767 1768 void clientConnect(int clientIf, String address, boolean isDirect, int transport, int phy) { 1769 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1770 1771 if (DBG) 1772 Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect + ", phy= " 1773 + phy); 1774 gattClientConnectNative(clientIf, address, isDirect, transport, phy); 1775 } 1776 1777 void clientDisconnect(int clientIf, String address) { 1778 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1779 1780 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1781 if (DBG) Log.d(TAG, "clientDisconnect() - address=" + address + ", connId=" + connId); 1782 1783 gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0); 1784 } 1785 1786 void clientSetPreferredPhy(int clientIf, String address, int txPhy, int rxPhy, int phyOptions) { 1787 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1788 1789 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1790 if (connId == null) { 1791 Log.d(TAG, "clientSetPreferredPhy() - no connection to " + address); 1792 return; 1793 } 1794 1795 if (DBG) Log.d(TAG, "clientSetPreferredPhy() - address=" + address + ", connId=" + connId); 1796 gattClientSetPreferredPhyNative(clientIf, connId, txPhy, rxPhy, phyOptions); 1797 } 1798 1799 void clientReadPhy(int clientIf, String address) { 1800 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1801 1802 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1803 if (connId == null) { 1804 Log.d(TAG, "clientReadPhy() - no connection to " + address); 1805 return; 1806 } 1807 1808 if (DBG) Log.d(TAG, "clientReadPhy() - address=" + address + ", connId=" + connId); 1809 gattClientReadPhyNative(clientIf, connId); 1810 } 1811 1812 int numHwTrackFiltersAvailable() { 1813 return (AdapterService.getAdapterService().getTotalNumOfTrackableAdvertisements() 1814 - mScanManager.getCurrentUsedTrackingAdvertisement()); 1815 } 1816 1817 synchronized List<ParcelUuid> getRegisteredServiceUuids() { 1818 Utils.enforceAdminPermission(this); 1819 List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>(); 1820 for (HandleMap.Entry entry : mHandleMap.mEntries) { 1821 serviceUuids.add(new ParcelUuid(entry.uuid)); 1822 } 1823 return serviceUuids; 1824 } 1825 1826 List<String> getConnectedDevices() { 1827 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1828 1829 Set<String> connectedDevAddress = new HashSet<String>(); 1830 connectedDevAddress.addAll(mClientMap.getConnectedDevices()); 1831 connectedDevAddress.addAll(mServerMap.getConnectedDevices()); 1832 List<String> connectedDeviceList = new ArrayList<String>(connectedDevAddress); 1833 return connectedDeviceList; 1834 } 1835 1836 void refreshDevice(int clientIf, String address) { 1837 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1838 1839 if (DBG) Log.d(TAG, "refreshDevice() - address=" + address); 1840 gattClientRefreshNative(clientIf, address); 1841 } 1842 1843 void discoverServices(int clientIf, String address) { 1844 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1845 1846 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1847 if (DBG) Log.d(TAG, "discoverServices() - address=" + address + ", connId=" + connId); 1848 1849 if (connId != null) 1850 gattClientSearchServiceNative(connId, true, 0, 0); 1851 else 1852 Log.e(TAG, "discoverServices() - No connection for " + address + "..."); 1853 } 1854 1855 void readCharacteristic(int clientIf, String address, int handle, int authReq) { 1856 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1857 1858 if (VDBG) Log.d(TAG, "readCharacteristic() - address=" + address); 1859 1860 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1861 if (connId == null) { 1862 Log.e(TAG, "readCharacteristic() - No connection for " + address + "..."); 1863 return; 1864 } 1865 1866 if (!permissionCheck(connId, handle)) { 1867 Log.w(TAG, "readCharacteristic() - permission check failed!"); 1868 return; 1869 } 1870 1871 gattClientReadCharacteristicNative(connId, handle, authReq); 1872 } 1873 1874 void writeCharacteristic(int clientIf, String address, int handle, int writeType, 1875 int authReq, byte[] value) { 1876 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1877 1878 if (VDBG) Log.d(TAG, "writeCharacteristic() - address=" + address); 1879 1880 if (mReliableQueue.contains(address)) writeType = 3; // Prepared write 1881 1882 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1883 if (connId == null) { 1884 Log.e(TAG, "writeCharacteristic() - No connection for " + address + "..."); 1885 return; 1886 } 1887 1888 if (!permissionCheck(connId, handle)) { 1889 Log.w(TAG, "writeCharacteristic() - permission check failed!"); 1890 return; 1891 } 1892 1893 gattClientWriteCharacteristicNative(connId, handle, writeType, authReq, value); 1894 } 1895 1896 void readDescriptor(int clientIf, String address, int handle, int authReq) { 1897 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1898 1899 if (VDBG) Log.d(TAG, "readDescriptor() - address=" + address); 1900 1901 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1902 if (connId == null) { 1903 Log.e(TAG, "readDescriptor() - No connection for " + address + "..."); 1904 return; 1905 } 1906 1907 if (!permissionCheck(connId, handle)) { 1908 Log.w(TAG, "readDescriptor() - permission check failed!"); 1909 return; 1910 } 1911 1912 gattClientReadDescriptorNative(connId, handle, authReq); 1913 }; 1914 1915 void writeDescriptor(int clientIf, String address, int handle, 1916 int authReq, byte[] value) { 1917 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1918 if (VDBG) Log.d(TAG, "writeDescriptor() - address=" + address); 1919 1920 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1921 if (connId == null) { 1922 Log.e(TAG, "writeDescriptor() - No connection for " + address + "..."); 1923 return; 1924 } 1925 1926 if (!permissionCheck(connId, handle)) { 1927 Log.w(TAG, "writeDescriptor() - permission check failed!"); 1928 return; 1929 } 1930 1931 gattClientWriteDescriptorNative(connId, handle, authReq, value); 1932 } 1933 1934 void beginReliableWrite(int clientIf, String address) { 1935 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1936 1937 if (DBG) Log.d(TAG, "beginReliableWrite() - address=" + address); 1938 mReliableQueue.add(address); 1939 } 1940 1941 void endReliableWrite(int clientIf, String address, boolean execute) { 1942 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1943 1944 if (DBG) Log.d(TAG, "endReliableWrite() - address=" + address 1945 + " execute: " + execute); 1946 mReliableQueue.remove(address); 1947 1948 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1949 if (connId != null) gattClientExecuteWriteNative(connId, execute); 1950 } 1951 1952 void registerForNotification(int clientIf, String address, int handle, boolean enable) { 1953 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1954 1955 if (DBG) Log.d(TAG, "registerForNotification() - address=" + address + " enable: " + enable); 1956 1957 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1958 if (connId == null) { 1959 Log.e(TAG, "registerForNotification() - No connection for " + address + "..."); 1960 return; 1961 } 1962 1963 if (!permissionCheck(connId, handle)) { 1964 Log.w(TAG, "registerForNotification() - permission check failed!"); 1965 return; 1966 } 1967 1968 gattClientRegisterForNotificationsNative(clientIf, address, handle, enable); 1969 } 1970 1971 void readRemoteRssi(int clientIf, String address) { 1972 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1973 1974 if (DBG) Log.d(TAG, "readRemoteRssi() - address=" + address); 1975 gattClientReadRemoteRssiNative(clientIf, address); 1976 } 1977 1978 void configureMTU(int clientIf, String address, int mtu) { 1979 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1980 1981 if (DBG) Log.d(TAG, "configureMTU() - address=" + address + " mtu=" + mtu); 1982 Integer connId = mClientMap.connIdByAddress(clientIf, address); 1983 if (connId != null) { 1984 gattClientConfigureMTUNative(connId, mtu); 1985 } else { 1986 Log.e(TAG, "configureMTU() - No connection for " + address + "..."); 1987 } 1988 } 1989 1990 void connectionParameterUpdate(int clientIf, String address, int connectionPriority) { 1991 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 1992 1993 int minInterval; 1994 int maxInterval; 1995 1996 // Slave latency 1997 int latency; 1998 1999 // Link supervision timeout is measured in N * 10ms 2000 int timeout = 2000; // 20s 2001 2002 switch (connectionPriority) 2003 { 2004 case BluetoothGatt.CONNECTION_PRIORITY_HIGH: 2005 minInterval = getResources().getInteger(R.integer.gatt_high_priority_min_interval); 2006 maxInterval = getResources().getInteger(R.integer.gatt_high_priority_max_interval); 2007 latency = getResources().getInteger(R.integer.gatt_high_priority_latency); 2008 break; 2009 2010 case BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER: 2011 minInterval = getResources().getInteger(R.integer.gatt_low_power_min_interval); 2012 maxInterval = getResources().getInteger(R.integer.gatt_low_power_max_interval); 2013 latency = getResources().getInteger(R.integer.gatt_low_power_latency); 2014 break; 2015 2016 default: 2017 // Using the values for CONNECTION_PRIORITY_BALANCED. 2018 minInterval = 2019 getResources().getInteger(R.integer.gatt_balanced_priority_min_interval); 2020 maxInterval = 2021 getResources().getInteger(R.integer.gatt_balanced_priority_max_interval); 2022 latency = getResources().getInteger(R.integer.gatt_balanced_priority_latency); 2023 break; 2024 } 2025 2026 if (DBG) Log.d(TAG, "connectionParameterUpdate() - address=" + address 2027 + "params=" + connectionPriority + " interval=" + minInterval + "/" + maxInterval); 2028 gattConnectionParameterUpdateNative(clientIf, address, minInterval, maxInterval, 2029 latency, timeout); 2030 } 2031 2032 /************************************************************************** 2033 * Callback functions - SERVER 2034 *************************************************************************/ 2035 2036 void onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb) 2037 throws RemoteException { 2038 2039 UUID uuid = new UUID(uuidMsb, uuidLsb); 2040 if (DBG) Log.d(TAG, "onServerRegistered() - UUID=" + uuid + ", serverIf=" + serverIf); 2041 ServerMap.App app = mServerMap.getByUuid(uuid); 2042 if (app != null) { 2043 app.id = serverIf; 2044 app.linkToDeath(new ServerDeathRecipient(serverIf)); 2045 app.callback.onServerRegistered(status, serverIf); 2046 } 2047 } 2048 2049 void onServiceAdded(int status, int serverIf, List<GattDbElement> service) 2050 throws RemoteException { 2051 if (DBG) Log.d(TAG, "onServiceAdded(), status=" + status); 2052 2053 if (status != 0) { 2054 return; 2055 } 2056 2057 GattDbElement svcEl = service.get(0); 2058 int srvcHandle = svcEl.attributeHandle; 2059 2060 BluetoothGattService svc = null; 2061 2062 for (GattDbElement el : service) { 2063 if (el.type == GattDbElement.TYPE_PRIMARY_SERVICE) { 2064 mHandleMap.addService(serverIf, el.attributeHandle, el.uuid, 2065 BluetoothGattService.SERVICE_TYPE_PRIMARY, 0, false); 2066 svc = new BluetoothGattService(svcEl.uuid, svcEl.attributeHandle, 2067 BluetoothGattService.SERVICE_TYPE_PRIMARY); 2068 } else if (el.type == GattDbElement.TYPE_SECONDARY_SERVICE) { 2069 mHandleMap.addService(serverIf, el.attributeHandle, el.uuid, 2070 BluetoothGattService.SERVICE_TYPE_SECONDARY, 0, false); 2071 svc = new BluetoothGattService(svcEl.uuid, svcEl.attributeHandle, 2072 BluetoothGattService.SERVICE_TYPE_SECONDARY); 2073 } else if (el.type == GattDbElement.TYPE_CHARACTERISTIC) { 2074 mHandleMap.addCharacteristic(serverIf, el.attributeHandle, el.uuid, srvcHandle); 2075 svc.addCharacteristic(new BluetoothGattCharacteristic(el.uuid, 2076 el.attributeHandle, el.properties, el.permissions)); 2077 } else if (el.type == GattDbElement.TYPE_DESCRIPTOR) { 2078 mHandleMap.addDescriptor(serverIf, el.attributeHandle, el.uuid, srvcHandle); 2079 List<BluetoothGattCharacteristic> chars = svc.getCharacteristics(); 2080 chars.get(chars.size()-1).addDescriptor( 2081 new BluetoothGattDescriptor(el.uuid, el.attributeHandle, el.permissions)); 2082 } 2083 } 2084 mHandleMap.setStarted(serverIf, srvcHandle, true); 2085 2086 ServerMap.App app = mServerMap.getById(serverIf); 2087 if (app != null) { 2088 app.callback.onServiceAdded(status, svc); 2089 } 2090 } 2091 2092 void onServiceStopped(int status, int serverIf, int srvcHandle) 2093 throws RemoteException { 2094 if (DBG) Log.d(TAG, "onServiceStopped() srvcHandle=" + srvcHandle 2095 + ", status=" + status); 2096 if (status == 0) 2097 mHandleMap.setStarted(serverIf, srvcHandle, false); 2098 stopNextService(serverIf, status); 2099 } 2100 2101 void onServiceDeleted(int status, int serverIf, int srvcHandle) { 2102 if (DBG) Log.d(TAG, "onServiceDeleted() srvcHandle=" + srvcHandle 2103 + ", status=" + status); 2104 mHandleMap.deleteService(serverIf, srvcHandle); 2105 } 2106 2107 void onClientConnected(String address, boolean connected, int connId, int serverIf) 2108 throws RemoteException { 2109 2110 if (DBG) Log.d(TAG, "onClientConnected() connId=" + connId 2111 + ", address=" + address + ", connected=" + connected); 2112 2113 ServerMap.App app = mServerMap.getById(serverIf); 2114 if (app == null) return; 2115 2116 if (connected) { 2117 mServerMap.addConnection(serverIf, connId, address); 2118 } else { 2119 mServerMap.removeConnection(serverIf, connId); 2120 } 2121 2122 app.callback.onServerConnectionState((byte)0, serverIf, connected, address); 2123 } 2124 2125 void onServerReadCharacteristic(String address, int connId, int transId, 2126 int handle, int offset, boolean isLong) 2127 throws RemoteException { 2128 if (VDBG) Log.d(TAG, "onServerReadCharacteristic() connId=" + connId 2129 + ", address=" + address + ", handle=" + handle 2130 + ", requestId=" + transId + ", offset=" + offset); 2131 2132 HandleMap.Entry entry = mHandleMap.getByHandle(handle); 2133 if (entry == null) return; 2134 2135 mHandleMap.addRequest(transId, handle); 2136 2137 ServerMap.App app = mServerMap.getById(entry.serverIf); 2138 if (app == null) return; 2139 2140 app.callback.onCharacteristicReadRequest(address, transId, offset, isLong, handle); 2141 } 2142 2143 void onServerReadDescriptor(String address, int connId, int transId, 2144 int handle, int offset, boolean isLong) 2145 throws RemoteException { 2146 if (VDBG) Log.d(TAG, "onServerReadDescriptor() connId=" + connId 2147 + ", address=" + address + ", handle=" + handle 2148 + ", requestId=" + transId + ", offset=" + offset); 2149 2150 HandleMap.Entry entry = mHandleMap.getByHandle(handle); 2151 if (entry == null) return; 2152 2153 mHandleMap.addRequest(transId, handle); 2154 2155 ServerMap.App app = mServerMap.getById(entry.serverIf); 2156 if (app == null) return; 2157 2158 app.callback.onDescriptorReadRequest(address, transId, offset, isLong, handle); 2159 } 2160 2161 void onServerWriteCharacteristic(String address, int connId, int transId, 2162 int handle, int offset, int length, 2163 boolean needRsp, boolean isPrep, 2164 byte[] data) 2165 throws RemoteException { 2166 if (VDBG) Log.d(TAG, "onServerWriteCharacteristic() connId=" + connId 2167 + ", address=" + address + ", handle=" + handle 2168 + ", requestId=" + transId + ", isPrep=" + isPrep 2169 + ", offset=" + offset); 2170 2171 HandleMap.Entry entry = mHandleMap.getByHandle(handle); 2172 if (entry == null) return; 2173 2174 mHandleMap.addRequest(transId, handle); 2175 2176 ServerMap.App app = mServerMap.getById(entry.serverIf); 2177 if (app == null) return; 2178 2179 app.callback.onCharacteristicWriteRequest(address, transId, 2180 offset, length, isPrep, needRsp, handle, data); 2181 } 2182 2183 void onServerWriteDescriptor(String address, int connId, int transId, 2184 int handle, int offset, int length, 2185 boolean needRsp, boolean isPrep, 2186 byte[] data) 2187 throws RemoteException { 2188 if (VDBG) Log.d(TAG, "onAttributeWrite() connId=" + connId 2189 + ", address=" + address + ", handle=" + handle 2190 + ", requestId=" + transId + ", isPrep=" + isPrep 2191 + ", offset=" + offset); 2192 2193 HandleMap.Entry entry = mHandleMap.getByHandle(handle); 2194 if (entry == null) return; 2195 2196 mHandleMap.addRequest(transId, handle); 2197 2198 ServerMap.App app = mServerMap.getById(entry.serverIf); 2199 if (app == null) return; 2200 2201 app.callback.onDescriptorWriteRequest(address, transId, 2202 offset, length, isPrep, needRsp, handle, data); 2203 } 2204 2205 void onExecuteWrite(String address, int connId, int transId, int execWrite) 2206 throws RemoteException { 2207 if (DBG) Log.d(TAG, "onExecuteWrite() connId=" + connId 2208 + ", address=" + address + ", transId=" + transId); 2209 2210 ServerMap.App app = mServerMap.getByConnId(connId); 2211 if (app == null) return; 2212 2213 app.callback.onExecuteWrite(address, transId, execWrite == 1); 2214 } 2215 2216 void onResponseSendCompleted(int status, int attrHandle) { 2217 if (DBG) Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle); 2218 } 2219 2220 void onNotificationSent(int connId, int status) throws RemoteException { 2221 if (VDBG) Log.d(TAG, "onNotificationSent() connId=" + connId + ", status=" + status); 2222 2223 String address = mServerMap.addressByConnId(connId); 2224 if (address == null) return; 2225 2226 ServerMap.App app = mServerMap.getByConnId(connId); 2227 if (app == null) return; 2228 2229 if (!app.isCongested) { 2230 app.callback.onNotificationSent(address, status); 2231 } else { 2232 if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) { 2233 status = BluetoothGatt.GATT_SUCCESS; 2234 } 2235 app.queueCallback(new CallbackInfo(address, status)); 2236 } 2237 } 2238 2239 void onServerCongestion(int connId, boolean congested) throws RemoteException { 2240 if (DBG) Log.d(TAG, "onServerCongestion() - connId=" + connId + ", congested=" + congested); 2241 2242 ServerMap.App app = mServerMap.getByConnId(connId); 2243 if (app == null) return; 2244 2245 app.isCongested = congested; 2246 while(!app.isCongested) { 2247 CallbackInfo callbackInfo = app.popQueuedCallback(); 2248 if (callbackInfo == null) return; 2249 app.callback.onNotificationSent(callbackInfo.address, callbackInfo.status); 2250 } 2251 } 2252 2253 void onMtuChanged(int connId, int mtu) throws RemoteException { 2254 if (DBG) Log.d(TAG, "onMtuChanged() - connId=" + connId + ", mtu=" + mtu); 2255 2256 String address = mServerMap.addressByConnId(connId); 2257 if (address == null) return; 2258 2259 ServerMap.App app = mServerMap.getByConnId(connId); 2260 if (app == null) return; 2261 2262 app.callback.onMtuChanged(address, mtu); 2263 } 2264 2265 /************************************************************************** 2266 * GATT Service functions - SERVER 2267 *************************************************************************/ 2268 2269 void registerServer(UUID uuid, IBluetoothGattServerCallback callback) { 2270 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2271 2272 if (DBG) Log.d(TAG, "registerServer() - UUID=" + uuid); 2273 mServerMap.add(uuid, callback, null, this); 2274 gattServerRegisterAppNative(uuid.getLeastSignificantBits(), 2275 uuid.getMostSignificantBits()); 2276 } 2277 2278 void unregisterServer(int serverIf) { 2279 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2280 2281 if (DBG) Log.d(TAG, "unregisterServer() - serverIf=" + serverIf); 2282 2283 deleteServices(serverIf); 2284 2285 mServerMap.remove(serverIf); 2286 gattServerUnregisterAppNative(serverIf); 2287 } 2288 2289 void serverConnect(int serverIf, String address, boolean isDirect, int transport) { 2290 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2291 2292 if (DBG) Log.d(TAG, "serverConnect() - address=" + address); 2293 gattServerConnectNative(serverIf, address, isDirect,transport); 2294 } 2295 2296 void serverDisconnect(int serverIf, String address) { 2297 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2298 2299 Integer connId = mServerMap.connIdByAddress(serverIf, address); 2300 if (DBG) Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId); 2301 2302 gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0); 2303 } 2304 2305 void serverSetPreferredPhy(int serverIf, String address, int txPhy, int rxPhy, int phyOptions) { 2306 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2307 2308 Integer connId = mServerMap.connIdByAddress(serverIf, address); 2309 if (connId == null) { 2310 Log.d(TAG, "serverSetPreferredPhy() - no connection to " + address); 2311 return; 2312 } 2313 2314 if (DBG) Log.d(TAG, "serverSetPreferredPhy() - address=" + address + ", connId=" + connId); 2315 gattServerSetPreferredPhyNative(serverIf, connId, txPhy, rxPhy, phyOptions); 2316 } 2317 2318 void serverReadPhy(int serverIf, String address) { 2319 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2320 2321 Integer connId = mServerMap.connIdByAddress(serverIf, address); 2322 if (connId == null) { 2323 Log.d(TAG, "serverReadPhy() - no connection to " + address); 2324 return; 2325 } 2326 2327 if (DBG) Log.d(TAG, "serverReadPhy() - address=" + address + ", connId=" + connId); 2328 gattServerReadPhyNative(serverIf, connId); 2329 } 2330 2331 void addService(int serverIf, BluetoothGattService service) { 2332 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2333 2334 if (DBG) Log.d(TAG, "addService() - uuid=" + service.getUuid()); 2335 2336 List<GattDbElement> db = new ArrayList<GattDbElement>(); 2337 2338 if (service.getType() == BluetoothGattService.SERVICE_TYPE_PRIMARY) 2339 db.add(GattDbElement.createPrimaryService(service.getUuid())); 2340 else db.add(GattDbElement.createSecondaryService(service.getUuid())); 2341 2342 for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) { 2343 int permission = ((characteristic.getKeySize() - 7) << 12) 2344 + characteristic.getPermissions(); 2345 db.add(GattDbElement.createCharacteristic(characteristic.getUuid(), 2346 characteristic.getProperties(), permission)); 2347 2348 for (BluetoothGattDescriptor descriptor: characteristic.getDescriptors()) { 2349 permission = ((characteristic.getKeySize() - 7) << 12) 2350 + descriptor.getPermissions(); 2351 db.add(GattDbElement.createDescriptor(descriptor.getUuid(), permission)); 2352 } 2353 } 2354 2355 for (BluetoothGattService includedService : service.getIncludedServices()) { 2356 int inclSrvc = mHandleMap.getServiceHandle(includedService.getUuid(), 2357 includedService.getType(), includedService.getInstanceId()); 2358 db.add(GattDbElement.createIncludedService(inclSrvc)); 2359 } 2360 2361 gattServerAddServiceNative(serverIf, db); 2362 } 2363 2364 void removeService(int serverIf, int handle) { 2365 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2366 2367 if (DBG) Log.d(TAG, "removeService() - handle=" + handle); 2368 2369 gattServerDeleteServiceNative(serverIf, handle); 2370 } 2371 2372 void clearServices(int serverIf) { 2373 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2374 2375 if (DBG) Log.d(TAG, "clearServices()"); 2376 deleteServices(serverIf); 2377 } 2378 2379 void sendResponse(int serverIf, String address, int requestId, 2380 int status, int offset, byte[] value) { 2381 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2382 2383 if (VDBG) Log.d(TAG, "sendResponse() - address=" + address); 2384 2385 int handle = 0; 2386 HandleMap.Entry entry = mHandleMap.getByRequestId(requestId); 2387 if (entry != null) handle = entry.handle; 2388 2389 int connId = mServerMap.connIdByAddress(serverIf, address); 2390 gattServerSendResponseNative(serverIf, connId, requestId, (byte)status, 2391 handle, offset, value, (byte)0); 2392 mHandleMap.deleteRequest(requestId); 2393 } 2394 2395 void sendNotification(int serverIf, String address, int handle, boolean confirm, byte[] value) { 2396 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 2397 2398 if (VDBG) Log.d(TAG, "sendNotification() - address=" + address + " handle=" + handle); 2399 2400 int connId = mServerMap.connIdByAddress(serverIf, address); 2401 if (connId == 0) return; 2402 2403 if (confirm) { 2404 gattServerSendIndicationNative(serverIf, handle, connId, value); 2405 } else { 2406 gattServerSendNotificationNative(serverIf, handle, connId, value); 2407 } 2408 } 2409 2410 2411 /************************************************************************** 2412 * Private functions 2413 *************************************************************************/ 2414 2415 private boolean isRestrictedCharUuid(final UUID charUuid) { 2416 return isHidUuid(charUuid); 2417 } 2418 2419 private boolean isRestrictedSrvcUuid(final UUID srvcUuid) { 2420 return isFidoUUID(srvcUuid); 2421 } 2422 2423 private boolean isHidUuid(final UUID uuid) { 2424 for (UUID hid_uuid : HID_UUIDS) { 2425 if (hid_uuid.equals(uuid)) return true; 2426 } 2427 return false; 2428 } 2429 2430 private boolean isFidoUUID(final UUID uuid) { 2431 for (UUID fido_uuid : FIDO_UUIDS) { 2432 if (fido_uuid.equals(uuid)) return true; 2433 } 2434 return false; 2435 } 2436 2437 private int getDeviceType(BluetoothDevice device) { 2438 int type = gattClientGetDeviceTypeNative(device.getAddress()); 2439 if (DBG) Log.d(TAG, "getDeviceType() - device=" + device 2440 + ", type=" + type); 2441 return type; 2442 } 2443 2444 private void enforceAdminPermission() { 2445 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 2446 } 2447 2448 private boolean needsPrivilegedPermissionForScan(ScanSettings settings) { 2449 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 2450 // BLE scan only mode needs special permission. 2451 if (adapter.getState() != BluetoothAdapter.STATE_ON) return true; 2452 2453 // Regular scan, no special permission. 2454 if (settings == null) return false; 2455 2456 // Regular scan, no special permission. 2457 if (settings.getReportDelayMillis() == 0) return false; 2458 2459 // Batch scan, truncated mode needs permission. 2460 return settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_ABBREVIATED; 2461 } 2462 2463 // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be 2464 // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission. 2465 private void enforcePrivilegedPermission() { 2466 enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, 2467 "Need BLUETOOTH_PRIVILEGED permission"); 2468 } 2469 2470 // Enforce caller has UPDATE_DEVICE_STATS permission, which allows the caller to blame other 2471 // apps for Bluetooth usage. A {@link SecurityException} will be thrown if the caller app does 2472 // not have UPDATE_DEVICE_STATS permission. 2473 private void enforceImpersonatationPermission() { 2474 enforceCallingOrSelfPermission(android.Manifest.permission.UPDATE_DEVICE_STATS, 2475 "Need UPDATE_DEVICE_STATS permission"); 2476 } 2477 2478 private void stopNextService(int serverIf, int status) throws RemoteException { 2479 if (DBG) Log.d(TAG, "stopNextService() - serverIf=" + serverIf 2480 + ", status=" + status); 2481 2482 if (status == 0) { 2483 List<HandleMap.Entry> entries = mHandleMap.getEntries(); 2484 for(HandleMap.Entry entry : entries) { 2485 if (entry.type != HandleMap.TYPE_SERVICE || 2486 entry.serverIf != serverIf || 2487 entry.started == false) 2488 continue; 2489 2490 gattServerStopServiceNative(serverIf, entry.handle); 2491 return; 2492 } 2493 } 2494 } 2495 2496 private void deleteServices(int serverIf) { 2497 if (DBG) Log.d(TAG, "deleteServices() - serverIf=" + serverIf); 2498 2499 /* 2500 * Figure out which handles to delete. 2501 * The handles are copied into a new list to avoid race conditions. 2502 */ 2503 List<Integer> handleList = new ArrayList<Integer>(); 2504 List<HandleMap.Entry> entries = mHandleMap.getEntries(); 2505 for(HandleMap.Entry entry : entries) { 2506 if (entry.type != HandleMap.TYPE_SERVICE || 2507 entry.serverIf != serverIf) 2508 continue; 2509 handleList.add(entry.handle); 2510 } 2511 2512 /* Now actually delete the services.... */ 2513 for(Integer handle : handleList) { 2514 gattServerDeleteServiceNative(serverIf, handle); 2515 } 2516 } 2517 2518 private List<UUID> parseUuids(byte[] adv_data) { 2519 List<UUID> uuids = new ArrayList<UUID>(); 2520 2521 int offset = 0; 2522 while(offset < (adv_data.length-2)) { 2523 int len = Byte.toUnsignedInt(adv_data[offset++]); 2524 if (len == 0) break; 2525 2526 int type = adv_data[offset++]; 2527 switch (type) { 2528 case 0x02: // Partial list of 16-bit UUIDs 2529 case 0x03: // Complete list of 16-bit UUIDs 2530 while (len > 1) { 2531 int uuid16 = adv_data[offset++]; 2532 uuid16 += (adv_data[offset++] << 8); 2533 len -= 2; 2534 uuids.add(UUID.fromString(String.format( 2535 "%08x-0000-1000-8000-00805f9b34fb", uuid16))); 2536 } 2537 break; 2538 2539 default: 2540 offset += (len - 1); 2541 break; 2542 } 2543 } 2544 2545 return uuids; 2546 } 2547 2548 @Override 2549 public void dump(StringBuilder sb) { 2550 super.dump(sb); 2551 println(sb, "mAdvertisingServiceUuids:"); 2552 for (UUID uuid : mAdvertisingServiceUuids) { 2553 println(sb, " " + uuid); 2554 } 2555 2556 println(sb, "mMaxScanFilters: " + mMaxScanFilters); 2557 2558 sb.append("\nGATT Scanner Map\n"); 2559 mScannerMap.dump(sb); 2560 2561 sb.append("GATT Client Map\n"); 2562 mClientMap.dump(sb); 2563 2564 sb.append("GATT Server Map\n"); 2565 mServerMap.dump(sb); 2566 2567 sb.append("GATT Handle Map\n"); 2568 mHandleMap.dump(sb); 2569 } 2570 2571 void addScanResult() { 2572 if (mScanEvents.isEmpty()) 2573 return; 2574 2575 BluetoothProto.ScanEvent curr = mScanEvents.get(mScanEvents.size() - 1); 2576 curr.setNumberResults(curr.getNumberResults() + 1); 2577 } 2578 2579 void addScanEvent(BluetoothProto.ScanEvent event) { 2580 synchronized(mScanEvents) { 2581 if (mScanEvents.size() == NUM_SCAN_EVENTS_KEPT) 2582 mScanEvents.remove(0); 2583 mScanEvents.add(event); 2584 } 2585 } 2586 2587 @Override 2588 public void dumpProto(BluetoothProto.BluetoothLog proto) { 2589 synchronized(mScanEvents) { 2590 for (BluetoothProto.ScanEvent event : mScanEvents) { 2591 proto.addScanEvent(event); 2592 } 2593 } 2594 } 2595 2596 /************************************************************************** 2597 * GATT Test functions 2598 *************************************************************************/ 2599 2600 void gattTestCommand(int command, UUID uuid1, String bda1, 2601 int p1, int p2, int p3, int p4, int p5) { 2602 if (bda1 == null) bda1 = "00:00:00:00:00:00"; 2603 if (uuid1 != null) 2604 gattTestNative(command, uuid1.getLeastSignificantBits(), 2605 uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5); 2606 else 2607 gattTestNative(command, 0,0, bda1, p1, p2, p3, p4, p5); 2608 } 2609 2610 private native void gattTestNative(int command, 2611 long uuid1_lsb, long uuid1_msb, String bda1, 2612 int p1, int p2, int p3, int p4, int p5); 2613 2614 /************************************************************************** 2615 * Native functions prototypes 2616 *************************************************************************/ 2617 2618 private native static void classInitNative(); 2619 private native void initializeNative(); 2620 private native void cleanupNative(); 2621 2622 private native int gattClientGetDeviceTypeNative(String address); 2623 2624 private native void gattClientRegisterAppNative(long app_uuid_lsb, 2625 long app_uuid_msb); 2626 2627 private native void gattClientUnregisterAppNative(int clientIf); 2628 2629 private native void gattClientConnectNative( 2630 int clientIf, String address, boolean isDirect, int transport, int initiating_phys); 2631 2632 private native void gattClientDisconnectNative(int clientIf, String address, 2633 int conn_id); 2634 2635 private native void gattClientSetPreferredPhyNative( 2636 int clientIf, int conn_id, int tx_phy, int rx_phy, int phy_options); 2637 2638 private native void gattClientReadPhyNative(int clientIf, int conn_id); 2639 2640 private native void gattClientRefreshNative(int clientIf, String address); 2641 2642 private native void gattClientSearchServiceNative(int conn_id, 2643 boolean search_all, long service_uuid_lsb, long service_uuid_msb); 2644 2645 private native void gattClientGetGattDbNative(int conn_id); 2646 2647 private native void gattClientReadCharacteristicNative(int conn_id, int handle, int authReq); 2648 2649 private native void gattClientReadDescriptorNative(int conn_id, int handle, int authReq); 2650 2651 private native void gattClientWriteCharacteristicNative(int conn_id, 2652 int handle, int write_type, int auth_req, byte[] value); 2653 2654 private native void gattClientWriteDescriptorNative(int conn_id, int handle, 2655 int auth_req, byte[] value); 2656 2657 private native void gattClientExecuteWriteNative(int conn_id, boolean execute); 2658 2659 private native void gattClientRegisterForNotificationsNative(int clientIf, 2660 String address, int handle, boolean enable); 2661 2662 private native void gattClientReadRemoteRssiNative(int clientIf, 2663 String address); 2664 2665 private native void gattClientConfigureMTUNative(int conn_id, int mtu); 2666 2667 private native void gattConnectionParameterUpdateNative(int client_if, String address, 2668 int minInterval, int maxInterval, int latency, int timeout); 2669 2670 private native void gattServerRegisterAppNative(long app_uuid_lsb, 2671 long app_uuid_msb); 2672 2673 private native void gattServerUnregisterAppNative(int serverIf); 2674 2675 private native void gattServerConnectNative(int server_if, String address, 2676 boolean is_direct, int transport); 2677 2678 private native void gattServerDisconnectNative(int serverIf, String address, 2679 int conn_id); 2680 2681 private native void gattServerSetPreferredPhyNative( 2682 int clientIf, int conn_id, int tx_phy, int rx_phy, int phy_options); 2683 2684 private native void gattServerReadPhyNative(int clientIf, int conn_id); 2685 2686 private native void gattServerAddServiceNative(int server_if, List<GattDbElement> service); 2687 2688 private native void gattServerStopServiceNative (int server_if, 2689 int svc_handle); 2690 2691 private native void gattServerDeleteServiceNative (int server_if, 2692 int svc_handle); 2693 2694 private native void gattServerSendIndicationNative (int server_if, 2695 int attr_handle, int conn_id, byte[] val); 2696 2697 private native void gattServerSendNotificationNative (int server_if, 2698 int attr_handle, int conn_id, byte[] val); 2699 2700 private native void gattServerSendResponseNative (int server_if, 2701 int conn_id, int trans_id, int status, int handle, int offset, 2702 byte[] val, int auth_req); 2703} 2704