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