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