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