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