• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 
17 package com.android.bluetooth.hid;
18 
19 import static android.Manifest.permission.BLUETOOTH_CONNECT;
20 
21 import android.annotation.RequiresPermission;
22 import android.app.ActivityManager;
23 import android.app.ActivityThread;
24 import android.bluetooth.BluetoothDevice;
25 import android.bluetooth.BluetoothHidDevice;
26 import android.bluetooth.BluetoothHidDeviceAppQosSettings;
27 import android.bluetooth.BluetoothHidDeviceAppSdpSettings;
28 import android.bluetooth.BluetoothProfile;
29 import android.bluetooth.IBluetoothHidDevice;
30 import android.bluetooth.IBluetoothHidDeviceCallback;
31 import android.content.Attributable;
32 import android.content.AttributionSource;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.os.Binder;
36 import android.os.Handler;
37 import android.os.IBinder;
38 import android.os.Message;
39 import android.os.Process;
40 import android.os.RemoteException;
41 import android.util.Log;
42 
43 import com.android.bluetooth.BluetoothMetricsProto;
44 import com.android.bluetooth.Utils;
45 import com.android.bluetooth.btservice.AdapterService;
46 import com.android.bluetooth.btservice.MetricsLogger;
47 import com.android.bluetooth.btservice.ProfileService;
48 import com.android.bluetooth.btservice.storage.DatabaseManager;
49 import com.android.internal.annotations.VisibleForTesting;
50 
51 import java.nio.ByteBuffer;
52 import java.util.ArrayList;
53 import java.util.Arrays;
54 import java.util.List;
55 import java.util.NoSuchElementException;
56 import java.util.Objects;
57 
58 /** @hide */
59 public class HidDeviceService extends ProfileService {
60     private static final boolean DBG = false;
61     private static final String TAG = HidDeviceService.class.getSimpleName();
62 
63     private static final int MESSAGE_APPLICATION_STATE_CHANGED = 1;
64     private static final int MESSAGE_CONNECT_STATE_CHANGED = 2;
65     private static final int MESSAGE_GET_REPORT = 3;
66     private static final int MESSAGE_SET_REPORT = 4;
67     private static final int MESSAGE_SET_PROTOCOL = 5;
68     private static final int MESSAGE_INTR_DATA = 6;
69     private static final int MESSAGE_VC_UNPLUG = 7;
70     private static final int MESSAGE_IMPORTANCE_CHANGE = 8;
71 
72     private static final int FOREGROUND_IMPORTANCE_CUTOFF =
73             ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
74 
75     private static HidDeviceService sHidDeviceService;
76 
77     private DatabaseManager mDatabaseManager;
78     private HidDeviceNativeInterface mHidDeviceNativeInterface;
79 
80     private boolean mNativeAvailable = false;
81     private BluetoothDevice mHidDevice;
82     private int mHidDeviceState = BluetoothHidDevice.STATE_DISCONNECTED;
83     private int mUserUid = 0;
84     private IBluetoothHidDeviceCallback mCallback;
85     private BluetoothHidDeviceDeathRecipient mDeathRcpt;
86     private ActivityManager mActivityManager;
87 
88     private HidDeviceServiceHandler mHandler;
89 
90     private class HidDeviceServiceHandler extends Handler {
91         @Override
handleMessage(Message msg)92         public void handleMessage(Message msg) {
93             if (DBG) {
94                 Log.d(TAG, "handleMessage(): msg.what=" + msg.what);
95             }
96 
97             switch (msg.what) {
98                 case MESSAGE_APPLICATION_STATE_CHANGED: {
99                     BluetoothDevice device = msg.obj != null ? (BluetoothDevice) msg.obj : null;
100                     Attributable.setAttributionSource(device,
101                             ActivityThread.currentAttributionSource());
102                     boolean success = (msg.arg1 != 0);
103 
104                     if (success) {
105                         Log.d(TAG, "App registered, set device to: " + device);
106                         mHidDevice = device;
107                     } else {
108                         mHidDevice = null;
109                     }
110 
111                     try {
112                         if (mCallback != null) {
113                             mCallback.onAppStatusChanged(device, success);
114                         } else {
115                             break;
116                         }
117                     } catch (RemoteException e) {
118                         Log.e(TAG, "e=" + e.toString());
119                         e.printStackTrace();
120                     }
121 
122                     if (success) {
123                         mDeathRcpt = new BluetoothHidDeviceDeathRecipient(HidDeviceService.this);
124                         if (mCallback != null) {
125                             IBinder binder = mCallback.asBinder();
126                             try {
127                                 binder.linkToDeath(mDeathRcpt, 0);
128                                 Log.i(TAG, "IBinder.linkToDeath() ok");
129                             } catch (RemoteException e) {
130                                 e.printStackTrace();
131                             }
132                         }
133                     } else if (mDeathRcpt != null) {
134                         if (mCallback != null) {
135                             IBinder binder = mCallback.asBinder();
136                             try {
137                                 binder.unlinkToDeath(mDeathRcpt, 0);
138                                 Log.i(TAG, "IBinder.unlinkToDeath() ok");
139                             } catch (NoSuchElementException e) {
140                                 e.printStackTrace();
141                             }
142                             mDeathRcpt.cleanup();
143                             mDeathRcpt = null;
144                         }
145                     }
146 
147                     if (!success) {
148                         mCallback = null;
149                     }
150 
151                     break;
152                 }
153 
154                 case MESSAGE_CONNECT_STATE_CHANGED: {
155                     BluetoothDevice device = (BluetoothDevice) msg.obj;
156                     Attributable.setAttributionSource(device,
157                             ActivityThread.currentAttributionSource());
158                     int halState = msg.arg1;
159                     int state = convertHalState(halState);
160 
161                     if (state != BluetoothHidDevice.STATE_DISCONNECTED) {
162                         mHidDevice = device;
163                     }
164 
165                     setAndBroadcastConnectionState(device, state);
166 
167                     try {
168                         if (mCallback != null) {
169                             mCallback.onConnectionStateChanged(device, state);
170                         }
171                     } catch (RemoteException e) {
172                         e.printStackTrace();
173                     }
174                     break;
175                 }
176 
177                 case MESSAGE_GET_REPORT:
178                     byte type = (byte) msg.arg1;
179                     byte id = (byte) msg.arg2;
180                     int bufferSize = msg.obj == null ? 0 : ((Integer) msg.obj).intValue();
181 
182                     try {
183                         if (mCallback != null) {
184                             mCallback.onGetReport(mHidDevice, type, id, bufferSize);
185                         }
186                     } catch (RemoteException e) {
187                         e.printStackTrace();
188                     }
189                     break;
190 
191                 case MESSAGE_SET_REPORT: {
192                     byte reportType = (byte) msg.arg1;
193                     byte reportId = (byte) msg.arg2;
194                     byte[] data = ((ByteBuffer) msg.obj).array();
195 
196                     try {
197                         if (mCallback != null) {
198                             mCallback.onSetReport(mHidDevice, reportType, reportId, data);
199                         }
200                     } catch (RemoteException e) {
201                         e.printStackTrace();
202                     }
203                     break;
204                 }
205 
206                 case MESSAGE_SET_PROTOCOL:
207                     byte protocol = (byte) msg.arg1;
208 
209                     try {
210                         if (mCallback != null) {
211                             mCallback.onSetProtocol(mHidDevice, protocol);
212                         }
213                     } catch (RemoteException e) {
214                         e.printStackTrace();
215                     }
216                     break;
217 
218                 case MESSAGE_INTR_DATA:
219                     byte reportId = (byte) msg.arg1;
220                     byte[] data = ((ByteBuffer) msg.obj).array();
221 
222                     try {
223                         if (mCallback != null) {
224                             mCallback.onInterruptData(mHidDevice, reportId, data);
225                         }
226                     } catch (RemoteException e) {
227                         e.printStackTrace();
228                     }
229                     break;
230 
231                 case MESSAGE_VC_UNPLUG:
232                     try {
233                         if (mCallback != null) {
234                             mCallback.onVirtualCableUnplug(mHidDevice);
235                         }
236                     } catch (RemoteException e) {
237                         e.printStackTrace();
238                     }
239                     mHidDevice = null;
240                     break;
241 
242                 case MESSAGE_IMPORTANCE_CHANGE:
243                     int importance = msg.arg1;
244                     int uid = msg.arg2;
245                     if (importance > FOREGROUND_IMPORTANCE_CUTOFF
246                             && uid >= Process.FIRST_APPLICATION_UID) {
247                         unregisterAppUid(uid);
248                     }
249                     break;
250             }
251         }
252     }
253 
254     private static class BluetoothHidDeviceDeathRecipient implements IBinder.DeathRecipient {
255         private HidDeviceService mService;
256 
BluetoothHidDeviceDeathRecipient(HidDeviceService service)257         BluetoothHidDeviceDeathRecipient(HidDeviceService service) {
258             mService = service;
259         }
260 
261         @Override
binderDied()262         public void binderDied() {
263             Log.w(TAG, "Binder died, need to unregister app :(");
264             mService.unregisterApp();
265         }
266 
cleanup()267         public void cleanup() {
268             mService = null;
269         }
270     }
271 
272     private ActivityManager.OnUidImportanceListener mUidImportanceListener =
273             new ActivityManager.OnUidImportanceListener() {
274                 @Override
275                 public void onUidImportance(final int uid, final int importance) {
276                     Message message = mHandler.obtainMessage(MESSAGE_IMPORTANCE_CHANGE);
277                     message.arg1 = importance;
278                     message.arg2 = uid;
279                     mHandler.sendMessage(message);
280                 }
281             };
282 
283     @VisibleForTesting
284     static class BluetoothHidDeviceBinder extends IBluetoothHidDevice.Stub
285             implements IProfileServiceBinder {
286 
287         private static final String TAG = BluetoothHidDeviceBinder.class.getSimpleName();
288 
289         private HidDeviceService mService;
290 
BluetoothHidDeviceBinder(HidDeviceService service)291         BluetoothHidDeviceBinder(HidDeviceService service) {
292             mService = service;
293         }
294 
295         @VisibleForTesting
getServiceForTesting()296         HidDeviceService getServiceForTesting() {
297             if (mService != null && mService.isAvailable()) {
298                 return mService;
299             }
300             return null;
301         }
302 
303         @Override
cleanup()304         public void cleanup() {
305             mService = null;
306         }
307 
308         @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getService(AttributionSource source)309         private HidDeviceService getService(AttributionSource source) {
310             if (!Utils.checkCallerIsSystemOrActiveUser(TAG)
311                     || !Utils.checkServiceAvailable(mService, TAG)
312                     || !Utils.checkConnectPermissionForDataDelivery(mService, source, TAG)) {
313                 return null;
314             }
315             return mService;
316         }
317 
318         @Override
registerApp(BluetoothHidDeviceAppSdpSettings sdp, BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos, IBluetoothHidDeviceCallback callback, AttributionSource source)319         public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
320                 BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
321                 IBluetoothHidDeviceCallback callback, AttributionSource source) {
322             if (DBG) {
323                 Log.d(TAG, "registerApp()");
324             }
325 
326             HidDeviceService service = getService(source);
327             if (service == null) {
328                 return false;
329             }
330 
331             return service.registerApp(sdp, inQos, outQos, callback);
332         }
333 
334         @Override
unregisterApp(AttributionSource source)335         public boolean unregisterApp(AttributionSource source) {
336             if (DBG) {
337                 Log.d(TAG, "unregisterApp()");
338             }
339 
340             HidDeviceService service = getService(source);
341             if (service == null) {
342                 return false;
343             }
344 
345             return service.unregisterApp();
346         }
347 
348         @Override
sendReport(BluetoothDevice device, int id, byte[] data, AttributionSource source)349         public boolean sendReport(BluetoothDevice device, int id, byte[] data,
350                 AttributionSource source) {
351             if (DBG) {
352                 Log.d(TAG, "sendReport(): device=" + device + "  id=" + id);
353             }
354 
355             Attributable.setAttributionSource(device, source);
356             HidDeviceService service = getService(source);
357             if (service == null) {
358                 return false;
359             }
360 
361             return service.sendReport(device, id, data);
362         }
363 
364         @Override
replyReport(BluetoothDevice device, byte type, byte id, byte[] data, AttributionSource source)365         public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data,
366                 AttributionSource source) {
367             if (DBG) {
368                 Log.d(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id);
369             }
370 
371             Attributable.setAttributionSource(device, source);
372             HidDeviceService service = getService(source);
373             if (service == null) {
374                 return false;
375             }
376 
377             return service.replyReport(device, type, id, data);
378         }
379 
380         @Override
unplug(BluetoothDevice device, AttributionSource source)381         public boolean unplug(BluetoothDevice device, AttributionSource source) {
382             if (DBG) {
383                 Log.d(TAG, "unplug(): device=" + device);
384             }
385 
386             Attributable.setAttributionSource(device, source);
387             HidDeviceService service = getService(source);
388             if (service == null) {
389                 return false;
390             }
391 
392             return service.unplug(device);
393         }
394 
395         @Override
connect(BluetoothDevice device, AttributionSource source)396         public boolean connect(BluetoothDevice device, AttributionSource source) {
397             if (DBG) {
398                 Log.d(TAG, "connect(): device=" + device);
399             }
400 
401             Attributable.setAttributionSource(device, source);
402             HidDeviceService service = getService(source);
403             if (service == null) {
404                 return false;
405             }
406 
407             return service.connect(device);
408         }
409 
410         @Override
disconnect(BluetoothDevice device, AttributionSource source)411         public boolean disconnect(BluetoothDevice device, AttributionSource source) {
412             if (DBG) {
413                 Log.d(TAG, "disconnect(): device=" + device);
414             }
415 
416             Attributable.setAttributionSource(device, source);
417             HidDeviceService service = getService(source);
418             if (service == null) {
419                 return false;
420             }
421 
422             return service.disconnect(device);
423         }
424 
425         @Override
setConnectionPolicy(BluetoothDevice device, int connectionPolicy, AttributionSource source)426         public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy,
427                 AttributionSource source) {
428             if (DBG) {
429                 Log.d(TAG, "setConnectionPolicy(): device=" + device + " connectionPolicy="
430                         + connectionPolicy);
431             }
432 
433             Attributable.setAttributionSource(device, source);
434             HidDeviceService service = getService(source);
435             if (service == null) {
436                 return false;
437             }
438 
439             return service.setConnectionPolicy(device, connectionPolicy);
440         }
441 
442         @Override
reportError(BluetoothDevice device, byte error, AttributionSource source)443         public boolean reportError(BluetoothDevice device, byte error, AttributionSource source) {
444             if (DBG) {
445                 Log.d(TAG, "reportError(): device=" + device + " error=" + error);
446             }
447 
448             Attributable.setAttributionSource(device, source);
449             HidDeviceService service = getService(source);
450             if (service == null) {
451                 return false;
452             }
453 
454             return service.reportError(device, error);
455         }
456 
457         @Override
getConnectionState(BluetoothDevice device, AttributionSource source)458         public int getConnectionState(BluetoothDevice device, AttributionSource source) {
459             if (DBG) {
460                 Log.d(TAG, "getConnectionState(): device=" + device);
461             }
462 
463             Attributable.setAttributionSource(device, source);
464             HidDeviceService service = getService(source);
465             if (service == null) {
466                 return BluetoothHidDevice.STATE_DISCONNECTED;
467             }
468 
469             return service.getConnectionState(device);
470         }
471 
472         @Override
getConnectedDevices(AttributionSource source)473         public List<BluetoothDevice> getConnectedDevices(AttributionSource source) {
474             if (DBG) {
475                 Log.d(TAG, "getConnectedDevices()");
476             }
477 
478             return getDevicesMatchingConnectionStates(new int[] {
479                     BluetoothProfile.STATE_CONNECTED
480             }, source);
481         }
482 
483         @Override
getDevicesMatchingConnectionStates(int[] states, AttributionSource source)484         public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states,
485                 AttributionSource source) {
486             if (DBG) {
487                 Log.d(TAG,
488                         "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states));
489             }
490 
491             HidDeviceService service = getService(source);
492             if (service == null) {
493                 return new ArrayList<BluetoothDevice>(0);
494             }
495 
496             return service.getDevicesMatchingConnectionStates(states);
497         }
498 
499         @Override
getUserAppName(AttributionSource source)500         public String getUserAppName(AttributionSource source) {
501             HidDeviceService service = getService(source);
502             if (service == null) {
503                 return "";
504             }
505             return service.getUserAppName();
506         }
507     }
508 
509     @Override
initBinder()510     protected IProfileServiceBinder initBinder() {
511         return new BluetoothHidDeviceBinder(this);
512     }
513 
checkDevice(BluetoothDevice device)514     private boolean checkDevice(BluetoothDevice device) {
515         if (mHidDevice == null || !mHidDevice.equals(device)) {
516             Log.w(TAG, "Unknown device: " + device);
517             return false;
518         }
519         return true;
520     }
521 
checkCallingUid()522     private boolean checkCallingUid() {
523         int callingUid = Binder.getCallingUid();
524         if (callingUid != mUserUid) {
525             Log.w(TAG, "checkCallingUid(): caller UID doesn't match registered user UID");
526             return false;
527         }
528         return true;
529     }
530 
registerApp(BluetoothHidDeviceAppSdpSettings sdp, BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos, IBluetoothHidDeviceCallback callback)531     synchronized boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
532             BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
533             IBluetoothHidDeviceCallback callback) {
534         if (mUserUid != 0) {
535             Log.w(TAG, "registerApp(): failed because another app is registered");
536             return false;
537         }
538 
539         int callingUid = Binder.getCallingUid();
540         if (DBG) {
541             Log.d(TAG, "registerApp(): calling uid=" + callingUid);
542         }
543         if (callingUid >= Process.FIRST_APPLICATION_UID
544                 && mActivityManager.getUidImportance(callingUid) > FOREGROUND_IMPORTANCE_CUTOFF) {
545             Log.w(TAG, "registerApp(): failed because the app is not foreground");
546             return false;
547         }
548         mUserUid = callingUid;
549         mCallback = callback;
550 
551         return mHidDeviceNativeInterface.registerApp(
552                 sdp.getName(),
553                 sdp.getDescription(),
554                 sdp.getProvider(),
555                 sdp.getSubclass(),
556                 sdp.getDescriptors(),
557                 inQos == null
558                         ? null
559                         : new int[] {
560                             inQos.getServiceType(),
561                             inQos.getTokenRate(),
562                             inQos.getTokenBucketSize(),
563                             inQos.getPeakBandwidth(),
564                             inQos.getLatency(),
565                             inQos.getDelayVariation()
566                         },
567                 outQos == null
568                         ? null
569                         : new int[] {
570                             outQos.getServiceType(),
571                             outQos.getTokenRate(),
572                             outQos.getTokenBucketSize(),
573                             outQos.getPeakBandwidth(),
574                             outQos.getLatency(),
575                             outQos.getDelayVariation()
576                         });
577     }
578 
unregisterApp()579     synchronized boolean unregisterApp() {
580         if (DBG) {
581             Log.d(TAG, "unregisterApp()");
582         }
583 
584         int callingUid = Binder.getCallingUid();
585         return unregisterAppUid(callingUid);
586     }
587 
unregisterAppUid(int uid)588     private synchronized boolean unregisterAppUid(int uid) {
589         if (DBG) {
590             Log.d(TAG, "unregisterAppUid(): uid=" + uid);
591         }
592 
593         if (mUserUid != 0 && (uid == mUserUid || uid < Process.FIRST_APPLICATION_UID)) {
594             mUserUid = 0;
595             return mHidDeviceNativeInterface.unregisterApp();
596         }
597         if (DBG) {
598             Log.d(TAG, "unregisterAppUid(): caller UID doesn't match user UID");
599         }
600         return false;
601     }
602 
sendReport(BluetoothDevice device, int id, byte[] data)603     synchronized boolean sendReport(BluetoothDevice device, int id, byte[] data) {
604         if (DBG) {
605             Log.d(TAG, "sendReport(): device=" + device + " id=" + id);
606         }
607 
608         return checkDevice(device) && checkCallingUid()
609                 && mHidDeviceNativeInterface.sendReport(id, data);
610     }
611 
replyReport(BluetoothDevice device, byte type, byte id, byte[] data)612     synchronized boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
613         if (DBG) {
614             Log.d(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id);
615         }
616 
617         return checkDevice(device) && checkCallingUid()
618                 && mHidDeviceNativeInterface.replyReport(type, id, data);
619     }
620 
unplug(BluetoothDevice device)621     synchronized boolean unplug(BluetoothDevice device) {
622         if (DBG) {
623             Log.d(TAG, "unplug(): device=" + device);
624         }
625 
626         return checkDevice(device) && checkCallingUid()
627                 && mHidDeviceNativeInterface.unplug();
628     }
629 
630     /**
631      * Connects the Hid device profile for the remote bluetooth device
632      *
633      * @param device is the device with which we would like to connect the hid device profile
634      * @return true if the connection is successful, false otherwise
635      */
connect(BluetoothDevice device)636     public synchronized boolean connect(BluetoothDevice device) {
637         if (DBG) {
638             Log.d(TAG, "connect(): device=" + device);
639         }
640 
641         return checkCallingUid() && mHidDeviceNativeInterface.connect(device);
642     }
643 
644     /**
645      * Disconnects the hid device profile for the remote bluetooth device
646      *
647      * @param device is the device with which we would like to disconnect the hid device profile
648      * @return true if the disconnection is successful, false otherwise
649      */
disconnect(BluetoothDevice device)650     public synchronized boolean disconnect(BluetoothDevice device) {
651         if (DBG) {
652             Log.d(TAG, "disconnect(): device=" + device);
653         }
654 
655         int callingUid = Binder.getCallingUid();
656         if (callingUid != mUserUid && callingUid >= Process.FIRST_APPLICATION_UID) {
657             Log.w(TAG, "disconnect(): caller UID doesn't match user UID");
658             return false;
659         }
660         return checkDevice(device) && mHidDeviceNativeInterface.disconnect();
661     }
662 
663     /**
664      * Connects Hid Device if connectionPolicy is {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}
665      * and disconnects Hid device if connectionPolicy is
666      * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}.
667      *
668      * <p> The device should already be paired.
669      * Connection policy can be one of:
670      * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED},
671      * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN},
672      * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN}
673      *
674      * @param device Paired bluetooth device
675      * @param connectionPolicy determines whether hid device should be connected or disconnected
676      * @return true if hid device is connected or disconnected, false otherwise
677      */
678     @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
setConnectionPolicy(BluetoothDevice device, int connectionPolicy)679     public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
680         enforceCallingOrSelfPermission(
681                 BLUETOOTH_PRIVILEGED, "Need BLUETOOTH_PRIVILEGED permission");
682         if (DBG) {
683             Log.d(TAG, "Saved connectionPolicy " + device + " = " + connectionPolicy);
684         }
685 
686         if (!mDatabaseManager.setProfileConnectionPolicy(device, BluetoothProfile.HID_DEVICE,
687                   connectionPolicy)) {
688             return false;
689         }
690         if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) {
691             disconnect(device);
692         }
693         return true;
694     }
695 
696     /**
697      * Get the connection policy of the profile.
698      *
699      * <p> The connection policy can be any of:
700      * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED},
701      * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN},
702      * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN}
703      *
704      * @param device Bluetooth device
705      * @return connection policy of the device
706      * @hide
707      */
708     @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
getConnectionPolicy(BluetoothDevice device)709     public int getConnectionPolicy(BluetoothDevice device) {
710         if (device == null) {
711             throw new IllegalArgumentException("Null device");
712         }
713         enforceCallingOrSelfPermission(
714                 BLUETOOTH_PRIVILEGED, "Need BLUETOOTH_PRIVILEGED permission");
715         return mDatabaseManager
716                 .getProfileConnectionPolicy(device, BluetoothProfile.HID_DEVICE);
717     }
718 
reportError(BluetoothDevice device, byte error)719     synchronized boolean reportError(BluetoothDevice device, byte error) {
720         if (DBG) {
721             Log.d(TAG, "reportError(): device=" + device + " error=" + error);
722         }
723 
724         return checkDevice(device) && checkCallingUid()
725                 && mHidDeviceNativeInterface.reportError(error);
726     }
727 
getUserAppName()728     synchronized String getUserAppName() {
729         if (mUserUid < Process.FIRST_APPLICATION_UID) {
730             return "";
731         }
732         String appName = getPackageManager().getNameForUid(mUserUid);
733         return appName != null ? appName : "";
734     }
735 
736     @Override
start()737     protected boolean start() {
738         if (DBG) {
739             Log.d(TAG, "start()");
740         }
741 
742         mDatabaseManager = Objects.requireNonNull(AdapterService.getAdapterService().getDatabase(),
743                 "DatabaseManager cannot be null when HidDeviceService starts");
744 
745         mHandler = new HidDeviceServiceHandler();
746         mHidDeviceNativeInterface = HidDeviceNativeInterface.getInstance();
747         mHidDeviceNativeInterface.init();
748         mNativeAvailable = true;
749         mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
750         mActivityManager.addOnUidImportanceListener(mUidImportanceListener,
751                 FOREGROUND_IMPORTANCE_CUTOFF);
752         setHidDeviceService(this);
753         return true;
754     }
755 
756     @Override
stop()757     protected boolean stop() {
758         if (DBG) {
759             Log.d(TAG, "stop()");
760         }
761 
762         if (sHidDeviceService == null) {
763             Log.w(TAG, "stop() called before start()");
764             return true;
765         }
766 
767         setHidDeviceService(null);
768         if (mNativeAvailable) {
769             mHidDeviceNativeInterface.cleanup();
770             mNativeAvailable = false;
771         }
772         mActivityManager.removeOnUidImportanceListener(mUidImportanceListener);
773         return true;
774     }
775 
776     @Override
onUnbind(Intent intent)777     public boolean onUnbind(Intent intent) {
778         Log.d(TAG, "Need to unregister app");
779         unregisterApp();
780         return super.onUnbind(intent);
781     }
782 
783     /**
784      * Get the HID Device Service instance
785      * @return HID Device Service instance
786      */
getHidDeviceService()787     public static synchronized HidDeviceService getHidDeviceService() {
788         if (sHidDeviceService == null) {
789             Log.d(TAG, "getHidDeviceService(): service is NULL");
790             return null;
791         }
792         if (!sHidDeviceService.isAvailable()) {
793             Log.d(TAG, "getHidDeviceService(): service is not available");
794             return null;
795         }
796         return sHidDeviceService;
797     }
798 
setHidDeviceService(HidDeviceService instance)799     private static synchronized void setHidDeviceService(HidDeviceService instance) {
800         if (DBG) {
801             Log.d(TAG, "setHidDeviceService(): set to: " + instance);
802         }
803         sHidDeviceService = instance;
804     }
805 
806     /**
807      * Gets the connections state for the hid device profile for the passed in device
808      *
809      * @param device is the device whose conenction state we want to verify
810      * @return current connection state, one of {@link BluetoothProfile#STATE_DISCONNECTED},
811      * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_CONNECTED}, or
812      * {@link BluetoothProfile#STATE_DISCONNECTING}
813      */
getConnectionState(BluetoothDevice device)814     public int getConnectionState(BluetoothDevice device) {
815         if (mHidDevice != null && mHidDevice.equals(device)) {
816             return mHidDeviceState;
817         }
818         return BluetoothHidDevice.STATE_DISCONNECTED;
819     }
820 
getDevicesMatchingConnectionStates(int[] states)821     List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
822         List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>();
823 
824         if (mHidDevice != null) {
825             for (int state : states) {
826                 if (state == mHidDeviceState) {
827                     inputDevices.add(mHidDevice);
828                     break;
829                 }
830             }
831         }
832         return inputDevices;
833     }
834 
onApplicationStateChangedFromNative(BluetoothDevice device, boolean registered)835     synchronized void onApplicationStateChangedFromNative(BluetoothDevice device,
836             boolean registered) {
837         if (DBG) {
838             Log.d(TAG, "onApplicationStateChanged(): registered=" + registered);
839         }
840 
841         Message msg = mHandler.obtainMessage(MESSAGE_APPLICATION_STATE_CHANGED);
842         msg.obj = device;
843         msg.arg1 = registered ? 1 : 0;
844         mHandler.sendMessage(msg);
845     }
846 
onConnectStateChangedFromNative(BluetoothDevice device, int state)847     synchronized void onConnectStateChangedFromNative(BluetoothDevice device, int state) {
848         if (DBG) {
849             Log.d(TAG, "onConnectStateChanged(): device="
850                     + device + " state=" + state);
851         }
852 
853         Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED);
854         msg.obj = device;
855         msg.arg1 = state;
856         mHandler.sendMessage(msg);
857     }
858 
onGetReportFromNative(byte type, byte id, short bufferSize)859     synchronized void onGetReportFromNative(byte type, byte id, short bufferSize) {
860         if (DBG) {
861             Log.d(TAG, "onGetReport(): type=" + type + " id=" + id + " bufferSize=" + bufferSize);
862         }
863 
864         Message msg = mHandler.obtainMessage(MESSAGE_GET_REPORT);
865         msg.obj = bufferSize > 0 ? new Integer(bufferSize) : null;
866         msg.arg1 = type;
867         msg.arg2 = id;
868         mHandler.sendMessage(msg);
869     }
870 
onSetReportFromNative(byte reportType, byte reportId, byte[] data)871     synchronized void onSetReportFromNative(byte reportType, byte reportId, byte[] data) {
872         if (DBG) {
873             Log.d(TAG, "onSetReport(): reportType=" + reportType + " reportId=" + reportId);
874         }
875 
876         ByteBuffer bb = ByteBuffer.wrap(data);
877 
878         Message msg = mHandler.obtainMessage(MESSAGE_SET_REPORT);
879         msg.arg1 = reportType;
880         msg.arg2 = reportId;
881         msg.obj = bb;
882         mHandler.sendMessage(msg);
883     }
884 
onSetProtocolFromNative(byte protocol)885     synchronized void onSetProtocolFromNative(byte protocol) {
886         if (DBG) {
887             Log.d(TAG, "onSetProtocol(): protocol=" + protocol);
888         }
889 
890         Message msg = mHandler.obtainMessage(MESSAGE_SET_PROTOCOL);
891         msg.arg1 = protocol;
892         mHandler.sendMessage(msg);
893     }
894 
onInterruptDataFromNative(byte reportId, byte[] data)895     synchronized void onInterruptDataFromNative(byte reportId, byte[] data) {
896         if (DBG) {
897             Log.d(TAG, "onInterruptData(): reportId=" + reportId);
898         }
899 
900         ByteBuffer bb = ByteBuffer.wrap(data);
901 
902         Message msg = mHandler.obtainMessage(MESSAGE_INTR_DATA);
903         msg.arg1 = reportId;
904         msg.obj = bb;
905         mHandler.sendMessage(msg);
906     }
907 
onVirtualCableUnplugFromNative()908     synchronized void onVirtualCableUnplugFromNative() {
909         if (DBG) {
910             Log.d(TAG, "onVirtualCableUnplug()");
911         }
912 
913         Message msg = mHandler.obtainMessage(MESSAGE_VC_UNPLUG);
914         mHandler.sendMessage(msg);
915     }
916 
setAndBroadcastConnectionState(BluetoothDevice device, int newState)917     private void setAndBroadcastConnectionState(BluetoothDevice device, int newState) {
918         if (DBG) {
919             Log.d(TAG, "setAndBroadcastConnectionState(): device=" + device.getAddress()
920                     + " oldState=" + mHidDeviceState + " newState=" + newState);
921         }
922 
923         if (mHidDevice != null && !mHidDevice.equals(device)) {
924             Log.w(TAG, "Connection state changed for unknown device, ignoring");
925             return;
926         }
927 
928         int prevState = mHidDeviceState;
929         mHidDeviceState = newState;
930 
931         if (prevState == newState) {
932             Log.w(TAG, "Connection state is unchanged, ignoring");
933             return;
934         }
935 
936         if (newState == BluetoothProfile.STATE_CONNECTED) {
937             MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.HID_DEVICE);
938         }
939 
940         Intent intent = new Intent(BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED);
941         intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState);
942         intent.putExtra(BluetoothProfile.EXTRA_STATE, newState);
943         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
944         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
945         sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions());
946     }
947 
convertHalState(int halState)948     private static int convertHalState(int halState) {
949         switch (halState) {
950             case HAL_CONN_STATE_CONNECTED:
951                 return BluetoothProfile.STATE_CONNECTED;
952             case HAL_CONN_STATE_CONNECTING:
953                 return BluetoothProfile.STATE_CONNECTING;
954             case HAL_CONN_STATE_DISCONNECTED:
955                 return BluetoothProfile.STATE_DISCONNECTED;
956             case HAL_CONN_STATE_DISCONNECTING:
957                 return BluetoothProfile.STATE_DISCONNECTING;
958             default:
959                 return BluetoothProfile.STATE_DISCONNECTED;
960         }
961     }
962 
963     static final int HAL_CONN_STATE_CONNECTED = 0;
964     static final int HAL_CONN_STATE_CONNECTING = 1;
965     static final int HAL_CONN_STATE_DISCONNECTED = 2;
966     static final int HAL_CONN_STATE_DISCONNECTING = 3;
967 }
968