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