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