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