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        gattClientUnregisterAppNative(clientIf);
1395    }
1396
1397    void clientConnect(int clientIf, String address, boolean isDirect, int transport) {
1398        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1399
1400        if (DBG) Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect);
1401        gattClientConnectNative(clientIf, address, isDirect, transport);
1402    }
1403
1404    void clientDisconnect(int clientIf, String address) {
1405        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1406
1407        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1408        if (DBG) Log.d(TAG, "clientDisconnect() - address=" + address + ", connId=" + connId);
1409
1410        gattClientDisconnectNative(clientIf, address, connId != null ? connId : 0);
1411    }
1412
1413    void startMultiAdvertising(int clientIf, AdvertiseData advertiseData,
1414            AdvertiseData scanResponse, AdvertiseSettings settings) {
1415        enforceAdminPermission();
1416        mAdvertiseManager.startAdvertising(new AdvertiseClient(clientIf, settings, advertiseData,
1417                scanResponse));
1418    }
1419
1420    void stopMultiAdvertising(AdvertiseClient client) {
1421        enforceAdminPermission();
1422        mAdvertiseManager.stopAdvertising(client);
1423    }
1424
1425    int numHwTrackFiltersAvailable() {
1426        return (AdapterService.getAdapterService().getTotalNumOfTrackableAdvertisements()
1427                    - mScanManager.getCurrentUsedTrackingAdvertisement());
1428    }
1429
1430    synchronized List<ParcelUuid> getRegisteredServiceUuids() {
1431        Utils.enforceAdminPermission(this);
1432        List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
1433        for (HandleMap.Entry entry : mHandleMap.mEntries) {
1434            serviceUuids.add(new ParcelUuid(entry.uuid));
1435        }
1436        return serviceUuids;
1437    }
1438
1439    List<String> getConnectedDevices() {
1440        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1441
1442        Set<String> connectedDevAddress = new HashSet<String>();
1443        connectedDevAddress.addAll(mClientMap.getConnectedDevices());
1444        connectedDevAddress.addAll(mServerMap.getConnectedDevices());
1445        List<String> connectedDeviceList = new ArrayList<String>(connectedDevAddress);
1446        return connectedDeviceList;
1447    }
1448
1449    void refreshDevice(int clientIf, String address) {
1450        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1451
1452        if (DBG) Log.d(TAG, "refreshDevice() - address=" + address);
1453        gattClientRefreshNative(clientIf, address);
1454    }
1455
1456    void discoverServices(int clientIf, String address) {
1457        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1458
1459        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1460        if (DBG) Log.d(TAG, "discoverServices() - address=" + address + ", connId=" + connId);
1461
1462        if (connId != null)
1463            gattClientSearchServiceNative(connId, true, 0, 0);
1464        else
1465            Log.e(TAG, "discoverServices() - No connection for " + address + "...");
1466    }
1467
1468    void readCharacteristic(int clientIf, String address, int handle, int authReq) {
1469        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1470
1471        if (VDBG) Log.d(TAG, "readCharacteristic() - address=" + address);
1472
1473        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1474        if (connId == null) {
1475            Log.e(TAG, "readCharacteristic() - No connection for " + address + "...");
1476            return;
1477        }
1478
1479        if (!permissionCheck(connId, handle)) {
1480            Log.w(TAG, "readCharacteristic() - permission check failed!");
1481            return;
1482        }
1483
1484        gattClientReadCharacteristicNative(connId, handle, authReq);
1485    }
1486
1487    void writeCharacteristic(int clientIf, String address, int handle, int writeType,
1488                             int authReq, byte[] value) {
1489        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1490
1491        if (VDBG) Log.d(TAG, "writeCharacteristic() - address=" + address);
1492
1493        if (mReliableQueue.contains(address)) writeType = 3; // Prepared write
1494
1495        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1496        if (connId == null) {
1497            Log.e(TAG, "writeCharacteristic() - No connection for " + address + "...");
1498            return;
1499        }
1500
1501        if (!permissionCheck(connId, handle)) {
1502            Log.w(TAG, "writeCharacteristic() - permission check failed!");
1503            return;
1504        }
1505
1506        gattClientWriteCharacteristicNative(connId, handle, writeType, authReq, value);
1507    }
1508
1509    void readDescriptor(int clientIf, String address, int handle, int authReq) {
1510        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1511
1512        if (VDBG) Log.d(TAG, "readDescriptor() - address=" + address);
1513
1514        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1515        if (connId == null) {
1516            Log.e(TAG, "readDescriptor() - No connection for " + address + "...");
1517            return;
1518        }
1519
1520        if (!permissionCheck(connId, handle)) {
1521            Log.w(TAG, "readDescriptor() - permission check failed!");
1522            return;
1523        }
1524
1525        gattClientReadDescriptorNative(connId, handle, authReq);
1526    };
1527
1528    void writeDescriptor(int clientIf, String address, int handle,
1529                            int writeType, int authReq, byte[] value) {
1530        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1531        if (VDBG) Log.d(TAG, "writeDescriptor() - address=" + address);
1532
1533        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1534        if (connId == null) {
1535            Log.e(TAG, "writeDescriptor() - No connection for " + address + "...");
1536            return;
1537        }
1538
1539        if (!permissionCheck(connId, handle)) {
1540            Log.w(TAG, "writeDescriptor() - permission check failed!");
1541            return;
1542        }
1543
1544        gattClientWriteDescriptorNative(connId, handle, writeType, authReq, value);
1545    }
1546
1547    void beginReliableWrite(int clientIf, String address) {
1548        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1549
1550        if (DBG) Log.d(TAG, "beginReliableWrite() - address=" + address);
1551        mReliableQueue.add(address);
1552    }
1553
1554    void endReliableWrite(int clientIf, String address, boolean execute) {
1555        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1556
1557        if (DBG) Log.d(TAG, "endReliableWrite() - address=" + address
1558                                + " execute: " + execute);
1559        mReliableQueue.remove(address);
1560
1561        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1562        if (connId != null) gattClientExecuteWriteNative(connId, execute);
1563    }
1564
1565    void registerForNotification(int clientIf, String address, int handle, boolean enable) {
1566        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1567
1568        if (DBG) Log.d(TAG, "registerForNotification() - address=" + address + " enable: " + enable);
1569
1570        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1571        if (connId == null) {
1572            Log.e(TAG, "registerForNotification() - No connection for " + address + "...");
1573            return;
1574        }
1575
1576        if (!permissionCheck(connId, handle)) {
1577            Log.w(TAG, "registerForNotification() - permission check failed!");
1578            return;
1579        }
1580
1581        gattClientRegisterForNotificationsNative(clientIf, address, handle, enable);
1582    }
1583
1584    void readRemoteRssi(int clientIf, String address) {
1585        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1586
1587        if (DBG) Log.d(TAG, "readRemoteRssi() - address=" + address);
1588        gattClientReadRemoteRssiNative(clientIf, address);
1589    }
1590
1591    void configureMTU(int clientIf, String address, int mtu) {
1592        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1593
1594        if (DBG) Log.d(TAG, "configureMTU() - address=" + address + " mtu=" + mtu);
1595        Integer connId = mClientMap.connIdByAddress(clientIf, address);
1596        if (connId != null) {
1597            gattClientConfigureMTUNative(connId, mtu);
1598        } else {
1599            Log.e(TAG, "configureMTU() - No connection for " + address + "...");
1600        }
1601    }
1602
1603    void connectionParameterUpdate(int clientIf, String address, int connectionPriority) {
1604        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1605
1606        int minInterval;
1607        int maxInterval;
1608
1609        // Slave latency
1610        int latency;
1611
1612        // Link supervision timeout is measured in N * 10ms
1613        int timeout = 2000; // 20s
1614
1615        switch (connectionPriority)
1616        {
1617            case BluetoothGatt.CONNECTION_PRIORITY_HIGH:
1618                minInterval = getResources().getInteger(R.integer.gatt_high_priority_min_interval);
1619                maxInterval = getResources().getInteger(R.integer.gatt_high_priority_max_interval);
1620                latency = getResources().getInteger(R.integer.gatt_high_priority_latency);
1621                break;
1622
1623            case BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER:
1624                minInterval = getResources().getInteger(R.integer.gatt_low_power_min_interval);
1625                maxInterval = getResources().getInteger(R.integer.gatt_low_power_max_interval);
1626                latency = getResources().getInteger(R.integer.gatt_low_power_latency);
1627                break;
1628
1629            default:
1630                // Using the values for CONNECTION_PRIORITY_BALANCED.
1631                minInterval =
1632                        getResources().getInteger(R.integer.gatt_balanced_priority_min_interval);
1633                maxInterval =
1634                        getResources().getInteger(R.integer.gatt_balanced_priority_max_interval);
1635                latency = getResources().getInteger(R.integer.gatt_balanced_priority_latency);
1636                break;
1637        }
1638
1639        if (DBG) Log.d(TAG, "connectionParameterUpdate() - address=" + address
1640            + "params=" + connectionPriority + " interval=" + minInterval + "/" + maxInterval);
1641        gattConnectionParameterUpdateNative(clientIf, address, minInterval, maxInterval,
1642                                            latency, timeout);
1643    }
1644
1645    /**************************************************************************
1646     * Callback functions - SERVER
1647     *************************************************************************/
1648
1649    void onServerRegistered(int status, int serverIf, long uuidLsb, long uuidMsb)
1650            throws RemoteException {
1651
1652        UUID uuid = new UUID(uuidMsb, uuidLsb);
1653        if (DBG) Log.d(TAG, "onServerRegistered() - UUID=" + uuid + ", serverIf=" + serverIf);
1654        ServerMap.App app = mServerMap.getByUuid(uuid);
1655        if (app != null) {
1656            app.id = serverIf;
1657            app.linkToDeath(new ServerDeathRecipient(serverIf));
1658            app.callback.onServerRegistered(status, serverIf);
1659        }
1660    }
1661
1662    void onServiceAdded(int status, int serverIf, int srvcType, int srvcInstId,
1663                        long srvcUuidLsb, long srvcUuidMsb, int srvcHandle)
1664                        throws RemoteException {
1665        UUID uuid = new UUID(srvcUuidMsb, srvcUuidLsb);
1666        if (DBG) Log.d(TAG, "onServiceAdded() UUID=" + uuid + ", status=" + status
1667            + ", handle=" + srvcHandle);
1668        if (status == 0) {
1669            mHandleMap.addService(serverIf, srvcHandle, uuid, srvcType, srvcInstId,
1670                mAdvertisingServiceUuids.remove(uuid));
1671        }
1672
1673        continueServiceDeclaration(serverIf, status, srvcHandle);
1674    }
1675
1676    void onIncludedServiceAdded(int status, int serverIf, int srvcHandle,
1677                                int includedSrvcHandle) throws RemoteException {
1678        if (DBG) Log.d(TAG, "onIncludedServiceAdded() status=" + status
1679            + ", service=" + srvcHandle + ", included=" + includedSrvcHandle);
1680        continueServiceDeclaration(serverIf, status, srvcHandle);
1681    }
1682
1683    void onCharacteristicAdded(int status, int serverIf,
1684                               long charUuidLsb, long charUuidMsb,
1685                               int srvcHandle, int charHandle)
1686                               throws RemoteException {
1687            UUID uuid = new UUID(charUuidMsb, charUuidLsb);
1688        if (DBG) Log.d(TAG, "onCharacteristicAdded() UUID=" + uuid + ", status=" + status
1689            + ", srvcHandle=" + srvcHandle + ", charHandle=" + charHandle);
1690        if (status == 0)
1691            mHandleMap.addCharacteristic(serverIf, charHandle, uuid, srvcHandle);
1692        continueServiceDeclaration(serverIf, status, srvcHandle);
1693    }
1694
1695    void onDescriptorAdded(int status, int serverIf,
1696                           long descrUuidLsb, long descrUuidMsb,
1697                           int srvcHandle, int descrHandle)
1698                           throws RemoteException {
1699            UUID uuid = new UUID(descrUuidMsb, descrUuidLsb);
1700        if (DBG) Log.d(TAG, "onDescriptorAdded() UUID=" + uuid + ", status=" + status
1701            + ", srvcHandle=" + srvcHandle + ", descrHandle=" + descrHandle);
1702        if (status == 0)
1703            mHandleMap.addDescriptor(serverIf, descrHandle, uuid, srvcHandle);
1704        continueServiceDeclaration(serverIf, status, srvcHandle);
1705    }
1706
1707    void onServiceStarted(int status, int serverIf, int srvcHandle)
1708            throws RemoteException {
1709        if (DBG) Log.d(TAG, "onServiceStarted() srvcHandle=" + srvcHandle
1710            + ", status=" + status);
1711        if (status == 0)
1712            mHandleMap.setStarted(serverIf, srvcHandle, true);
1713    }
1714
1715    void onServiceStopped(int status, int serverIf, int srvcHandle)
1716            throws RemoteException {
1717        if (DBG) Log.d(TAG, "onServiceStopped() srvcHandle=" + srvcHandle
1718            + ", status=" + status);
1719        if (status == 0)
1720            mHandleMap.setStarted(serverIf, srvcHandle, false);
1721        stopNextService(serverIf, status);
1722    }
1723
1724    void onServiceDeleted(int status, int serverIf, int srvcHandle) {
1725        if (DBG) Log.d(TAG, "onServiceDeleted() srvcHandle=" + srvcHandle
1726            + ", status=" + status);
1727        mHandleMap.deleteService(serverIf, srvcHandle);
1728    }
1729
1730    void onClientConnected(String address, boolean connected, int connId, int serverIf)
1731            throws RemoteException {
1732
1733        if (DBG) Log.d(TAG, "onConnected() connId=" + connId
1734            + ", address=" + address + ", connected=" + connected);
1735
1736        ServerMap.App app = mServerMap.getById(serverIf);
1737        if (app == null) return;
1738
1739        if (connected) {
1740            mServerMap.addConnection(serverIf, connId, address);
1741        } else {
1742            mServerMap.removeConnection(serverIf, connId);
1743        }
1744
1745        app.callback.onServerConnectionState((byte)0, serverIf, connected, address);
1746    }
1747
1748    void onAttributeRead(String address, int connId, int transId,
1749                            int attrHandle, int offset, boolean isLong)
1750                            throws RemoteException {
1751        if (VDBG) Log.d(TAG, "onAttributeRead() connId=" + connId
1752            + ", address=" + address + ", handle=" + attrHandle
1753            + ", requestId=" + transId + ", offset=" + offset);
1754
1755        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1756        if (entry == null) return;
1757
1758        mHandleMap.addRequest(transId, attrHandle);
1759
1760        ServerMap.App app = mServerMap.getById(entry.serverIf);
1761        if (app == null) return;
1762
1763        switch(entry.type) {
1764            case HandleMap.TYPE_CHARACTERISTIC:
1765            {
1766                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1767                app.callback.onCharacteristicReadRequest(address, transId, offset, isLong,
1768                    serviceEntry.serviceType, serviceEntry.instance,
1769                    new ParcelUuid(serviceEntry.uuid), entry.instance,
1770                    new ParcelUuid(entry.uuid));
1771                break;
1772            }
1773
1774            case HandleMap.TYPE_DESCRIPTOR:
1775            {
1776                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1777                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1778                app.callback.onDescriptorReadRequest(address, transId, offset, isLong,
1779                    serviceEntry.serviceType, serviceEntry.instance,
1780                    new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1781                    new ParcelUuid(charEntry.uuid),
1782                    new ParcelUuid(entry.uuid));
1783                break;
1784            }
1785
1786            default:
1787                Log.e(TAG, "onAttributeRead() - Requested unknown attribute type.");
1788                break;
1789        }
1790    }
1791
1792    void onAttributeWrite(String address, int connId, int transId,
1793                            int attrHandle, int offset, int length,
1794                            boolean needRsp, boolean isPrep,
1795                            byte[] data)
1796                            throws RemoteException {
1797        if (VDBG) Log.d(TAG, "onAttributeWrite() connId=" + connId
1798            + ", address=" + address + ", handle=" + attrHandle
1799            + ", requestId=" + transId + ", isPrep=" + isPrep
1800            + ", offset=" + offset);
1801
1802        HandleMap.Entry entry = mHandleMap.getByHandle(attrHandle);
1803        if (entry == null) return;
1804
1805        mHandleMap.addRequest(transId, attrHandle);
1806
1807        ServerMap.App app = mServerMap.getById(entry.serverIf);
1808        if (app == null) return;
1809
1810        switch(entry.type) {
1811            case HandleMap.TYPE_CHARACTERISTIC:
1812            {
1813                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1814                app.callback.onCharacteristicWriteRequest(address, transId,
1815                            offset, length, isPrep, needRsp,
1816                            serviceEntry.serviceType, serviceEntry.instance,
1817                            new ParcelUuid(serviceEntry.uuid), entry.instance,
1818                            new ParcelUuid(entry.uuid), data);
1819                break;
1820            }
1821
1822            case HandleMap.TYPE_DESCRIPTOR:
1823            {
1824                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(entry.serviceHandle);
1825                HandleMap.Entry charEntry = mHandleMap.getByHandle(entry.charHandle);
1826                app.callback.onDescriptorWriteRequest(address, transId,
1827                            offset, length, isPrep, needRsp,
1828                            serviceEntry.serviceType, serviceEntry.instance,
1829                            new ParcelUuid(serviceEntry.uuid), charEntry.instance,
1830                            new ParcelUuid(charEntry.uuid),
1831                            new ParcelUuid(entry.uuid), data);
1832                break;
1833            }
1834
1835            default:
1836                Log.e(TAG, "onAttributeWrite() - Requested unknown attribute type.");
1837                break;
1838        }
1839    }
1840
1841    void onExecuteWrite(String address, int connId, int transId, int execWrite)
1842            throws RemoteException {
1843        if (DBG) Log.d(TAG, "onExecuteWrite() connId=" + connId
1844            + ", address=" + address + ", transId=" + transId);
1845
1846        ServerMap.App app = mServerMap.getByConnId(connId);
1847        if (app == null) return;
1848
1849        app.callback.onExecuteWrite(address, transId, execWrite == 1);
1850    }
1851
1852    void onResponseSendCompleted(int status, int attrHandle) {
1853        if (DBG) Log.d(TAG, "onResponseSendCompleted() handle=" + attrHandle);
1854    }
1855
1856    void onNotificationSent(int connId, int status) throws RemoteException {
1857        if (VDBG) Log.d(TAG, "onNotificationSent() connId=" + connId + ", status=" + status);
1858
1859        String address = mServerMap.addressByConnId(connId);
1860        if (address == null) return;
1861
1862        ServerMap.App app = mServerMap.getByConnId(connId);
1863        if (app == null) return;
1864
1865        if (!app.isCongested) {
1866            app.callback.onNotificationSent(address, status);
1867        } else {
1868            if (status == BluetoothGatt.GATT_CONNECTION_CONGESTED) {
1869                status = BluetoothGatt.GATT_SUCCESS;
1870            }
1871            app.queueCallback(new CallbackInfo(address, status));
1872        }
1873    }
1874
1875    void onServerCongestion(int connId, boolean congested) throws RemoteException {
1876        if (DBG) Log.d(TAG, "onServerCongestion() - connId=" + connId + ", congested=" + congested);
1877
1878        ServerMap.App app = mServerMap.getByConnId(connId);
1879        if (app == null) return;
1880
1881        app.isCongested = congested;
1882        while(!app.isCongested) {
1883            CallbackInfo callbackInfo = app.popQueuedCallback();
1884            if (callbackInfo == null) return;
1885            app.callback.onNotificationSent(callbackInfo.address, callbackInfo.status);
1886        }
1887    }
1888
1889    void onMtuChanged(int connId, int mtu) throws RemoteException {
1890        if (DBG) Log.d(TAG, "onMtuChanged() - connId=" + connId + ", mtu=" + mtu);
1891
1892        String address = mServerMap.addressByConnId(connId);
1893        if (address == null) return;
1894
1895        ServerMap.App app = mServerMap.getByConnId(connId);
1896        if (app == null) return;
1897
1898        app.callback.onMtuChanged(address, mtu);
1899    }
1900
1901    /**************************************************************************
1902     * GATT Service functions - SERVER
1903     *************************************************************************/
1904
1905    void registerServer(UUID uuid, IBluetoothGattServerCallback callback) {
1906        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1907
1908        if (DBG) Log.d(TAG, "registerServer() - UUID=" + uuid);
1909        mServerMap.add(uuid, callback, this);
1910        gattServerRegisterAppNative(uuid.getLeastSignificantBits(),
1911                                    uuid.getMostSignificantBits());
1912    }
1913
1914    void unregisterServer(int serverIf) {
1915        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1916
1917        if (DBG) Log.d(TAG, "unregisterServer() - serverIf=" + serverIf);
1918
1919        deleteServices(serverIf);
1920
1921        mServerMap.remove(serverIf);
1922        gattServerUnregisterAppNative(serverIf);
1923    }
1924
1925    void serverConnect(int serverIf, String address, boolean isDirect, int transport) {
1926        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1927
1928        if (DBG) Log.d(TAG, "serverConnect() - address=" + address);
1929        gattServerConnectNative(serverIf, address, isDirect,transport);
1930    }
1931
1932    void serverDisconnect(int serverIf, String address) {
1933        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1934
1935        Integer connId = mServerMap.connIdByAddress(serverIf, address);
1936        if (DBG) Log.d(TAG, "serverDisconnect() - address=" + address + ", connId=" + connId);
1937
1938        gattServerDisconnectNative(serverIf, address, connId != null ? connId : 0);
1939    }
1940
1941    void beginServiceDeclaration(int serverIf, int srvcType, int srvcInstanceId,
1942                                 int minHandles, UUID srvcUuid, boolean advertisePreferred) {
1943        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1944
1945        if (DBG) Log.d(TAG, "beginServiceDeclaration() - uuid=" + srvcUuid);
1946        ServiceDeclaration serviceDeclaration = addDeclaration();
1947        serviceDeclaration.addService(srvcUuid, srvcType, srvcInstanceId, minHandles,
1948            advertisePreferred);
1949    }
1950
1951    void addIncludedService(int serverIf, int srvcType, int srvcInstanceId,
1952                            UUID srvcUuid) {
1953        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1954
1955        if (DBG) Log.d(TAG, "addIncludedService() - uuid=" + srvcUuid);
1956        getActiveDeclaration().addIncludedService(srvcUuid, srvcType, srvcInstanceId);
1957    }
1958
1959    void addCharacteristic(int serverIf, UUID charUuid, int properties,
1960                           int permissions) {
1961        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1962
1963        if (DBG) Log.d(TAG, "addCharacteristic() - uuid=" + charUuid);
1964        getActiveDeclaration().addCharacteristic(charUuid, properties, permissions);
1965    }
1966
1967    void addDescriptor(int serverIf, UUID descUuid, int permissions) {
1968        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1969
1970        if (DBG) Log.d(TAG, "addDescriptor() - uuid=" + descUuid);
1971        getActiveDeclaration().addDescriptor(descUuid, permissions);
1972    }
1973
1974    void endServiceDeclaration(int serverIf) {
1975        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1976
1977        if (DBG) Log.d(TAG, "endServiceDeclaration()");
1978
1979        if (getActiveDeclaration() == getPendingDeclaration()) {
1980            try {
1981                continueServiceDeclaration(serverIf, (byte)0, 0);
1982            } catch (RemoteException e) {
1983                Log.e(TAG,""+e);
1984            }
1985        }
1986    }
1987
1988    void removeService(int serverIf, int srvcType,
1989                  int srvcInstanceId, UUID srvcUuid) {
1990        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1991
1992        if (DBG) Log.d(TAG, "removeService() - uuid=" + srvcUuid);
1993
1994        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
1995        if (srvcHandle == 0) return;
1996        gattServerDeleteServiceNative(serverIf, srvcHandle);
1997    }
1998
1999    void clearServices(int serverIf) {
2000        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2001
2002        if (DBG) Log.d(TAG, "clearServices()");
2003        deleteServices(serverIf);
2004    }
2005
2006    void sendResponse(int serverIf, String address, int requestId,
2007                      int status, int offset, byte[] value) {
2008        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2009
2010        if (VDBG) Log.d(TAG, "sendResponse() - address=" + address);
2011
2012        int handle = 0;
2013        HandleMap.Entry entry = mHandleMap.getByRequestId(requestId);
2014        if (entry != null) handle = entry.handle;
2015
2016        int connId = mServerMap.connIdByAddress(serverIf, address);
2017        gattServerSendResponseNative(serverIf, connId, requestId, (byte)status,
2018                                     handle, offset, value, (byte)0);
2019        mHandleMap.deleteRequest(requestId);
2020    }
2021
2022    void sendNotification(int serverIf, String address, int srvcType,
2023                                 int srvcInstanceId, UUID srvcUuid,
2024                                 int charInstanceId, UUID charUuid,
2025                                 boolean confirm, byte[] value) {
2026        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2027
2028        if (VDBG) Log.d(TAG, "sendNotification() - address=" + address);
2029
2030        int srvcHandle = mHandleMap.getServiceHandle(srvcUuid, srvcType, srvcInstanceId);
2031        if (srvcHandle == 0) return;
2032
2033        int charHandle = mHandleMap.getCharacteristicHandle(srvcHandle, charUuid, charInstanceId);
2034        if (charHandle == 0) return;
2035
2036        int connId = mServerMap.connIdByAddress(serverIf, address);
2037        if (connId == 0) return;
2038
2039        if (confirm) {
2040            gattServerSendIndicationNative(serverIf, charHandle, connId, value);
2041        } else {
2042            gattServerSendNotificationNative(serverIf, charHandle, connId, value);
2043        }
2044    }
2045
2046
2047    /**************************************************************************
2048     * Private functions
2049     *************************************************************************/
2050
2051    private boolean isRestrictedCharUuid(final UUID charUuid) {
2052      return isHidUuid(charUuid);
2053    }
2054
2055    private boolean isRestrictedSrvcUuid(final UUID srvcUuid) {
2056      return isFidoUUID(srvcUuid);
2057    }
2058
2059    private boolean isHidUuid(final UUID uuid) {
2060        for (UUID hid_uuid : HID_UUIDS) {
2061            if (hid_uuid.equals(uuid)) return true;
2062        }
2063        return false;
2064    }
2065
2066    private boolean isFidoUUID(final UUID uuid) {
2067        for (UUID fido_uuid : FIDO_UUIDS) {
2068            if (fido_uuid.equals(uuid)) return true;
2069        }
2070        return false;
2071    }
2072
2073    private int getDeviceType(BluetoothDevice device) {
2074        int type = gattClientGetDeviceTypeNative(device.getAddress());
2075        if (DBG) Log.d(TAG, "getDeviceType() - device=" + device
2076            + ", type=" + type);
2077        return type;
2078    }
2079
2080    private void enforceAdminPermission() {
2081        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
2082    }
2083
2084    private boolean needsPrivilegedPermissionForScan(ScanSettings settings) {
2085        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2086        // BLE scan only mode needs special permission.
2087        if (adapter.getState() != BluetoothAdapter.STATE_ON) return true;
2088
2089        // Regular scan, no special permission.
2090        if (settings == null) return false;
2091
2092        // Regular scan, no special permission.
2093        if (settings.getReportDelayMillis() == 0) return false;
2094
2095        // Batch scan, truncated mode needs permission.
2096        return settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_ABBREVIATED;
2097    }
2098
2099    // Enforce caller has BLUETOOTH_PRIVILEGED permission. A {@link SecurityException} will be
2100    // thrown if the caller app does not have BLUETOOTH_PRIVILEGED permission.
2101    private void enforcePrivilegedPermission() {
2102        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
2103            "Need BLUETOOTH_PRIVILEGED permission");
2104    }
2105
2106    // Enforce caller has UPDATE_DEVICE_STATS permission, which allows the caller to blame other
2107    // apps for Bluetooth usage. A {@link SecurityException} will be thrown if the caller app does
2108    // not have UPDATE_DEVICE_STATS permission.
2109    private void enforceImpersonatationPermission() {
2110        enforceCallingOrSelfPermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
2111                "Need UPDATE_DEVICE_STATS permission");
2112    }
2113
2114    private void continueServiceDeclaration(int serverIf, int status, int srvcHandle) throws RemoteException {
2115        if (mServiceDeclarations.size() == 0) return;
2116        if (DBG) Log.d(TAG, "continueServiceDeclaration() - srvcHandle=" + srvcHandle);
2117
2118        boolean finished = false;
2119
2120        ServiceDeclaration.Entry entry = null;
2121        if (status == 0)
2122            entry = getPendingDeclaration().getNext();
2123
2124        if (entry != null) {
2125            if (DBG) Log.d(TAG, "continueServiceDeclaration() - next entry type="
2126                + entry.type);
2127            switch(entry.type) {
2128                case ServiceDeclaration.TYPE_SERVICE:
2129                    if (entry.advertisePreferred) {
2130                        mAdvertisingServiceUuids.add(entry.uuid);
2131                    }
2132                    gattServerAddServiceNative(serverIf, entry.serviceType,
2133                        entry.instance,
2134                        entry.uuid.getLeastSignificantBits(),
2135                        entry.uuid.getMostSignificantBits(),
2136                        getPendingDeclaration().getNumHandles());
2137                    break;
2138
2139                case ServiceDeclaration.TYPE_CHARACTERISTIC:
2140                    gattServerAddCharacteristicNative(serverIf, srvcHandle,
2141                        entry.uuid.getLeastSignificantBits(),
2142                        entry.uuid.getMostSignificantBits(),
2143                        entry.properties, entry.permissions);
2144                    break;
2145
2146                case ServiceDeclaration.TYPE_DESCRIPTOR:
2147                    gattServerAddDescriptorNative(serverIf, srvcHandle,
2148                        entry.uuid.getLeastSignificantBits(),
2149                        entry.uuid.getMostSignificantBits(),
2150                        entry.permissions);
2151                    break;
2152
2153                case ServiceDeclaration.TYPE_INCLUDED_SERVICE:
2154                {
2155                    int inclSrvc = mHandleMap.getServiceHandle(entry.uuid,
2156                                            entry.serviceType, entry.instance);
2157                    if (inclSrvc != 0) {
2158                        gattServerAddIncludedServiceNative(serverIf, srvcHandle,
2159                                                           inclSrvc);
2160                    } else {
2161                        finished = true;
2162                    }
2163                    break;
2164                }
2165            }
2166        } else {
2167            gattServerStartServiceNative(serverIf, srvcHandle,
2168                (byte)BluetoothDevice.TRANSPORT_BREDR | BluetoothDevice.TRANSPORT_LE);
2169            finished = true;
2170        }
2171
2172        if (finished) {
2173            if (DBG) Log.d(TAG, "continueServiceDeclaration() - completed.");
2174            ServerMap.App app = mServerMap.getById(serverIf);
2175            if (app != null) {
2176                HandleMap.Entry serviceEntry = mHandleMap.getByHandle(srvcHandle);
2177
2178                if (serviceEntry != null) {
2179                    app.callback.onServiceAdded(status, serviceEntry.serviceType,
2180                        serviceEntry.instance, new ParcelUuid(serviceEntry.uuid));
2181                } else {
2182                    app.callback.onServiceAdded(status, 0, 0, null);
2183                }
2184            }
2185            removePendingDeclaration();
2186
2187            if (getPendingDeclaration() != null) {
2188                continueServiceDeclaration(serverIf, (byte)0, 0);
2189            }
2190        }
2191    }
2192
2193    private void stopNextService(int serverIf, int status) throws RemoteException {
2194        if (DBG) Log.d(TAG, "stopNextService() - serverIf=" + serverIf
2195            + ", status=" + status);
2196
2197        if (status == 0) {
2198            List<HandleMap.Entry> entries = mHandleMap.getEntries();
2199            for(HandleMap.Entry entry : entries) {
2200                if (entry.type != HandleMap.TYPE_SERVICE ||
2201                    entry.serverIf != serverIf ||
2202                    entry.started == false)
2203                        continue;
2204
2205                gattServerStopServiceNative(serverIf, entry.handle);
2206                return;
2207            }
2208        }
2209    }
2210
2211    private void deleteServices(int serverIf) {
2212        if (DBG) Log.d(TAG, "deleteServices() - serverIf=" + serverIf);
2213
2214        /*
2215         * Figure out which handles to delete.
2216         * The handles are copied into a new list to avoid race conditions.
2217         */
2218        List<Integer> handleList = new ArrayList<Integer>();
2219        List<HandleMap.Entry> entries = mHandleMap.getEntries();
2220        for(HandleMap.Entry entry : entries) {
2221            if (entry.type != HandleMap.TYPE_SERVICE ||
2222                entry.serverIf != serverIf)
2223                    continue;
2224            handleList.add(entry.handle);
2225        }
2226
2227        /* Now actually delete the services.... */
2228        for(Integer handle : handleList) {
2229            gattServerDeleteServiceNative(serverIf, handle);
2230        }
2231    }
2232
2233    private List<UUID> parseUuids(byte[] adv_data) {
2234        List<UUID> uuids = new ArrayList<UUID>();
2235
2236        int offset = 0;
2237        while(offset < (adv_data.length-2)) {
2238            int len = adv_data[offset++];
2239            if (len == 0) break;
2240
2241            int type = adv_data[offset++];
2242            switch (type) {
2243                case 0x02: // Partial list of 16-bit UUIDs
2244                case 0x03: // Complete list of 16-bit UUIDs
2245                    while (len > 1) {
2246                        int uuid16 = adv_data[offset++];
2247                        uuid16 += (adv_data[offset++] << 8);
2248                        len -= 2;
2249                        uuids.add(UUID.fromString(String.format(
2250                            "%08x-0000-1000-8000-00805f9b34fb", uuid16)));
2251                    }
2252                    break;
2253
2254                default:
2255                    offset += (len - 1);
2256                    break;
2257            }
2258        }
2259
2260        return uuids;
2261    }
2262
2263    @Override
2264    public void dump(StringBuilder sb) {
2265        super.dump(sb);
2266        println(sb, "mAdvertisingServiceUuids:");
2267        for (UUID uuid : mAdvertisingServiceUuids) {
2268            println(sb, "  " + uuid);
2269        }
2270        for (ServiceDeclaration declaration : mServiceDeclarations) {
2271            println(sb, "  " + declaration);
2272        }
2273        println(sb, "mMaxScanFilters: " + mMaxScanFilters);
2274
2275        sb.append("\nGATT Client Map\n");
2276        mClientMap.dump(sb);
2277
2278        sb.append("GATT Server Map\n");
2279        mServerMap.dump(sb);
2280
2281        sb.append("GATT Handle Map\n");
2282        mHandleMap.dump(sb);
2283    }
2284
2285    void addScanResult() {
2286        if (mScanEvents.isEmpty())
2287            return;
2288
2289        BluetoothProto.ScanEvent curr = mScanEvents.get(mScanEvents.size() - 1);
2290        curr.setNumberResults(curr.getNumberResults() + 1);
2291    }
2292
2293    void addScanEvent(BluetoothProto.ScanEvent event) {
2294        synchronized(mScanEvents) {
2295            if (mScanEvents.size() == NUM_SCAN_EVENTS_KEPT)
2296                mScanEvents.remove(0);
2297            mScanEvents.add(event);
2298        }
2299    }
2300
2301    @Override
2302    public void dumpProto(BluetoothProto.BluetoothLog proto) {
2303        synchronized(mScanEvents) {
2304            for (BluetoothProto.ScanEvent event : mScanEvents) {
2305                proto.addScanEvent(event);
2306            }
2307        }
2308    }
2309
2310    /**************************************************************************
2311     * GATT Test functions
2312     *************************************************************************/
2313
2314    void gattTestCommand(int command, UUID uuid1, String bda1,
2315                         int p1, int p2, int p3, int p4, int p5) {
2316        if (bda1 == null) bda1 = "00:00:00:00:00:00";
2317        if (uuid1 != null)
2318            gattTestNative(command, uuid1.getLeastSignificantBits(),
2319                       uuid1.getMostSignificantBits(), bda1, p1, p2, p3, p4, p5);
2320        else
2321            gattTestNative(command, 0,0, bda1, p1, p2, p3, p4, p5);
2322    }
2323
2324    private native void gattTestNative(int command,
2325                                    long uuid1_lsb, long uuid1_msb, String bda1,
2326                                    int p1, int p2, int p3, int p4, int p5);
2327
2328    /**************************************************************************
2329     * Native functions prototypes
2330     *************************************************************************/
2331
2332    private native static void classInitNative();
2333    private native void initializeNative();
2334    private native void cleanupNative();
2335
2336    private native int gattClientGetDeviceTypeNative(String address);
2337
2338    private native void gattClientRegisterAppNative(long app_uuid_lsb,
2339                                                    long app_uuid_msb);
2340
2341    private native void gattClientUnregisterAppNative(int clientIf);
2342
2343    private native void gattClientConnectNative(int clientIf, String address,
2344            boolean isDirect, int transport);
2345
2346    private native void gattClientDisconnectNative(int clientIf, String address,
2347            int conn_id);
2348
2349    private native void gattClientRefreshNative(int clientIf, String address);
2350
2351    private native void gattClientSearchServiceNative(int conn_id,
2352            boolean search_all, long service_uuid_lsb, long service_uuid_msb);
2353
2354    private native void gattClientGetGattDbNative(int conn_id);
2355
2356    private native void gattClientReadCharacteristicNative(int conn_id, int handle, int authReq);
2357
2358    private native void gattClientReadDescriptorNative(int conn_id, int handle, int authReq);
2359
2360    private native void gattClientWriteCharacteristicNative(int conn_id,
2361            int handle, int write_type, int auth_req, byte[] value);
2362
2363    private native void gattClientWriteDescriptorNative(int conn_id, int handle,
2364            int write_type, int auth_req, byte[] value);
2365
2366    private native void gattClientExecuteWriteNative(int conn_id, boolean execute);
2367
2368    private native void gattClientRegisterForNotificationsNative(int clientIf,
2369            String address, int handle, boolean enable);
2370
2371    private native void gattClientReadRemoteRssiNative(int clientIf,
2372            String address);
2373
2374    private native void gattClientConfigureMTUNative(int conn_id, int mtu);
2375
2376    private native void gattConnectionParameterUpdateNative(int client_if, String address,
2377            int minInterval, int maxInterval, int latency, int timeout);
2378
2379    private native void gattServerRegisterAppNative(long app_uuid_lsb,
2380                                                    long app_uuid_msb);
2381
2382    private native void gattServerUnregisterAppNative(int serverIf);
2383
2384    private native void gattServerConnectNative(int server_if, String address,
2385                                             boolean is_direct, int transport);
2386
2387    private native void gattServerDisconnectNative(int serverIf, String address,
2388                                              int conn_id);
2389
2390    private native void gattServerAddServiceNative (int server_if,
2391            int service_type, int service_id_inst_id,
2392            long service_id_uuid_lsb, long service_id_uuid_msb,
2393            int num_handles);
2394
2395    private native void gattServerAddIncludedServiceNative (int server_if,
2396            int svc_handle, int included_svc_handle);
2397
2398    private native void gattServerAddCharacteristicNative (int server_if,
2399            int svc_handle, long char_uuid_lsb, long char_uuid_msb,
2400            int properties, int permissions);
2401
2402    private native void gattServerAddDescriptorNative (int server_if,
2403            int svc_handle, long desc_uuid_lsb, long desc_uuid_msb,
2404            int permissions);
2405
2406    private native void gattServerStartServiceNative (int server_if,
2407            int svc_handle, int transport );
2408
2409    private native void gattServerStopServiceNative (int server_if,
2410                                                     int svc_handle);
2411
2412    private native void gattServerDeleteServiceNative (int server_if,
2413                                                       int svc_handle);
2414
2415    private native void gattServerSendIndicationNative (int server_if,
2416            int attr_handle, int conn_id, byte[] val);
2417
2418    private native void gattServerSendNotificationNative (int server_if,
2419            int attr_handle, int conn_id, byte[] val);
2420
2421    private native void gattServerSendResponseNative (int server_if,
2422            int conn_id, int trans_id, int status, int handle, int offset,
2423            byte[] val, int auth_req);
2424}
2425