GattService.java revision 3ae219d81403f905ed4efc3b6071acae075e7660
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        byte[] legacy_adv_data = Arrays.copyOfRange(adv_data, 0, 62);
714
715        for (ScanClient client : mScanManager.getRegularScanQueue()) {
716            if (client.uuids.length > 0) {
717                int matches = 0;
718                for (UUID search : client.uuids) {
719                    for (UUID remote: remoteUuids) {
720                        if (remote.equals(search)) {
721                            ++matches;
722                            break; // Only count 1st match in case of duplicates
723                        }
724                    }
725                }
726
727                if (matches < client.uuids.length) continue;
728            }
729
730            ScannerMap.App app = mScannerMap.getById(client.scannerId);
731            if (app == null) {
732                continue;
733            }
734
735            BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
736
737            ScanSettings settings = client.settings;
738            byte[] scan_record_data;
739            // This is for compability with applications that assume fixed size scan data.
740            if (settings.getLegacy() && ((event_type & ET_LEGACY_MASK) == 0)) {
741                scan_record_data = legacy_adv_data;
742            } else {
743                scan_record_data = adv_data;
744            }
745
746            ScanResult result = new ScanResult(device, event_type, primary_phy, secondary_phy,
747                    advertising_sid, tx_power, rssi, periodic_adv_int,
748                    ScanRecord.parseFromBytes(scan_record_data),
749                    SystemClock.elapsedRealtimeNanos());
750            // Do no report if location mode is OFF or the client has no location permission
751            // PEERS_MAC_ADDRESS permission holders always get results
752            if (!hasScanResultPermission(client) || !matchesFilters(client, result)) {
753                continue;
754            }
755
756            if ((settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_ALL_MATCHES) == 0) {
757                continue;
758            }
759
760            // if this is legacy scan, return only legacy scan results
761            if (settings.getLegacy() && ((event_type & ET_LEGACY_MASK) == 0)) {
762                continue;
763            }
764
765            try {
766                app.appScanStats.addResult();
767                app.callback.onScanResult(result);
768            } catch (RemoteException e) {
769                Log.e(TAG, "Exception: " + e);
770                mScannerMap.remove(client.scannerId);
771                mScanManager.stopScan(client);
772            }
773        }
774    }
775
776    void onScannerRegistered(int status, int scannerId, long uuidLsb, long uuidMsb)
777            throws RemoteException {
778        UUID uuid = new UUID(uuidMsb, uuidLsb);
779        if (DBG) Log.d(TAG, "onScannerRegistered() - UUID=" + uuid
780                + ", scannerId=" + scannerId + ", status=" + status);
781
782        ScannerMap.App app = mScannerMap.getByUuid(uuid);
783        if (app != null) {
784            if (status == 0) {
785                app.id = scannerId;
786                app.linkToDeath(new ScannerDeathRecipient(scannerId));
787            } else {
788                mScannerMap.remove(scannerId);
789            }
790            app.callback.onScannerRegistered(status, scannerId);
791        }
792    }
793
794    /** Determines if the given scan client has the appropriate permissions to receive callbacks. */
795    private boolean hasScanResultPermission(final ScanClient client) {
796        final boolean requiresLocationEnabled =
797                getResources().getBoolean(R.bool.strict_location_check);
798        final boolean locationEnabledSetting = Settings.Secure.getInt(getContentResolver(),
799                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF)
800                != Settings.Secure.LOCATION_MODE_OFF;
801        final boolean locationEnabled = !requiresLocationEnabled || locationEnabledSetting
802                || client.legacyForegroundApp;
803        return (client.hasPeersMacAddressPermission
804                || (client.hasLocationPermission && locationEnabled));
805    }
806
807    // Check if a scan record matches a specific filters.
808    private boolean matchesFilters(ScanClient client, ScanResult scanResult) {
809        if (client.filters == null || client.filters.isEmpty()) {
810            return true;
811        }
812        for (ScanFilter filter : client.filters) {
813            if (filter.matches(scanResult)) {
814                return true;
815            }
816        }
817        return false;
818    }
819
820    void onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb)
821            throws RemoteException {
822        UUID uuid = new UUID(uuidMsb, uuidLsb);
823        if (DBG) Log.d(TAG, "onClientRegistered() - UUID=" + uuid + ", clientIf=" + clientIf);
824        ClientMap.App app = mClientMap.getByUuid(uuid);
825        if (app != null) {
826            if (status == 0) {
827                app.id = clientIf;
828                app.linkToDeath(new ClientDeathRecipient(clientIf));
829            } else {
830                mClientMap.remove(uuid);
831            }
832            app.callback.onClientRegistered(status, clientIf);
833        }
834    }
835
836    void onConnected(int clientIf, int connId, int status, String address)
837            throws RemoteException  {
838        if (DBG) Log.d(TAG, "onConnected() - clientIf=" + clientIf
839            + ", connId=" + connId + ", address=" + address);
840
841        if (status == 0) mClientMap.addConnection(clientIf, connId, address);
842        ClientMap.App app = mClientMap.getById(clientIf);
843        if (app != null) {
844            app.callback.onClientConnectionState(status, clientIf,
845                                (status==BluetoothGatt.GATT_SUCCESS), address);
846        }
847    }
848
849    void onDisconnected(int clientIf, int connId, int status, String address)
850            throws RemoteException {
851        if (DBG) Log.d(TAG, "onDisconnected() - clientIf=" + clientIf
852            + ", connId=" + connId + ", address=" + address);
853
854        mClientMap.removeConnection(clientIf, connId);
855        ClientMap.App app = mClientMap.getById(clientIf);
856        if (app != null) {
857            app.callback.onClientConnectionState(status, clientIf, false, address);
858        }
859    }
860
861    void onSearchCompleted(int connId, int status) throws RemoteException {
862        if (DBG) Log.d(TAG, "onSearchCompleted() - connId=" + connId+ ", status=" + status);
863        // Gatt DB is ready!
864
865        // This callback was called from the jni_workqueue thread. If we make request to the stack
866        // on the same thread, it might cause deadlock. Schedule request on a new thread instead.
867        Thread t = new Thread(new Runnable() {
868            public void run() {
869                gattClientGetGattDbNative(connId);
870            }
871        });
872        t.start();
873    }
874
875    GattDbElement GetSampleGattDbElement() {
876        return new GattDbElement();
877    }
878
879    void onGetGattDb(int connId, ArrayList<GattDbElement> db) throws RemoteException {
880        String address = mClientMap.addressByConnId(connId);
881
882        if (DBG) Log.d(TAG, "onGetGattDb() - address=" + address);
883
884        ClientMap.App app = mClientMap.getByConnId(connId);
885        if (app == null || app.callback == null) {
886            Log.e(TAG, "app or callback is null");
887            return;
888        }
889
890        List<BluetoothGattService> db_out = new ArrayList<BluetoothGattService>();
891
892        BluetoothGattService currSrvc = null;
893        BluetoothGattCharacteristic currChar = null;
894
895        for (GattDbElement el: db) {
896            switch (el.type)
897            {
898                case GattDbElement.TYPE_PRIMARY_SERVICE:
899                case GattDbElement.TYPE_SECONDARY_SERVICE:
900                    if (DBG) Log.d(TAG, "got service with UUID=" + el.uuid);
901
902                    currSrvc = new BluetoothGattService(el.uuid, el.id, el.type);
903                    db_out.add(currSrvc);
904                    break;
905
906                case GattDbElement.TYPE_CHARACTERISTIC:
907                    if (DBG) Log.d(TAG, "got characteristic with UUID=" + el.uuid);
908
909                    currChar = new BluetoothGattCharacteristic(el.uuid, el.id, el.properties, 0);
910                    currSrvc.addCharacteristic(currChar);
911                    break;
912
913                case GattDbElement.TYPE_DESCRIPTOR:
914                    if (DBG) Log.d(TAG, "got descriptor with UUID=" + el.uuid);
915
916                    currChar.addDescriptor(new BluetoothGattDescriptor(el.uuid, el.id, 0));
917                    break;
918
919                case GattDbElement.TYPE_INCLUDED_SERVICE:
920                    if (DBG) Log.d(TAG, "got included service with UUID=" + el.uuid);
921
922                    currSrvc.addIncludedService(new BluetoothGattService(el.uuid, el.id, el.type));
923                    break;
924
925                default:
926                    Log.e(TAG, "got unknown element with type=" + el.type + " and UUID=" + el.uuid);
927            }
928        }
929
930        // Search is complete when there was error, or nothing more to process
931        gattClientDatabases.put(connId, db_out);
932        app.callback.onSearchComplete(address, db_out, 0 /* status */);
933    }
934
935    void onRegisterForNotifications(int connId, int status, int registered, int handle) {
936        String address = mClientMap.addressByConnId(connId);
937
938        if (DBG) Log.d(TAG, "onRegisterForNotifications() - address=" + address
939            + ", status=" + status + ", registered=" + registered
940            + ", handle=" + handle);
941    }
942
943    void onNotify(int connId, String address, int handle,
944            boolean isNotify, byte[] data) throws RemoteException {
945
946        if (VDBG) Log.d(TAG, "onNotify() - address=" + address
947            + ", handle=" + handle + ", length=" + data.length);
948
949        if (!permissionCheck(connId, handle)) {
950            Log.w(TAG, "onNotify() - permission check failed!");
951            return;
952        }
953
954        ClientMap.App app = mClientMap.getByConnId(connId);
955        if (app != null) {
956            app.callback.onNotify(address, handle, data);
957        }
958    }
959
960    void onReadCharacteristic(int connId, int status, int handle, byte[] data) throws RemoteException {
961        String address = mClientMap.addressByConnId(connId);
962
963        if (VDBG) Log.d(TAG, "onReadCharacteristic() - address=" + address
964            + ", status=" + status + ", length=" + data.length);
965
966        ClientMap.App app = mClientMap.getByConnId(connId);
967        if (app != null) {
968            app.callback.onCharacteristicRead(address, status, handle, data);
969        }
970    }
971
972    void onWriteCharacteristic(int connId, int status, int handle)
973            throws RemoteException {
974        String address = mClientMap.addressByConnId(connId);
975
976        if (VDBG) Log.d(TAG, "onWriteCharacteristic() - address=" + address
977            + ", status=" + status);
978
979        ClientMap.App app = mClientMap.getByConnId(connId);
980        if (app == null) return;
981
982        if (!app.isCongested) {
983            app.callback.onCharacteristicWrite(address, status, handle);
984        } else {
985            if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) {
986                status = BluetoothGatt.GATT_SUCCESS;
987            }
988            CallbackInfo callbackInfo = new CallbackInfo(address, status, handle);
989            app.queueCallback(callbackInfo);
990        }
991    }
992
993    void onExecuteCompleted(int connId, int status) throws RemoteException {
994        String address = mClientMap.addressByConnId(connId);
995        if (VDBG) Log.d(TAG, "onExecuteCompleted() - address=" + address
996            + ", status=" + status);
997
998        ClientMap.App app = mClientMap.getByConnId(connId);
999        if (app != null) {
1000            app.callback.onExecuteWrite(address, status);
1001        }
1002    }
1003
1004    void onReadDescriptor(int connId, int status, int handle, byte[] data) throws RemoteException {
1005        String address = mClientMap.addressByConnId(connId);
1006
1007        if (VDBG) Log.d(TAG, "onReadDescriptor() - address=" + address
1008            + ", status=" + status + ", length=" + data.length);
1009
1010        ClientMap.App app = mClientMap.getByConnId(connId);
1011        if (app != null) {
1012            app.callback.onDescriptorRead(address, status, handle, data);
1013        }
1014    }
1015
1016    void onWriteDescriptor(int connId, int status, int handle) throws RemoteException {
1017        String address = mClientMap.addressByConnId(connId);
1018
1019        if (VDBG) Log.d(TAG, "onWriteDescriptor() - address=" + address
1020            + ", status=" + status);
1021
1022        ClientMap.App app = mClientMap.getByConnId(connId);
1023        if (app != null) {
1024            app.callback.onDescriptorWrite(address, status, handle);
1025        }
1026    }
1027
1028    void onReadRemoteRssi(int clientIf, String address,
1029                    int rssi, int status) throws RemoteException{
1030        if (DBG) Log.d(TAG, "onReadRemoteRssi() - clientIf=" + clientIf + " address=" +
1031                     address + ", rssi=" + rssi + ", status=" + status);
1032
1033        ClientMap.App app = mClientMap.getById(clientIf);
1034        if (app != null) {
1035            app.callback.onReadRemoteRssi(address, rssi, status);
1036        }
1037    }
1038
1039    void onScanFilterEnableDisabled(int action, int status, int clientIf) {
1040        if (DBG) {
1041            Log.d(TAG, "onScanFilterEnableDisabled() - clientIf=" + clientIf + ", status=" + status
1042                    + ", action=" + action);
1043        }
1044        mScanManager.callbackDone(clientIf, status);
1045    }
1046
1047    void onScanFilterParamsConfigured(int action, int status, int clientIf, int availableSpace) {
1048        if (DBG) {
1049            Log.d(TAG, "onScanFilterParamsConfigured() - clientIf=" + clientIf
1050                    + ", status=" + status + ", action=" + action
1051                    + ", availableSpace=" + availableSpace);
1052        }
1053        mScanManager.callbackDone(clientIf, status);
1054    }
1055
1056    void onScanFilterConfig(int action, int status, int clientIf, int filterType,
1057            int availableSpace) {
1058        if (DBG) {
1059            Log.d(TAG, "onScanFilterConfig() - clientIf=" + clientIf + ", action = " + action
1060                    + " status = " + status + ", filterType=" + filterType
1061                    + ", availableSpace=" + availableSpace);
1062        }
1063
1064        mScanManager.callbackDone(clientIf, status);
1065    }
1066
1067    void onBatchScanStorageConfigured(int status, int clientIf) {
1068        if (DBG) {
1069            Log.d(TAG, "onBatchScanStorageConfigured() - clientIf="+ clientIf + ", status=" + status);
1070        }
1071        mScanManager.callbackDone(clientIf, status);
1072    }
1073
1074    // TODO: split into two different callbacks : onBatchScanStarted and onBatchScanStopped.
1075    void onBatchScanStartStopped(int startStopAction, int status, int clientIf) {
1076        if (DBG) {
1077            Log.d(TAG, "onBatchScanStartStopped() - clientIf=" + clientIf
1078                    + ", status=" + status + ", startStopAction=" + startStopAction);
1079        }
1080        mScanManager.callbackDone(clientIf, status);
1081    }
1082
1083    void onBatchScanReports(int status, int scannerId, int reportType, int numRecords,
1084            byte[] recordData) throws RemoteException {
1085        if (DBG) {
1086            Log.d(TAG, "onBatchScanReports() - scannerId=" + scannerId + ", status=" + status
1087                    + ", reportType=" + reportType + ", numRecords=" + numRecords);
1088        }
1089        mScanManager.callbackDone(scannerId, status);
1090        Set<ScanResult> results = parseBatchScanResults(numRecords, reportType, recordData);
1091        if (reportType == ScanManager.SCAN_RESULT_TYPE_TRUNCATED) {
1092            // We only support single client for truncated mode.
1093            ScannerMap.App app = mScannerMap.getById(scannerId);
1094            if (app == null) return;
1095            app.callback.onBatchScanResults(new ArrayList<ScanResult>(results));
1096        } else {
1097            for (ScanClient client : mScanManager.getFullBatchScanQueue()) {
1098                // Deliver results for each client.
1099                deliverBatchScan(client, results);
1100            }
1101        }
1102    }
1103
1104    // Check and deliver scan results for different scan clients.
1105    private void deliverBatchScan(ScanClient client, Set<ScanResult> allResults) throws
1106            RemoteException {
1107        ScannerMap.App app = mScannerMap.getById(client.scannerId);
1108        if (app == null) return;
1109        if (client.filters == null || client.filters.isEmpty()) {
1110            app.callback.onBatchScanResults(new ArrayList<ScanResult>(allResults));
1111        }
1112        // Reconstruct the scan results.
1113        List<ScanResult> results = new ArrayList<ScanResult>();
1114        for (ScanResult scanResult : allResults) {
1115            if (matchesFilters(client, scanResult)) {
1116                results.add(scanResult);
1117            }
1118        }
1119        app.callback.onBatchScanResults(results);
1120    }
1121
1122    private Set<ScanResult> parseBatchScanResults(int numRecords, int reportType,
1123            byte[] batchRecord) {
1124        if (numRecords == 0) {
1125            return Collections.emptySet();
1126        }
1127        if (DBG) Log.d(TAG, "current time is " + SystemClock.elapsedRealtimeNanos());
1128        if (reportType == ScanManager.SCAN_RESULT_TYPE_TRUNCATED) {
1129            return parseTruncatedResults(numRecords, batchRecord);
1130        } else {
1131            return parseFullResults(numRecords, batchRecord);
1132        }
1133    }
1134
1135    private Set<ScanResult> parseTruncatedResults(int numRecords, byte[] batchRecord) {
1136        if (DBG) Log.d(TAG, "batch record " + Arrays.toString(batchRecord));
1137        Set<ScanResult> results = new HashSet<ScanResult>(numRecords);
1138        long now = SystemClock.elapsedRealtimeNanos();
1139        for (int i = 0; i < numRecords; ++i) {
1140            byte[] record = extractBytes(batchRecord, i * TRUNCATED_RESULT_SIZE,
1141                    TRUNCATED_RESULT_SIZE);
1142            byte[] address = extractBytes(record, 0, 6);
1143            reverse(address);
1144            BluetoothDevice device = mAdapter.getRemoteDevice(address);
1145            int rssi = record[8];
1146            long timestampNanos = now - parseTimestampNanos(extractBytes(record, 9, 2));
1147            results.add(new ScanResult(device, ScanRecord.parseFromBytes(new byte[0]),
1148                    rssi, timestampNanos));
1149        }
1150        return results;
1151    }
1152
1153    @VisibleForTesting
1154    long parseTimestampNanos(byte[] data) {
1155        long timestampUnit = NumberUtils.littleEndianByteArrayToInt(data);
1156        // Timestamp is in every 50 ms.
1157        return TimeUnit.MILLISECONDS.toNanos(timestampUnit * 50);
1158    }
1159
1160    private Set<ScanResult> parseFullResults(int numRecords, byte[] batchRecord) {
1161        Log.d(TAG, "Batch record : " + Arrays.toString(batchRecord));
1162        Set<ScanResult> results = new HashSet<ScanResult>(numRecords);
1163        int position = 0;
1164        long now = SystemClock.elapsedRealtimeNanos();
1165        while (position < batchRecord.length) {
1166            byte[] address = extractBytes(batchRecord, position, 6);
1167            // TODO: remove temp hack.
1168            reverse(address);
1169            BluetoothDevice device = mAdapter.getRemoteDevice(address);
1170            position += 6;
1171            // Skip address type.
1172            position++;
1173            // Skip tx power level.
1174            position++;
1175            int rssi = batchRecord[position++];
1176            long timestampNanos = now - parseTimestampNanos(extractBytes(batchRecord, position, 2));
1177            position += 2;
1178
1179            // Combine advertise packet and scan response packet.
1180            int advertisePacketLen = batchRecord[position++];
1181            byte[] advertiseBytes = extractBytes(batchRecord, position, advertisePacketLen);
1182            position += advertisePacketLen;
1183            int scanResponsePacketLen = batchRecord[position++];
1184            byte[] scanResponseBytes = extractBytes(batchRecord, position, scanResponsePacketLen);
1185            position += scanResponsePacketLen;
1186            byte[] scanRecord = new byte[advertisePacketLen + scanResponsePacketLen];
1187            System.arraycopy(advertiseBytes, 0, scanRecord, 0, advertisePacketLen);
1188            System.arraycopy(scanResponseBytes, 0, scanRecord,
1189                    advertisePacketLen, scanResponsePacketLen);
1190            Log.d(TAG, "ScanRecord : " + Arrays.toString(scanRecord));
1191            results.add(new ScanResult(device, ScanRecord.parseFromBytes(scanRecord),
1192                    rssi, timestampNanos));
1193        }
1194        return results;
1195    }
1196
1197    // Reverse byte array.
1198    private void reverse(byte[] address) {
1199        int len = address.length;
1200        for (int i = 0; i < len / 2; ++i) {
1201            byte b = address[i];
1202            address[i] = address[len - 1 - i];
1203            address[len - 1 - i] = b;
1204        }
1205    }
1206
1207    // Helper method to extract bytes from byte array.
1208    private static byte[] extractBytes(byte[] scanRecord, int start, int length) {
1209        byte[] bytes = new byte[length];
1210        System.arraycopy(scanRecord, start, bytes, 0, length);
1211        return bytes;
1212    }
1213
1214    void onBatchScanThresholdCrossed(int clientIf) {
1215        if (DBG) {
1216            Log.d(TAG, "onBatchScanThresholdCrossed() - clientIf=" + clientIf);
1217        }
1218        flushPendingBatchResults(clientIf);
1219    }
1220
1221    AdvtFilterOnFoundOnLostInfo CreateonTrackAdvFoundLostObject(int client_if, int adv_pkt_len,
1222                    byte[] adv_pkt, int scan_rsp_len, byte[] scan_rsp, int filt_index, int adv_state,
1223                    int adv_info_present, String address, int addr_type, int tx_power, int rssi_value,
1224                    int time_stamp) {
1225
1226        return new AdvtFilterOnFoundOnLostInfo(client_if, adv_pkt_len, adv_pkt,
1227                    scan_rsp_len, scan_rsp, filt_index, adv_state,
1228                    adv_info_present, address, addr_type, tx_power,
1229                    rssi_value, time_stamp);
1230    }
1231
1232    void onTrackAdvFoundLost(AdvtFilterOnFoundOnLostInfo trackingInfo) throws RemoteException {
1233        if (DBG) Log.d(TAG, "onTrackAdvFoundLost() - scannerId= " + trackingInfo.getClientIf()
1234                    + " address = " + trackingInfo.getAddress()
1235                    + " adv_state = " + trackingInfo.getAdvState());
1236
1237        ScannerMap.App app = mScannerMap.getById(trackingInfo.getClientIf());
1238        if (app == null || app.callback == null) {
1239            Log.e(TAG, "app or callback is null");
1240            return;
1241        }
1242
1243        BluetoothDevice device = BluetoothAdapter.getDefaultAdapter()
1244                        .getRemoteDevice(trackingInfo.getAddress());
1245        int advertiserState = trackingInfo.getAdvState();
1246        ScanResult result = new ScanResult(device,
1247                        ScanRecord.parseFromBytes(trackingInfo.getResult()),
1248                        trackingInfo.getRSSIValue(), SystemClock.elapsedRealtimeNanos());
1249
1250        for (ScanClient client : mScanManager.getRegularScanQueue()) {
1251            if (client.scannerId == trackingInfo.getClientIf()) {
1252                ScanSettings settings = client.settings;
1253                if ((advertiserState == ADVT_STATE_ONFOUND)
1254                        && ((settings.getCallbackType()
1255                                & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0)) {
1256                    app.callback.onFoundOrLost(true, result);
1257                } else if ((advertiserState == ADVT_STATE_ONLOST)
1258                                && ((settings.getCallbackType()
1259                                        & ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0)) {
1260                    app.callback.onFoundOrLost(false, result);
1261                } else {
1262                    Log.d(TAG, "Not reporting onlost/onfound : " + advertiserState
1263                                + " scannerId = " + client.scannerId
1264                                + " callbackType " + settings.getCallbackType());
1265                }
1266            }
1267        }
1268    }
1269
1270    void onScanParamSetupCompleted(int status, int scannerId) throws RemoteException {
1271        ScannerMap.App app = mScannerMap.getById(scannerId);
1272        if (app == null || app.callback == null) {
1273            Log.e(TAG, "Advertise app or callback is null");
1274            return;
1275        }
1276        Log.d(TAG, "onScanParamSetupCompleted : " + status);
1277    }
1278
1279    // callback from AdvertiseManager for advertise status dispatch.
1280    void onMultipleAdvertiseCallback(int advertiserId, int status, boolean isStart,
1281            AdvertiseSettings settings) throws RemoteException {
1282        AdvertiserMap.App app = mAdvertiserMap.getById(advertiserId);
1283        if (app == null || app.callback == null) {
1284            Log.e(TAG, "Advertise app or callback is null");
1285            return;
1286        }
1287        if (DBG) Log.d(TAG, "onMultipleAdvertiseCallback : advertiserId: " + advertiserId
1288            + " isStart: " + isStart + " status: " + status);
1289        app.callback.onMultiAdvertiseCallback(status, isStart, settings);
1290    }
1291
1292    // callback from ScanManager for dispatch of errors apps.
1293    void onScanManagerErrorCallback(int scannerId, int errorCode) throws RemoteException {
1294        ScannerMap.App app = mScannerMap.getById(scannerId);
1295        if (app == null || app.callback == null) {
1296            Log.e(TAG, "App or callback is null");
1297            return;
1298        }
1299        app.callback.onScanManagerErrorCallback(errorCode);
1300    }
1301
1302    void onConfigureMTU(int connId, int status, int mtu) throws RemoteException {
1303        String address = mClientMap.addressByConnId(connId);
1304
1305        if (DBG) Log.d(TAG, "onConfigureMTU() address=" + address + ", status="
1306            + status + ", mtu=" + mtu);
1307
1308        ClientMap.App app = mClientMap.getByConnId(connId);
1309        if (app != null) {
1310            app.callback.onConfigureMTU(address, mtu, status);
1311        }
1312    }
1313
1314    // Followings are callbacks for Bluetooth LE Advertise operations.
1315    // Start advertising flow is
1316    //     register advertiser         -> onAdvertiserRegistered
1317    //     enable advertising instance -> onAdvertiseInstaceEnabled
1318    // ->  set advertise data          -> onAdvertiseDataSet
1319    // ->  set scan response           -> onAdvertiseDataSet
1320
1321    void onAdvertiserRegistered(int status, int advertiserId, long uuidLsb, long uuidMsb)
1322            throws RemoteException {
1323        UUID uuid = new UUID(uuidMsb, uuidLsb);
1324        if (DBG) Log.d(TAG, "onAdvertiserRegistered() - UUID=" + uuid
1325                + ", advertiserId=" + advertiserId + ", status=" + status);
1326
1327        AdvertiserMap.App app = mAdvertiserMap.getByUuid(uuid);
1328        if (app != null) {
1329            if (status == 0) {
1330                app.id = advertiserId;
1331                app.linkToDeath(new AdvertiserDeathRecipient(advertiserId));
1332            } else {
1333                mAdvertiserMap.remove(advertiserId);
1334            }
1335            app.callback.onAdvertiserRegistered(status, advertiserId);
1336        }
1337    }
1338
1339    void onAdvertiserStarted(int status, int advertiserId)
1340            throws RemoteException {
1341        if (DBG) Log.d(TAG, "onAdvertiserStarted() - advertiserId=" + advertiserId +
1342            ", status=" + status);
1343
1344        AdvertiserMap.App app = mAdvertiserMap.getById(advertiserId);
1345        if (app != null) {
1346            if (status == 0) {
1347                AdvertiseClient client = mAdvertiseManager.getAdvertiseClient(advertiserId);
1348                AdvertiseSettings settings = (client == null) ? null : client.settings;
1349                app.callback.onMultiAdvertiseCallback(AdvertiseCallback.ADVERTISE_SUCCESS,
1350                        true, settings);
1351            } else {
1352                app.callback.onMultiAdvertiseCallback(
1353                        AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR, true, null);
1354            }
1355        }
1356    }
1357
1358    // Callback when advertise instance is enabled.
1359    void onAdvertiseInstanceEnabled(int status, int advertiserId,
1360                                    boolean enable) throws RemoteException {
1361        if (DBG) Log.d(TAG, "onAdvertiseInstanceEnabled() - "
1362                + "advertiserId=" + advertiserId + ", status=" + status + ", enable=" + enable);
1363
1364        AdvertiserMap.App app = mAdvertiserMap.getById(advertiserId);
1365        if (app != null) {
1366            if (status == 0) {
1367                app.callback.onMultiAdvertiseCallback(AdvertiseCallback.ADVERTISE_SUCCESS,
1368                        enable, null);
1369            } else {
1370                app.callback.onMultiAdvertiseCallback(
1371                        AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR, enable, null);
1372            }
1373        }
1374    }
1375
1376    void onClientCongestion(int connId, boolean congested) throws RemoteException {
1377        if (VDBG) Log.d(TAG, "onClientCongestion() - connId=" + connId + ", congested=" + congested);
1378
1379        ClientMap.App app = mClientMap.getByConnId(connId);
1380
1381        if (app != null) {
1382            app.isCongested = congested;
1383            while(!app.isCongested) {
1384                CallbackInfo callbackInfo = app.popQueuedCallback();
1385                if (callbackInfo == null)  return;
1386                app.callback.onCharacteristicWrite(callbackInfo.address,
1387                        callbackInfo.status, callbackInfo.handle);
1388            }
1389        }
1390    }
1391
1392    /**************************************************************************
1393     * GATT Service functions - Shared CLIENT/SERVER
1394     *************************************************************************/
1395
1396    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
1397        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1398
1399        final int DEVICE_TYPE_BREDR = 0x1;
1400
1401        Map<BluetoothDevice, Integer> deviceStates = new HashMap<BluetoothDevice,
1402                                                                 Integer>();
1403
1404        // Add paired LE devices
1405
1406        Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
1407        for (BluetoothDevice device : bondedDevices) {
1408            if (getDeviceType(device) != DEVICE_TYPE_BREDR) {
1409                deviceStates.put(device, BluetoothProfile.STATE_DISCONNECTED);
1410            }
1411        }
1412
1413        // Add connected deviceStates
1414
1415        Set<String> connectedDevices = new HashSet<String>();
1416        connectedDevices.addAll(mClientMap.getConnectedDevices());
1417        connectedDevices.addAll(mServerMap.getConnectedDevices());
1418
1419        for (String address : connectedDevices ) {
1420            BluetoothDevice device = mAdapter.getRemoteDevice(address);
1421            if (device != null) {
1422                deviceStates.put(device, BluetoothProfile.STATE_CONNECTED);
1423            }
1424        }
1425
1426        // Create matching device sub-set
1427
1428        List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>();
1429
1430        for (Map.Entry<BluetoothDevice, Integer> entry : deviceStates.entrySet()) {
1431            for(int state : states) {
1432                if (entry.getValue() == state) {
1433                    deviceList.add(entry.getKey());
1434                }
1435            }
1436        }
1437
1438        return deviceList;
1439    }
1440
1441    void registerScanner(IScannerCallback callback) {
1442        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1443
1444        UUID uuid = UUID.randomUUID();
1445        if (DBG) Log.d(TAG, "registerScanner() - UUID=" + uuid);
1446        mScannerMap.add(uuid, callback, this);
1447        mScanManager.registerScanner(uuid);
1448    }
1449
1450    void unregisterScanner(int scannerId) {
1451        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1452
1453        if (DBG) Log.d(TAG, "unregisterScanner() - scannerId=" + scannerId);
1454        mScannerMap.remove(scannerId);
1455        mScanManager.unregisterScanner(scannerId);
1456    }
1457
1458    void startScan(int scannerId, ScanSettings settings,
1459            List<ScanFilter> filters, WorkSource workSource,
1460            List<List<ResultStorageDescriptor>> storages, String callingPackage) {
1461        if (DBG) Log.d(TAG, "start scan with filters");
1462        enforceAdminPermission();
1463        if (needsPrivilegedPermissionForScan(settings)) {
1464            enforcePrivilegedPermission();
1465        }
1466        if (workSource != null) {
1467            enforceImpersonatationPermission();
1468        } else {
1469            // Blame the caller if the work source is unspecified.
1470            workSource = new WorkSource(Binder.getCallingUid(), callingPackage);
1471        }
1472        final ScanClient scanClient = new ScanClient(scannerId, settings, filters, workSource,
1473                storages);
1474        scanClient.hasLocationPermission = Utils.checkCallerHasLocationPermission(this, mAppOps,
1475                callingPackage);
1476        scanClient.hasPeersMacAddressPermission = Utils.checkCallerHasPeersMacAddressPermission(
1477                this);
1478        scanClient.legacyForegroundApp = Utils.isLegacyForegroundApp(this, callingPackage);
1479
1480        AppScanStats app = null;
1481        app = mScannerMap.getAppScanStatsById(scannerId);
1482
1483        if (app != null) {
1484            if (app.isScanningTooFrequently() &&
1485                checkCallingOrSelfPermission(BLUETOOTH_PRIVILEGED) != PERMISSION_GRANTED) {
1486                Log.e(TAG, "App '" + app.appName + "' is scanning too frequently");
1487                return;
1488            }
1489            scanClient.stats = app;
1490
1491            boolean isFilteredScan = (filters != null) && !filters.isEmpty();
1492            app.recordScanStart(settings, isFilteredScan);
1493        }
1494
1495        mScanManager.startScan(scanClient);
1496    }
1497
1498    void flushPendingBatchResults(int scannerId) {
1499        if (DBG) Log.d(TAG, "flushPendingBatchResults - scannerId=" + scannerId);
1500        mScanManager.flushBatchScanResults(new ScanClient(scannerId));
1501    }
1502
1503    void stopScan(ScanClient client) {
1504        enforceAdminPermission();
1505        int scanQueueSize = mScanManager.getBatchScanQueue().size() +
1506                mScanManager.getRegularScanQueue().size();
1507        if (DBG) Log.d(TAG, "stopScan() - queue size =" + scanQueueSize);
1508
1509        AppScanStats app = null;
1510        app = mScannerMap.getAppScanStatsById(client.scannerId);
1511        if (app != null) app.recordScanStop();
1512
1513        mScanManager.stopScan(client);
1514    }
1515
1516    void disconnectAll() {
1517        if (DBG) Log.d(TAG, "disconnectAll()");
1518        Map<Integer, String> connMap = mClientMap.getConnectedMap();
1519        for(Map.Entry<Integer, String> entry:connMap.entrySet()){
1520            if (DBG) Log.d(TAG, "disconnecting addr:" + entry.getValue());
1521            clientDisconnect(entry.getKey(), entry.getValue());
1522            //clientDisconnect(int clientIf, String address)
1523        }
1524    }
1525
1526    void unregAll() {
1527        for(ClientMap.App app:mClientMap.mApps){
1528            if (DBG) Log.d(TAG, "unreg:" + app.id);
1529            unregisterClient(app.id);
1530        }
1531    }
1532
1533    /**************************************************************************
1534     * ADVERTISER
1535     *************************************************************************/
1536
1537    void registerAdvertiser(IAdvertiserCallback callback) {
1538        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1539
1540        UUID uuid = UUID.randomUUID();
1541        if (DBG) Log.d(TAG, "registerAdvertiser() - UUID=" + uuid);
1542        mAdvertiserMap.add(uuid, callback, this);
1543        mAdvertiseManager.registerAdvertiser(uuid);
1544    }
1545
1546    void unregisterAdvertiser(int advertiserId) {
1547        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1548
1549        if (DBG) Log.d(TAG, "unregisterAdvertiser() - advertiserId=" + advertiserId);
1550        mAdvertiserMap.remove(advertiserId);
1551        mAdvertiseManager.unregisterAdvertiser(advertiserId);
1552    }
1553
1554    void startMultiAdvertising(int advertiserId, AdvertiseData advertiseData,
1555            AdvertiseData scanResponse, AdvertiseSettings settings) {
1556        enforceAdminPermission();
1557
1558        if (DBG) Log.d(TAG, "startMultiAdvertising() - advertiserId=" + advertiserId);
1559        mAdvertiseManager.startAdvertising(new AdvertiseClient(advertiserId, settings, advertiseData,
1560                scanResponse));
1561    }
1562
1563    void stopMultiAdvertising(AdvertiseClient client) {
1564        enforceAdminPermission();
1565
1566        if (DBG) Log.d(TAG, "stopMultiAdvertising() - advertiserId=" + client.advertiserId);
1567        mAdvertiseManager.stopAdvertising(client);
1568    }
1569
1570    void registerSync(
1571            ScanResult scanResult, int skip, int timeout, IPeriodicAdvertisingCallback callback) {
1572        enforceAdminPermission();
1573        // TODO(jpawlowski): implement
1574    }
1575
1576    void unregisterSync(IPeriodicAdvertisingCallback callback) {
1577        enforceAdminPermission();
1578        // TODO(jpawlowski): implement
1579    }
1580
1581    /**************************************************************************
1582     * ADVERTISING SET
1583     *************************************************************************/
1584
1585    void registerAdvertisingSet(AdvertisingSetParameters parameters, AdvertiseData advertiseData,
1586            AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters,
1587            AdvertiseData periodicData, IAdvertisingSetCallback callback) {
1588        // TODO(jpawlowski): implement
1589    }
1590
1591    /**************************************************************************
1592     * GATT Service functions - CLIENT
1593     *************************************************************************/
1594
1595    void registerClient(UUID uuid, IBluetoothGattCallbackExt callback) {
1596        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1597
1598        if (DBG) Log.d(TAG, "registerClient() - UUID=" + uuid);
1599        mClientMap.add(uuid, callback, this);
1600        gattClientRegisterAppNative(uuid.getLeastSignificantBits(),
1601                                    uuid.getMostSignificantBits());
1602    }
1603
1604    void unregisterClient(int clientIf) {
1605        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1606
1607        if (DBG) Log.d(TAG, "unregisterClient() - clientIf=" + clientIf);
1608        mClientMap.remove(clientIf);
1609        gattClientUnregisterAppNative(clientIf);
1610    }
1611
1612    void clientConnect(int clientIf, String address, boolean isDirect, int transport, int phy) {
1613        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1614
1615        if (DBG) Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect);
1616        // TODO(jpawlowski): propagate PHY!
1617        gattClientConnectNative(clientIf, address, isDirect, transport);
1618    }
1619
1620    void clientDisconnect(int clientIf, String address) {
1621        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1622
1623        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1624        if (DBG) Log.d(TAG, "clientDisconnect() - address=" + address + ", connId=" + connId);
1625
1626        gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0);
1627    }
1628
1629    int numHwTrackFiltersAvailable() {
1630        return (AdapterService.getAdapterService().getTotalNumOfTrackableAdvertisements()
1631                    - mScanManager.getCurrentUsedTrackingAdvertisement());
1632    }
1633
1634    synchronized List<ParcelUuid> getRegisteredServiceUuids() {
1635        Utils.enforceAdminPermission(this);
1636        List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
1637        for (HandleMap.Entry entry : mHandleMap.mEntries) {
1638            serviceUuids.add(new ParcelUuid(entry.uuid));
1639        }
1640        return serviceUuids;
1641    }
1642
1643    List<String> getConnectedDevices() {
1644        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1645
1646        Set<String> connectedDevAddress = new HashSet<String>();
1647        connectedDevAddress.addAll(mClientMap.getConnectedDevices());
1648        connectedDevAddress.addAll(mServerMap.getConnectedDevices());
1649        List<String> connectedDeviceList = new ArrayList<String>(connectedDevAddress);
1650        return connectedDeviceList;
1651    }
1652
1653    void refreshDevice(int clientIf, String address) {
1654        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1655
1656        if (DBG) Log.d(TAG, "refreshDevice() - address=" + address);
1657        gattClientRefreshNative(clientIf, address);
1658    }
1659
1660    void discoverServices(int clientIf, String address) {
1661        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1662
1663        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1664        if (DBG) Log.d(TAG, "discoverServices() - address=" + address + ", connId=" + connId);
1665
1666        if (connId != null)
1667            gattClientSearchServiceNative(connId, true, 0, 0);
1668        else
1669            Log.e(TAG, "discoverServices() - No connection for " + address + "...");
1670    }
1671
1672    void readCharacteristic(int clientIf, String address, int handle, int authReq) {
1673        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1674
1675        if (VDBG) Log.d(TAG, "readCharacteristic() - address=" + address);
1676
1677        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1678        if (connId == null) {
1679            Log.e(TAG, "readCharacteristic() - No connection for " + address + "...");
1680            return;
1681        }
1682
1683        if (!permissionCheck(connId, handle)) {
1684            Log.w(TAG, "readCharacteristic() - permission check failed!");
1685            return;
1686        }
1687
1688        gattClientReadCharacteristicNative(connId, handle, authReq);
1689    }
1690
1691    void writeCharacteristic(int clientIf, String address, int handle, int writeType,
1692                             int authReq, byte[] value) {
1693        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1694
1695        if (VDBG) Log.d(TAG, "writeCharacteristic() - address=" + address);
1696
1697        if (mReliableQueue.contains(address)) writeType = 3; // Prepared write
1698
1699        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1700        if (connId == null) {
1701            Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
1702            return;
1703        }
1704
1705        if (!permissionCheck(connId, handle)) {
1706            Log.w(TAG, "writeCharacteristic() - permission check failed!");
1707            return;
1708        }
1709
1710        gattClientWriteCharacteristicNative(connId, handle, writeType, authReq, value);
1711    }
1712
1713    void readDescriptor(int clientIf, String address, int handle, int authReq) {
1714        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1715
1716        if (VDBG) Log.d(TAG, "readDescriptor() - address=" + address);
1717
1718        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1719        if (connId == null) {
1720            Log.e(TAG, "readDescriptor() - No connection for " + address + "...");
1721            return;
1722        }
1723
1724        if (!permissionCheck(connId, handle)) {
1725            Log.w(TAG, "readDescriptor() - permission check failed!");
1726            return;
1727        }
1728
1729        gattClientReadDescriptorNative(connId, handle, authReq);
1730    };
1731
1732    void writeDescriptor(int clientIf, String address, int handle,
1733                            int authReq, byte[] value) {
1734        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1735        if (VDBG) Log.d(TAG, "writeDescriptor() - address=" + address);
1736
1737        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1738        if (connId == null) {
1739            Log.e(TAG, "writeDescriptor() - No connection for " + address + "...");
1740            return;
1741        }
1742
1743        if (!permissionCheck(connId, handle)) {
1744            Log.w(TAG, "writeDescriptor() - permission check failed!");
1745            return;
1746        }
1747
1748        gattClientWriteDescriptorNative(connId, handle, authReq, value);
1749    }
1750
1751    void beginReliableWrite(int clientIf, String address) {
1752        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1753
1754        if (DBG) Log.d(TAG, "beginReliableWrite() - address=" + address);
1755        mReliableQueue.add(address);
1756    }
1757
1758    void endReliableWrite(int clientIf, String address, boolean execute) {
1759        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1760
1761        if (DBG) Log.d(TAG, "endReliableWrite() - address=" + address
1762                                + " execute: " + execute);
1763        mReliableQueue.remove(address);
1764
1765        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1766        if (connId != null) gattClientExecuteWriteNative(connId, execute);
1767    }
1768
1769    void registerForNotification(int clientIf, String address, int handle, boolean enable) {
1770        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1771
1772        if (DBG) Log.d(TAG, "registerForNotification() - address=" + address + " enable: " + enable);
1773
1774        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1775        if (connId == null) {
1776            Log.e(TAG, "registerForNotification() - No connection for " + address + "...");
1777            return;
1778        }
1779
1780        if (!permissionCheck(connId, handle)) {
1781            Log.w(TAG, "registerForNotification() - permission check failed!");
1782            return;
1783        }
1784
1785        gattClientRegisterForNotificationsNative(clientIf, address, handle, enable);
1786    }
1787
1788    void readRemoteRssi(int clientIf, String address) {
1789        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1790
1791        if (DBG) Log.d(TAG, "readRemoteRssi() - address=" + address);
1792        gattClientReadRemoteRssiNative(clientIf, address);
1793    }
1794
1795    void configureMTU(int clientIf, String address, int mtu) {
1796        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1797
1798        if (DBG) Log.d(TAG, "configureMTU() - address=" + address + " mtu=" + mtu);
1799        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1800        if (connId != null) {
1801            gattClientConfigureMTUNative(connId, mtu);
1802        } else {
1803            Log.e(TAG, "configureMTU() - No connection for " + address + "...");
1804        }
1805    }
1806
1807    void connectionParameterUpdate(int clientIf, String address, int connectionPriority) {
1808        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1809
1810        int minInterval;
1811        int maxInterval;
1812
1813        // Slave latency
1814        int latency;
1815
1816        // Link supervision timeout is measured in N * 10ms
1817        int timeout = 2000; // 20s
1818
1819        switch (connectionPriority)
1820        {
1821            case BluetoothGatt.CONNECTION_PRIORITY_HIGH:
1822                minInterval = getResources().getInteger(R.integer.gatt_high_priority_min_interval);
1823                maxInterval = getResources().getInteger(R.integer.gatt_high_priority_max_interval);
1824                latency = getResources().getInteger(R.integer.gatt_high_priority_latency);
1825                break;
1826
1827            case BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER:
1828                minInterval = getResources().getInteger(R.integer.gatt_low_power_min_interval);
1829                maxInterval = getResources().getInteger(R.integer.gatt_low_power_max_interval);
1830                latency = getResources().getInteger(R.integer.gatt_low_power_latency);
1831                break;
1832
1833            default:
1834                // Using the values for CONNECTION_PRIORITY_BALANCED.
1835                minInterval =
1836                        getResources().getInteger(R.integer.gatt_balanced_priority_min_interval);
1837                maxInterval =
1838                        getResources().getInteger(R.integer.gatt_balanced_priority_max_interval);
1839                latency = getResources().getInteger(R.integer.gatt_balanced_priority_latency);
1840                break;
1841        }
1842
1843        if (DBG) Log.d(TAG, "connectionParameterUpdate() - address=" + address
1844            + "params=" + connectionPriority + " interval=" + minInterval + "/" + maxInterval);
1845        gattConnectionParameterUpdateNative(clientIf, address, minInterval, maxInterval,
1846                                            latency, timeout);
1847    }
1848
1849    /**************************************************************************
1850     * Callback functions - SERVER
1851     *************************************************************************/
1852
1853    void onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb)
1854            throws RemoteException {
1855
1856        UUID uuid = new UUID(uuidMsb, uuidLsb);
1857        if (DBG) Log.d(TAG, "onServerRegistered() - UUID=" + uuid + ", serverIf=" + serverIf);
1858        ServerMap.App app = mServerMap.getByUuid(uuid);
1859        if (app != null) {
1860            app.id = serverIf;
1861            app.linkToDeath(new ServerDeathRecipient(serverIf));
1862            app.callback.onServerRegistered(status, serverIf);
1863        }
1864    }
1865
1866    void onServiceAdded(int status, int serverIf, List<GattDbElement> service)
1867                        throws RemoteException {
1868        if (DBG) Log.d(TAG, "onServiceAdded(), status=" + status);
1869
1870        if (status != 0) {
1871            return;
1872        }
1873
1874        GattDbElement svcEl = service.get(0);
1875        int srvcHandle = svcEl.attributeHandle;
1876
1877        BluetoothGattService svc = null;
1878
1879        for (GattDbElement el : service) {
1880            if (el.type == GattDbElement.TYPE_PRIMARY_SERVICE) {
1881                mHandleMap.addService(serverIf, el.attributeHandle, el.uuid,
1882                        BluetoothGattService.SERVICE_TYPE_PRIMARY, 0, false);
1883                svc = new BluetoothGattService(svcEl.uuid, svcEl.attributeHandle,
1884                        BluetoothGattService.SERVICE_TYPE_PRIMARY);
1885            } else if (el.type == GattDbElement.TYPE_SECONDARY_SERVICE) {
1886                mHandleMap.addService(serverIf, el.attributeHandle, el.uuid,
1887                        BluetoothGattService.SERVICE_TYPE_SECONDARY, 0, false);
1888                svc = new BluetoothGattService(svcEl.uuid, svcEl.attributeHandle,
1889                        BluetoothGattService.SERVICE_TYPE_SECONDARY);
1890            } else if (el.type == GattDbElement.TYPE_CHARACTERISTIC) {
1891                mHandleMap.addCharacteristic(serverIf, el.attributeHandle, el.uuid, srvcHandle);
1892                svc.addCharacteristic(new BluetoothGattCharacteristic(el.uuid,
1893                        el.attributeHandle, el.properties, el.permissions));
1894            } else if (el.type == GattDbElement.TYPE_DESCRIPTOR) {
1895                mHandleMap.addDescriptor(serverIf, el.attributeHandle, el.uuid, srvcHandle);
1896                List<BluetoothGattCharacteristic> chars = svc.getCharacteristics();
1897                chars.get(chars.size()-1).addDescriptor(
1898                        new BluetoothGattDescriptor(el.uuid, el.attributeHandle, el.permissions));
1899            }
1900        }
1901        mHandleMap.setStarted(serverIf, srvcHandle, true);
1902
1903        ServerMap.App app = mServerMap.getById(serverIf);
1904        if (app != null) {
1905                app.callback.onServiceAdded(status, svc);
1906        }
1907    }
1908
1909    void onServiceStopped(int status, int serverIf, int srvcHandle)
1910            throws RemoteException {
1911        if (DBG) Log.d(TAG, "onServiceStopped() srvcHandle=" + srvcHandle
1912            + ", status=" + status);
1913        if (status == 0)
1914            mHandleMap.setStarted(serverIf, srvcHandle, false);
1915        stopNextService(serverIf, status);
1916    }
1917
1918    void onServiceDeleted(int status, int serverIf, int srvcHandle) {
1919        if (DBG) Log.d(TAG, "onServiceDeleted() srvcHandle=" + srvcHandle
1920            + ", status=" + status);
1921        mHandleMap.deleteService(serverIf, srvcHandle);
1922    }
1923
1924    void onClientConnected(String address, boolean connected, int connId, int serverIf)
1925            throws RemoteException {
1926
1927        if (DBG) Log.d(TAG, "onClientConnected() connId=" + connId
1928            + ", address=" + address + ", connected=" + connected);
1929
1930        ServerMap.App app = mServerMap.getById(serverIf);
1931        if (app == null) return;
1932
1933        if (connected) {
1934            mServerMap.addConnection(serverIf, connId, address);
1935        } else {
1936            mServerMap.removeConnection(serverIf, connId);
1937        }
1938
1939        app.callback.onServerConnectionState((byte)0, serverIf, connected, address);
1940    }
1941
1942    void onServerReadCharacteristic(String address, int connId, int transId,
1943                            int handle, int offset, boolean isLong)
1944                            throws RemoteException {
1945        if (VDBG) Log.d(TAG, "onServerReadCharacteristic() connId=" + connId
1946            + ", address=" + address + ", handle=" + handle
1947            + ", requestId=" + transId + ", offset=" + offset);
1948
1949        HandleMap.Entry entry = mHandleMap.getByHandle(handle);
1950        if (entry == null) return;
1951
1952        mHandleMap.addRequest(transId, handle);
1953
1954        ServerMap.App app = mServerMap.getById(entry.serverIf);
1955        if (app == null) return;
1956
1957        app.callback.onCharacteristicReadRequest(address, transId, offset, isLong, handle);
1958    }
1959
1960    void onServerReadDescriptor(String address, int connId, int transId,
1961                            int handle, int offset, boolean isLong)
1962                            throws RemoteException {
1963        if (VDBG) Log.d(TAG, "onServerReadDescriptor() connId=" + connId
1964            + ", address=" + address + ", handle=" + handle
1965            + ", requestId=" + transId + ", offset=" + offset);
1966
1967        HandleMap.Entry entry = mHandleMap.getByHandle(handle);
1968        if (entry == null) return;
1969
1970        mHandleMap.addRequest(transId, handle);
1971
1972        ServerMap.App app = mServerMap.getById(entry.serverIf);
1973        if (app == null) return;
1974
1975        app.callback.onDescriptorReadRequest(address, transId, offset, isLong, handle);
1976    }
1977
1978    void onServerWriteCharacteristic(String address, int connId, int transId,
1979                            int handle, int offset, int length,
1980                            boolean needRsp, boolean isPrep,
1981                            byte[] data)
1982                            throws RemoteException {
1983        if (VDBG) Log.d(TAG, "onServerWriteCharacteristic() connId=" + connId
1984            + ", address=" + address + ", handle=" + handle
1985            + ", requestId=" + transId + ", isPrep=" + isPrep
1986            + ", offset=" + offset);
1987
1988        HandleMap.Entry entry = mHandleMap.getByHandle(handle);
1989        if (entry == null) return;
1990
1991        mHandleMap.addRequest(transId, handle);
1992
1993        ServerMap.App app = mServerMap.getById(entry.serverIf);
1994        if (app == null) return;
1995
1996        app.callback.onCharacteristicWriteRequest(address, transId,
1997                    offset, length, isPrep, needRsp, handle, data);
1998    }
1999
2000    void onServerWriteDescriptor(String address, int connId, int transId,
2001                            int handle, int offset, int length,
2002                            boolean needRsp, boolean isPrep,
2003                            byte[] data)
2004                            throws RemoteException {
2005        if (VDBG) Log.d(TAG, "onAttributeWrite() connId=" + connId
2006            + ", address=" + address + ", handle=" + handle
2007            + ", requestId=" + transId + ", isPrep=" + isPrep
2008            + ", offset=" + offset);
2009
2010        HandleMap.Entry entry = mHandleMap.getByHandle(handle);
2011        if (entry == null) return;
2012
2013        mHandleMap.addRequest(transId, handle);
2014
2015        ServerMap.App app = mServerMap.getById(entry.serverIf);
2016        if (app == null) return;
2017
2018        app.callback.onDescriptorWriteRequest(address, transId,
2019                    offset, length, isPrep, needRsp, handle, data);
2020    }
2021
2022    void onExecuteWrite(String address, int connId, int transId, int execWrite)
2023            throws RemoteException {
2024        if (DBG) Log.d(TAG, "onExecuteWrite() connId=" + connId
2025            + ", address=" + address + ", transId=" + transId);
2026
2027        ServerMap.App app = mServerMap.getByConnId(connId);
2028        if (app == null) return;
2029
2030        app.callback.onExecuteWrite(address, transId, execWrite == 1);
2031    }
2032
2033    void onResponseSendCompleted(int status, int attrHandle) {
2034        if (DBG) Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle);
2035    }
2036
2037    void onNotificationSent(int connId, int status) throws RemoteException {
2038        if (VDBG) Log.d(TAG, "onNotificationSent() connId=" + connId + ", status=" + status);
2039
2040        String address = mServerMap.addressByConnId(connId);
2041        if (address == null) return;
2042
2043        ServerMap.App app = mServerMap.getByConnId(connId);
2044        if (app == null) return;
2045
2046        if (!app.isCongested) {
2047            app.callback.onNotificationSent(address, status);
2048        } else {
2049            if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) {
2050                status = BluetoothGatt.GATT_SUCCESS;
2051            }
2052            app.queueCallback(new CallbackInfo(address, status));
2053        }
2054    }
2055
2056    void onServerCongestion(int connId, boolean congested) throws RemoteException {
2057        if (DBG) Log.d(TAG, "onServerCongestion() - connId=" + connId + ", congested=" + congested);
2058
2059        ServerMap.App app = mServerMap.getByConnId(connId);
2060        if (app == null) return;
2061
2062        app.isCongested = congested;
2063        while(!app.isCongested) {
2064            CallbackInfo callbackInfo = app.popQueuedCallback();
2065            if (callbackInfo == null) return;
2066            app.callback.onNotificationSent(callbackInfo.address, callbackInfo.status);
2067        }
2068    }
2069
2070    void onMtuChanged(int connId, int mtu) throws RemoteException {
2071        if (DBG) Log.d(TAG, "onMtuChanged() - connId=" + connId + ", mtu=" + mtu);
2072
2073        String address = mServerMap.addressByConnId(connId);
2074        if (address == null) return;
2075
2076        ServerMap.App app = mServerMap.getByConnId(connId);
2077        if (app == null) return;
2078
2079        app.callback.onMtuChanged(address, mtu);
2080    }
2081
2082    /**************************************************************************
2083     * GATT Service functions - SERVER
2084     *************************************************************************/
2085
2086    void registerServer(UUID uuid, IBluetoothGattServerCallbackExt callback) {
2087        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2088
2089        if (DBG) Log.d(TAG, "registerServer() - UUID=" + uuid);
2090        mServerMap.add(uuid, callback, this);
2091        gattServerRegisterAppNative(uuid.getLeastSignificantBits(),
2092                                    uuid.getMostSignificantBits());
2093    }
2094
2095    void unregisterServer(int serverIf) {
2096        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2097
2098        if (DBG) Log.d(TAG, "unregisterServer() - serverIf=" + serverIf);
2099
2100        deleteServices(serverIf);
2101
2102        mServerMap.remove(serverIf);
2103        gattServerUnregisterAppNative(serverIf);
2104    }
2105
2106    void serverConnect(int serverIf, String address, boolean isDirect, int transport) {
2107        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2108
2109        if (DBG) Log.d(TAG, "serverConnect() - address=" + address);
2110        gattServerConnectNative(serverIf, address, isDirect,transport);
2111    }
2112
2113    void serverDisconnect(int serverIf, String address) {
2114        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2115
2116        Integer connId = mServerMap.connIdByAddress(serverIf, address);
2117        if (DBG) Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId);
2118
2119        gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0);
2120    }
2121
2122    void addService(int serverIf, BluetoothGattService service) {
2123        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2124
2125        if (DBG) Log.d(TAG, "addService() - uuid=" + service.getUuid());
2126
2127        List<GattDbElement> db = new ArrayList<GattDbElement>();
2128
2129        if (service.getType() == BluetoothGattService.SERVICE_TYPE_PRIMARY)
2130            db.add(GattDbElement.createPrimaryService(service.getUuid()));
2131        else db.add(GattDbElement.createSecondaryService(service.getUuid()));
2132
2133        for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
2134            int permission = ((characteristic.getKeySize() - 7) << 12)
2135                                    + characteristic.getPermissions();
2136            db.add(GattDbElement.createCharacteristic(characteristic.getUuid(),
2137                 characteristic.getProperties(), permission));
2138
2139            for (BluetoothGattDescriptor descriptor: characteristic.getDescriptors()) {
2140                permission = ((characteristic.getKeySize() - 7) << 12)
2141                                    + descriptor.getPermissions();
2142                db.add(GattDbElement.createDescriptor(descriptor.getUuid(), permission));
2143            }
2144        }
2145
2146        for (BluetoothGattService includedService : service.getIncludedServices()) {
2147            int inclSrvc = mHandleMap.getServiceHandle(includedService.getUuid(),
2148                    includedService.getType(), includedService.getInstanceId());
2149            db.add(GattDbElement.createIncludedService(inclSrvc));
2150        }
2151
2152        gattServerAddServiceNative(serverIf, db);
2153    }
2154
2155    void removeService(int serverIf, int handle) {
2156        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2157
2158        if (DBG) Log.d(TAG, "removeService() - handle=" + handle);
2159
2160        gattServerDeleteServiceNative(serverIf, handle);
2161    }
2162
2163    void clearServices(int serverIf) {
2164        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2165
2166        if (DBG) Log.d(TAG, "clearServices()");
2167        deleteServices(serverIf);
2168    }
2169
2170    void sendResponse(int serverIf, String address, int requestId,
2171                      int status, int offset, byte[] value) {
2172        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2173
2174        if (VDBG) Log.d(TAG, "sendResponse() - address=" + address);
2175
2176        int handle = 0;
2177        HandleMap.Entry entry = mHandleMap.getByRequestId(requestId);
2178        if (entry != null) handle = entry.handle;
2179
2180        int connId = mServerMap.connIdByAddress(serverIf, address);
2181        gattServerSendResponseNative(serverIf, connId, requestId, (byte)status,
2182                                     handle, offset, value, (byte)0);
2183        mHandleMap.deleteRequest(requestId);
2184    }
2185
2186    void sendNotification(int serverIf, String address, int handle, boolean confirm, byte[] value) {
2187        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2188
2189        if (VDBG) Log.d(TAG, "sendNotification() - address=" + address + " handle=" + handle);
2190
2191        int connId = mServerMap.connIdByAddress(serverIf, address);
2192        if (connId == 0) return;
2193
2194        if (confirm) {
2195            gattServerSendIndicationNative(serverIf, handle, connId, value);
2196        } else {
2197            gattServerSendNotificationNative(serverIf, handle, connId, value);
2198        }
2199    }
2200
2201
2202    /**************************************************************************
2203     * Private functions
2204     *************************************************************************/
2205
2206    private boolean isRestrictedCharUuid(final UUID charUuid) {
2207      return isHidUuid(charUuid);
2208    }
2209
2210    private boolean isRestrictedSrvcUuid(final UUID srvcUuid) {
2211      return isFidoUUID(srvcUuid);
2212    }
2213
2214    private boolean isHidUuid(final UUID uuid) {
2215        for (UUID hid_uuid : HID_UUIDS) {
2216            if (hid_uuid.equals(uuid)) return true;
2217        }
2218        return false;
2219    }
2220
2221    private boolean isFidoUUID(final UUID uuid) {
2222        for (UUID fido_uuid : FIDO_UUIDS) {
2223            if (fido_uuid.equals(uuid)) return true;
2224        }
2225        return false;
2226    }
2227
2228    private int getDeviceType(BluetoothDevice device) {
2229        int type = gattClientGetDeviceTypeNative(device.getAddress());
2230        if (DBG) Log.d(TAG, "getDeviceType() - device=" + device
2231            + ", type=" + type);
2232        return type;
2233    }
2234
2235    private void enforceAdminPermission() {
2236        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
2237    }
2238
2239    private boolean needsPrivilegedPermissionForScan(ScanSettings settings) {
2240        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2241        // BLE scan only mode needs special permission.
2242        if (adapter.getState() != BluetoothAdapter.STATE_ON) return true;
2243
2244        // Regular scan, no special permission.
2245        if (settings == null) return false;
2246
2247        // Regular scan, no special permission.
2248        if (settings.getReportDelayMillis() == 0) return false;
2249
2250        // Batch scan, truncated mode needs permission.
2251        return settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_ABBREVIATED;
2252    }
2253
2254    // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be
2255    // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission.
2256    private void enforcePrivilegedPermission() {
2257        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
2258            "Need BLUETOOTH_PRIVILEGED permission");
2259    }
2260
2261    // Enforce caller has UPDATE_DEVICE_STATS permission, which allows the caller to blame other
2262    // apps for Bluetooth usage. A {@link SecurityException} will be thrown if the caller app does
2263    // not have UPDATE_DEVICE_STATS permission.
2264    private void enforceImpersonatationPermission() {
2265        enforceCallingOrSelfPermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
2266                "Need UPDATE_DEVICE_STATS permission");
2267    }
2268
2269    private void stopNextService(int serverIf, int status) throws RemoteException {
2270        if (DBG) Log.d(TAG, "stopNextService() - serverIf=" + serverIf
2271            + ", status=" + status);
2272
2273        if (status == 0) {
2274            List<HandleMap.Entry> entries = mHandleMap.getEntries();
2275            for(HandleMap.Entry entry : entries) {
2276                if (entry.type != HandleMap.TYPE_SERVICE ||
2277                    entry.serverIf != serverIf ||
2278                    entry.started == false)
2279                        continue;
2280
2281                gattServerStopServiceNative(serverIf, entry.handle);
2282                return;
2283            }
2284        }
2285    }
2286
2287    private void deleteServices(int serverIf) {
2288        if (DBG) Log.d(TAG, "deleteServices() - serverIf=" + serverIf);
2289
2290        /*
2291         * Figure out which handles to delete.
2292         * The handles are copied into a new list to avoid race conditions.
2293         */
2294        List<Integer> handleList = new ArrayList<Integer>();
2295        List<HandleMap.Entry> entries = mHandleMap.getEntries();
2296        for(HandleMap.Entry entry : entries) {
2297            if (entry.type != HandleMap.TYPE_SERVICE ||
2298                entry.serverIf != serverIf)
2299                    continue;
2300            handleList.add(entry.handle);
2301        }
2302
2303        /* Now actually delete the services.... */
2304        for(Integer handle : handleList) {
2305            gattServerDeleteServiceNative(serverIf, handle);
2306        }
2307    }
2308
2309    private List<UUID> parseUuids(byte[] adv_data) {
2310        List<UUID> uuids = new ArrayList<UUID>();
2311
2312        int offset = 0;
2313        while(offset < (adv_data.length-2)) {
2314            int len = adv_data[offset++];
2315            if (len == 0) break;
2316
2317            int type = adv_data[offset++];
2318            switch (type) {
2319                case 0x02: // Partial list of 16-bit UUIDs
2320                case 0x03: // Complete list of 16-bit UUIDs
2321                    while (len > 1) {
2322                        int uuid16 = adv_data[offset++];
2323                        uuid16 += (adv_data[offset++] << 8);
2324                        len -= 2;
2325                        uuids.add(UUID.fromString(String.format(
2326                            "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
2327                    }
2328                    break;
2329
2330                default:
2331                    offset += (len - 1);
2332                    break;
2333            }
2334        }
2335
2336        return uuids;
2337    }
2338
2339    @Override
2340    public void dump(StringBuilder sb) {
2341        super.dump(sb);
2342        println(sb, "mAdvertisingServiceUuids:");
2343        for (UUID uuid : mAdvertisingServiceUuids) {
2344            println(sb, "  " + uuid);
2345        }
2346
2347        println(sb, "mMaxScanFilters: " + mMaxScanFilters);
2348
2349        sb.append("\nGATT Scanner Map\n");
2350        mScannerMap.dump(sb);
2351
2352        sb.append("GATT Client Map\n");
2353        mClientMap.dump(sb);
2354
2355        sb.append("GATT Server Map\n");
2356        mServerMap.dump(sb);
2357
2358        sb.append("GATT Handle Map\n");
2359        mHandleMap.dump(sb);
2360    }
2361
2362    void addScanResult() {
2363        if (mScanEvents.isEmpty())
2364            return;
2365
2366        BluetoothProto.ScanEvent curr = mScanEvents.get(mScanEvents.size() - 1);
2367        curr.setNumberResults(curr.getNumberResults() + 1);
2368    }
2369
2370    void addScanEvent(BluetoothProto.ScanEvent event) {
2371        synchronized(mScanEvents) {
2372            if (mScanEvents.size() == NUM_SCAN_EVENTS_KEPT)
2373                mScanEvents.remove(0);
2374            mScanEvents.add(event);
2375        }
2376    }
2377
2378    @Override
2379    public void dumpProto(BluetoothProto.BluetoothLog proto) {
2380        synchronized(mScanEvents) {
2381            for (BluetoothProto.ScanEvent event : mScanEvents) {
2382                proto.addScanEvent(event);
2383            }
2384        }
2385    }
2386
2387    /**************************************************************************
2388     * GATT Test functions
2389     *************************************************************************/
2390
2391    void gattTestCommand(int command, UUID uuid1, String bda1,
2392                         int p1, int p2, int p3, int p4, int p5) {
2393        if (bda1 == null) bda1 = "00:00:00:00:00:00";
2394        if (uuid1 != null)
2395            gattTestNative(command, uuid1.getLeastSignificantBits(),
2396                       uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5);
2397        else
2398            gattTestNative(command, 0,0, bda1, p1, p2, p3, p4, p5);
2399    }
2400
2401    private native void gattTestNative(int command,
2402                                    long uuid1_lsb, long uuid1_msb, String bda1,
2403                                    int p1, int p2, int p3, int p4, int p5);
2404
2405    /**************************************************************************
2406     * Native functions prototypes
2407     *************************************************************************/
2408
2409    private native static void classInitNative();
2410    private native void initializeNative();
2411    private native void cleanupNative();
2412
2413    private native int gattClientGetDeviceTypeNative(String address);
2414
2415    private native void gattClientRegisterAppNative(long app_uuid_lsb,
2416                                                    long app_uuid_msb);
2417
2418    private native void gattClientUnregisterAppNative(int clientIf);
2419
2420    private native void gattClientConnectNative(int clientIf, String address,
2421            boolean isDirect, int transport);
2422
2423    private native void gattClientDisconnectNative(int clientIf, String address,
2424            int conn_id);
2425
2426    private native void gattClientRefreshNative(int clientIf, String address);
2427
2428    private native void gattClientSearchServiceNative(int conn_id,
2429            boolean search_all, long service_uuid_lsb, long service_uuid_msb);
2430
2431    private native void gattClientGetGattDbNative(int conn_id);
2432
2433    private native void gattClientReadCharacteristicNative(int conn_id, int handle, int authReq);
2434
2435    private native void gattClientReadDescriptorNative(int conn_id, int handle, int authReq);
2436
2437    private native void gattClientWriteCharacteristicNative(int conn_id,
2438            int handle, int write_type, int auth_req, byte[] value);
2439
2440    private native void gattClientWriteDescriptorNative(int conn_id, int handle,
2441            int auth_req, byte[] value);
2442
2443    private native void gattClientExecuteWriteNative(int conn_id, boolean execute);
2444
2445    private native void gattClientRegisterForNotificationsNative(int clientIf,
2446            String address, int handle, boolean enable);
2447
2448    private native void gattClientReadRemoteRssiNative(int clientIf,
2449            String address);
2450
2451    private native void gattClientConfigureMTUNative(int conn_id, int mtu);
2452
2453    private native void gattConnectionParameterUpdateNative(int client_if, String address,
2454            int minInterval, int maxInterval, int latency, int timeout);
2455
2456    private native void gattServerRegisterAppNative(long app_uuid_lsb,
2457                                                    long app_uuid_msb);
2458
2459    private native void gattServerUnregisterAppNative(int serverIf);
2460
2461    private native void gattServerConnectNative(int server_if, String address,
2462                                             boolean is_direct, int transport);
2463
2464    private native void gattServerDisconnectNative(int serverIf, String address,
2465                                              int conn_id);
2466
2467    private native void gattServerAddServiceNative(int server_if, List<GattDbElement> service);
2468
2469    private native void gattServerStopServiceNative (int server_if,
2470                                                     int svc_handle);
2471
2472    private native void gattServerDeleteServiceNative (int server_if,
2473                                                       int svc_handle);
2474
2475    private native void gattServerSendIndicationNative (int server_if,
2476            int attr_handle, int conn_id, byte[] val);
2477
2478    private native void gattServerSendNotificationNative (int server_if,
2479            int attr_handle, int conn_id, byte[] val);
2480
2481    private native void gattServerSendResponseNative (int server_if,
2482            int conn_id, int trans_id, int status, int handle, int offset,
2483            byte[] val, int auth_req);
2484}
2485