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