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