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