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