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