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