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