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