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