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