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