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