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