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