• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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 #define LOG_TAG "BluetoothHidHostServiceJni"
18 
19 #define LOG_NDEBUG 1
20 
21 #include "com_android_bluetooth.h"
22 #include "hardware/bt_hh.h"
23 #include "utils/Log.h"
24 
25 #include <string.h>
26 #include <shared_mutex>
27 namespace android {
28 
29 static jmethodID method_onConnectStateChanged;
30 static jmethodID method_onGetProtocolMode;
31 static jmethodID method_onGetReport;
32 static jmethodID method_onHandshake;
33 static jmethodID method_onVirtualUnplug;
34 static jmethodID method_onGetIdleTime;
35 
36 static const bthh_interface_t* sBluetoothHidInterface = NULL;
37 static jobject mCallbacksObj = NULL;
38 static std::shared_timed_mutex mCallbacks_mutex;
39 
marshall_bda(RawAddress * bd_addr)40 static jbyteArray marshall_bda(RawAddress* bd_addr) {
41   CallbackEnv sCallbackEnv(__func__);
42   if (!sCallbackEnv.valid()) return NULL;
43 
44   jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(RawAddress));
45   if (!addr) {
46     ALOGE("Fail to new jbyteArray bd addr");
47     return NULL;
48   }
49   sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(RawAddress),
50                                    (jbyte*)bd_addr);
51   return addr;
52 }
53 
connection_state_callback(RawAddress * bd_addr,bthh_connection_state_t state)54 static void connection_state_callback(RawAddress* bd_addr,
55                                       bthh_connection_state_t state) {
56   std::shared_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
57   CallbackEnv sCallbackEnv(__func__);
58   if (!sCallbackEnv.valid()) return;
59   if (!mCallbacksObj) {
60     ALOGE("%s: mCallbacksObj is null", __func__);
61     return;
62   }
63   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
64   if (!addr.get()) {
65     ALOGE("Fail to new jbyteArray bd addr for HID channel state");
66     return;
67   }
68 
69   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged,
70                                addr.get(), (jint)state);
71 }
72 
get_protocol_mode_callback(RawAddress * bd_addr,bthh_status_t hh_status,bthh_protocol_mode_t mode)73 static void get_protocol_mode_callback(RawAddress* bd_addr,
74                                        bthh_status_t hh_status,
75                                        bthh_protocol_mode_t mode) {
76   std::shared_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
77   CallbackEnv sCallbackEnv(__func__);
78   if (!sCallbackEnv.valid()) return;
79   if (!mCallbacksObj) {
80     ALOGE("%s: mCallbacksObj is null", __func__);
81     return;
82   }
83   if (hh_status != BTHH_OK) {
84     ALOGE("BTHH Status is not OK!");
85     return;
86   }
87 
88   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
89   if (!addr.get()) {
90     ALOGE("Fail to new jbyteArray bd addr for get protocal mode callback");
91     return;
92   }
93 
94   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetProtocolMode,
95                                addr.get(), (jint)mode);
96 }
97 
get_report_callback(RawAddress * bd_addr,bthh_status_t hh_status,uint8_t * rpt_data,int rpt_size)98 static void get_report_callback(RawAddress* bd_addr, bthh_status_t hh_status,
99                                 uint8_t* rpt_data, int rpt_size) {
100   std::shared_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
101   CallbackEnv sCallbackEnv(__func__);
102   if (!sCallbackEnv.valid()) return;
103   if (!mCallbacksObj) {
104     ALOGE("%s: mCallbacksObj is null", __func__);
105     return;
106   }
107   if (hh_status != BTHH_OK) {
108     ALOGE("BTHH Status is not OK!");
109     return;
110   }
111 
112   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
113   if (!addr.get()) {
114     ALOGE("Fail to new jbyteArray bd addr for get report callback");
115     return;
116   }
117   ScopedLocalRef<jbyteArray> data(sCallbackEnv.get(),
118                                   sCallbackEnv->NewByteArray(rpt_size));
119   if (!data.get()) {
120     ALOGE("Fail to new jbyteArray data for get report callback");
121     return;
122   }
123 
124   sCallbackEnv->SetByteArrayRegion(data.get(), 0, rpt_size, (jbyte*)rpt_data);
125   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetReport, addr.get(),
126                                data.get(), (jint)rpt_size);
127 }
128 
virtual_unplug_callback(RawAddress * bd_addr,bthh_status_t hh_status)129 static void virtual_unplug_callback(RawAddress* bd_addr,
130                                     bthh_status_t hh_status) {
131   ALOGV("call to virtual_unplug_callback");
132   std::shared_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
133   CallbackEnv sCallbackEnv(__func__);
134   if (!sCallbackEnv.valid()) return;
135   if (!mCallbacksObj) {
136     ALOGE("%s: mCallbacksObj is null", __func__);
137     return;
138   }
139   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
140   if (!addr.get()) {
141     ALOGE("Fail to new jbyteArray bd addr for HID channel state");
142     return;
143   }
144   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualUnplug,
145                                addr.get(), (jint)hh_status);
146 }
147 
handshake_callback(RawAddress * bd_addr,bthh_status_t hh_status)148 static void handshake_callback(RawAddress* bd_addr, bthh_status_t hh_status) {
149   std::shared_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
150   CallbackEnv sCallbackEnv(__func__);
151   if (!sCallbackEnv.valid()) return;
152   if (!mCallbacksObj) {
153     ALOGE("%s: mCallbacksObj is null", __func__);
154     return;
155   }
156 
157   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
158   if (!addr.get()) {
159     ALOGE("Fail to new jbyteArray bd addr for handshake callback");
160     return;
161   }
162   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onHandshake, addr.get(),
163                                (jint)hh_status);
164 }
165 
get_idle_time_callback(RawAddress * bd_addr,bthh_status_t hh_status,int idle_time)166 static void get_idle_time_callback(RawAddress* bd_addr, bthh_status_t hh_status,
167                                    int idle_time) {
168   std::shared_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
169   CallbackEnv sCallbackEnv(__func__);
170   if (!sCallbackEnv.valid()) return;
171 
172   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
173   if (!addr.get()) {
174     ALOGE("%s: Fail to new jbyteArray bd addr", __func__);
175     return;
176   }
177   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetIdleTime, addr.get(),
178                                (jint)idle_time);
179 }
180 
181 static bthh_callbacks_t sBluetoothHidCallbacks = {
182     sizeof(sBluetoothHidCallbacks),
183     connection_state_callback,
184     NULL,
185     get_protocol_mode_callback,
186     get_idle_time_callback,
187     get_report_callback,
188     virtual_unplug_callback,
189     handshake_callback};
190 
191 // Define native functions
192 
classInitNative(JNIEnv * env,jclass clazz)193 static void classInitNative(JNIEnv* env, jclass clazz) {
194   method_onConnectStateChanged =
195       env->GetMethodID(clazz, "onConnectStateChanged", "([BI)V");
196   method_onGetProtocolMode =
197       env->GetMethodID(clazz, "onGetProtocolMode", "([BI)V");
198   method_onGetReport = env->GetMethodID(clazz, "onGetReport", "([B[BI)V");
199   method_onHandshake = env->GetMethodID(clazz, "onHandshake", "([BI)V");
200   method_onVirtualUnplug = env->GetMethodID(clazz, "onVirtualUnplug", "([BI)V");
201   method_onGetIdleTime = env->GetMethodID(clazz, "onGetIdleTime", "([BI)V");
202 
203   ALOGI("%s: succeeds", __func__);
204 }
205 
initializeNative(JNIEnv * env,jobject object)206 static void initializeNative(JNIEnv* env, jobject object) {
207   std::unique_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
208   const bt_interface_t* btInf = getBluetoothInterface();
209   if (btInf == NULL) {
210     ALOGE("Bluetooth module is not loaded");
211     return;
212   }
213 
214   if (sBluetoothHidInterface != NULL) {
215     ALOGW("Cleaning up Bluetooth HID Interface before initializing...");
216     sBluetoothHidInterface->cleanup();
217     sBluetoothHidInterface = NULL;
218   }
219 
220   if (mCallbacksObj != NULL) {
221     ALOGW("Cleaning up Bluetooth GID callback object");
222     env->DeleteGlobalRef(mCallbacksObj);
223     mCallbacksObj = NULL;
224   }
225 
226   sBluetoothHidInterface =
227       (bthh_interface_t*)btInf->get_profile_interface(BT_PROFILE_HIDHOST_ID);
228   if (sBluetoothHidInterface == NULL) {
229     ALOGE("Failed to get Bluetooth HID Interface");
230     return;
231   }
232 
233   bt_status_t status = sBluetoothHidInterface->init(&sBluetoothHidCallbacks);
234   if (status != BT_STATUS_SUCCESS) {
235     ALOGE("Failed to initialize Bluetooth HID, status: %d", status);
236     sBluetoothHidInterface = NULL;
237     return;
238   }
239 
240   mCallbacksObj = env->NewGlobalRef(object);
241 }
242 
cleanupNative(JNIEnv * env,jobject object)243 static void cleanupNative(JNIEnv* env, jobject object) {
244   std::unique_lock<std::shared_timed_mutex> lock(mCallbacks_mutex);
245   const bt_interface_t* btInf = getBluetoothInterface();
246 
247   if (btInf == NULL) {
248     ALOGE("Bluetooth module is not loaded");
249     return;
250   }
251 
252   if (sBluetoothHidInterface != NULL) {
253     ALOGW("Cleaning up Bluetooth HID Interface...");
254     sBluetoothHidInterface->cleanup();
255     sBluetoothHidInterface = NULL;
256   }
257 
258   if (mCallbacksObj != NULL) {
259     ALOGW("Cleaning up Bluetooth GID callback object");
260     env->DeleteGlobalRef(mCallbacksObj);
261     mCallbacksObj = NULL;
262   }
263 }
264 
connectHidNative(JNIEnv * env,jobject object,jbyteArray address)265 static jboolean connectHidNative(JNIEnv* env, jobject object,
266                                  jbyteArray address) {
267   if (!sBluetoothHidInterface) return JNI_FALSE;
268 
269   jbyte* addr = env->GetByteArrayElements(address, NULL);
270   if (!addr) {
271     ALOGE("Bluetooth device address null");
272     return JNI_FALSE;
273   }
274 
275   jboolean ret = JNI_TRUE;
276   bt_status_t status = sBluetoothHidInterface->connect((RawAddress*)addr);
277   if (status != BT_STATUS_SUCCESS && status != BT_STATUS_BUSY) {
278     ALOGE("Failed HID channel connection, status: %d", status);
279     ret = JNI_FALSE;
280   }
281   env->ReleaseByteArrayElements(address, addr, 0);
282 
283   return ret;
284 }
285 
disconnectHidNative(JNIEnv * env,jobject object,jbyteArray address)286 static jboolean disconnectHidNative(JNIEnv* env, jobject object,
287                                     jbyteArray address) {
288   jbyte* addr;
289   jboolean ret = JNI_TRUE;
290   if (!sBluetoothHidInterface) return JNI_FALSE;
291 
292   addr = env->GetByteArrayElements(address, NULL);
293   if (!addr) {
294     ALOGE("Bluetooth device address null");
295     return JNI_FALSE;
296   }
297 
298   bt_status_t status = sBluetoothHidInterface->disconnect((RawAddress*)addr);
299   if (status != BT_STATUS_SUCCESS) {
300     ALOGE("Failed disconnect hid channel, status: %d", status);
301     ret = JNI_FALSE;
302   }
303   env->ReleaseByteArrayElements(address, addr, 0);
304 
305   return ret;
306 }
307 
getProtocolModeNative(JNIEnv * env,jobject object,jbyteArray address)308 static jboolean getProtocolModeNative(JNIEnv* env, jobject object,
309                                       jbyteArray address) {
310   if (!sBluetoothHidInterface) return JNI_FALSE;
311 
312   jbyte* addr = env->GetByteArrayElements(address, NULL);
313   if (!addr) {
314     ALOGE("Bluetooth device address null");
315     return JNI_FALSE;
316   }
317 
318   jboolean ret = JNI_TRUE;
319   // TODO: protocolMode is unused by the backend: see b/28908173
320   bthh_protocol_mode_t protocolMode = BTHH_UNSUPPORTED_MODE;
321   bt_status_t status = sBluetoothHidInterface->get_protocol(
322       (RawAddress*)addr, (bthh_protocol_mode_t)protocolMode);
323   if (status != BT_STATUS_SUCCESS) {
324     ALOGE("Failed get protocol mode, status: %d", status);
325     ret = JNI_FALSE;
326   }
327   env->ReleaseByteArrayElements(address, addr, 0);
328 
329   return ret;
330 }
331 
virtualUnPlugNative(JNIEnv * env,jobject object,jbyteArray address)332 static jboolean virtualUnPlugNative(JNIEnv* env, jobject object,
333                                     jbyteArray address) {
334   if (!sBluetoothHidInterface) return JNI_FALSE;
335 
336   jbyte* addr = env->GetByteArrayElements(address, NULL);
337   if (!addr) {
338     ALOGE("Bluetooth device address null");
339     return JNI_FALSE;
340   }
341 
342   jboolean ret = JNI_TRUE;
343   bt_status_t status =
344       sBluetoothHidInterface->virtual_unplug((RawAddress*)addr);
345   if (status != BT_STATUS_SUCCESS) {
346     ALOGE("Failed virual unplug, status: %d", status);
347     ret = JNI_FALSE;
348   }
349   env->ReleaseByteArrayElements(address, addr, 0);
350   return ret;
351 }
352 
setProtocolModeNative(JNIEnv * env,jobject object,jbyteArray address,jint protocolMode)353 static jboolean setProtocolModeNative(JNIEnv* env, jobject object,
354                                       jbyteArray address, jint protocolMode) {
355   if (!sBluetoothHidInterface) return JNI_FALSE;
356 
357   ALOGD("%s: protocolMode = %d", __func__, protocolMode);
358 
359   jbyte* addr = env->GetByteArrayElements(address, NULL);
360   if (!addr) {
361     ALOGE("Bluetooth device address null");
362     return JNI_FALSE;
363   }
364 
365   bthh_protocol_mode_t mode;
366   switch (protocolMode) {
367     case 0:
368       mode = BTHH_REPORT_MODE;
369       break;
370     case 1:
371       mode = BTHH_BOOT_MODE;
372       break;
373     default:
374       ALOGE("Unknown HID protocol mode");
375       return JNI_FALSE;
376   }
377 
378   jboolean ret = JNI_TRUE;
379   bt_status_t status =
380       sBluetoothHidInterface->set_protocol((RawAddress*)addr, mode);
381   if (status != BT_STATUS_SUCCESS) {
382     ALOGE("Failed set protocol mode, status: %d", status);
383     ret = JNI_FALSE;
384   }
385   env->ReleaseByteArrayElements(address, addr, 0);
386 
387   return ret;
388 }
389 
getReportNative(JNIEnv * env,jobject object,jbyteArray address,jbyte reportType,jbyte reportId,jint bufferSize)390 static jboolean getReportNative(JNIEnv* env, jobject object, jbyteArray address,
391                                 jbyte reportType, jbyte reportId,
392                                 jint bufferSize) {
393   ALOGV("%s: reportType = %d, reportId = %d, bufferSize = %d", __func__,
394         reportType, reportId, bufferSize);
395   if (!sBluetoothHidInterface) return JNI_FALSE;
396 
397   jbyte* addr = env->GetByteArrayElements(address, NULL);
398   if (!addr) {
399     ALOGE("Bluetooth device address null");
400     return JNI_FALSE;
401   }
402 
403   jint rType = reportType;
404   jint rId = reportId;
405 
406   bt_status_t status = sBluetoothHidInterface->get_report(
407       (RawAddress*)addr, (bthh_report_type_t)rType, (uint8_t)rId, bufferSize);
408   jboolean ret = JNI_TRUE;
409   if (status != BT_STATUS_SUCCESS) {
410     ALOGE("Failed get report, status: %d", status);
411     ret = JNI_FALSE;
412   }
413   env->ReleaseByteArrayElements(address, addr, 0);
414 
415   return ret;
416 }
417 
setReportNative(JNIEnv * env,jobject object,jbyteArray address,jbyte reportType,jstring report)418 static jboolean setReportNative(JNIEnv* env, jobject object, jbyteArray address,
419                                 jbyte reportType, jstring report) {
420   ALOGV("%s: reportType = %d", __func__, reportType);
421   if (!sBluetoothHidInterface) return JNI_FALSE;
422 
423   jbyte* addr = env->GetByteArrayElements(address, NULL);
424   if (!addr) {
425     ALOGE("Bluetooth device address null");
426     return JNI_FALSE;
427   }
428   jint rType = reportType;
429   const char* c_report = env->GetStringUTFChars(report, NULL);
430 
431   jboolean ret = JNI_TRUE;
432   bt_status_t status = sBluetoothHidInterface->set_report(
433       (RawAddress*)addr, (bthh_report_type_t)rType, (char*)c_report);
434   if (status != BT_STATUS_SUCCESS) {
435     ALOGE("Failed set report, status: %d", status);
436     ret = JNI_FALSE;
437   }
438   env->ReleaseStringUTFChars(report, c_report);
439   env->ReleaseByteArrayElements(address, addr, 0);
440 
441   return ret;
442 }
443 
sendDataNative(JNIEnv * env,jobject object,jbyteArray address,jstring report)444 static jboolean sendDataNative(JNIEnv* env, jobject object, jbyteArray address,
445                                jstring report) {
446   ALOGV("%s", __func__);
447   jboolean ret = JNI_TRUE;
448   if (!sBluetoothHidInterface) return JNI_FALSE;
449 
450   jbyte* addr = env->GetByteArrayElements(address, NULL);
451   if (!addr) {
452     ALOGE("Bluetooth device address null");
453     return JNI_FALSE;
454   }
455 
456   const char* c_report = env->GetStringUTFChars(report, NULL);
457 
458   bt_status_t status =
459       sBluetoothHidInterface->send_data((RawAddress*)addr, (char*)c_report);
460   if (status != BT_STATUS_SUCCESS) {
461     ALOGE("Failed set data, status: %d", status);
462     ret = JNI_FALSE;
463   }
464   env->ReleaseStringUTFChars(report, c_report);
465   env->ReleaseByteArrayElements(address, addr, 0);
466 
467   return ret;
468 }
469 
getIdleTimeNative(JNIEnv * env,jobject object,jbyteArray address)470 static jboolean getIdleTimeNative(JNIEnv* env, jobject object,
471                                   jbyteArray address) {
472   if (!sBluetoothHidInterface) return JNI_FALSE;
473 
474   jbyte* addr = env->GetByteArrayElements(address, NULL);
475   if (!addr) {
476     ALOGE("%s: Bluetooth device address null", __func__);
477     return JNI_FALSE;
478   }
479 
480   bt_status_t status = sBluetoothHidInterface->get_idle_time((RawAddress*)addr);
481   if (status != BT_STATUS_SUCCESS) {
482     ALOGE("%s: Failed get idle time, status: %d", __func__, status);
483   }
484   env->ReleaseByteArrayElements(address, addr, 0);
485 
486   return status == BT_STATUS_SUCCESS ? JNI_TRUE : JNI_FALSE;
487 }
488 
setIdleTimeNative(JNIEnv * env,jobject object,jbyteArray address,jbyte idle_time)489 static jboolean setIdleTimeNative(JNIEnv* env, jobject object,
490                                   jbyteArray address, jbyte idle_time) {
491   if (!sBluetoothHidInterface) return JNI_FALSE;
492 
493   jbyte* addr = env->GetByteArrayElements(address, NULL);
494   if (!addr) {
495     ALOGE("%s: Bluetooth device address null", __func__);
496     return JNI_FALSE;
497   }
498 
499   bt_status_t status =
500       sBluetoothHidInterface->set_idle_time((RawAddress*)addr, idle_time);
501   if (status != BT_STATUS_SUCCESS) {
502     ALOGE("%s: Failed set idle time, status: %d", __func__, status);
503   }
504   env->ReleaseByteArrayElements(address, addr, 0);
505 
506   return status == BT_STATUS_SUCCESS ? JNI_TRUE : JNI_FALSE;
507 }
508 
509 static JNINativeMethod sMethods[] = {
510     {"classInitNative", "()V", (void*)classInitNative},
511     {"initializeNative", "()V", (void*)initializeNative},
512     {"cleanupNative", "()V", (void*)cleanupNative},
513     {"connectHidNative", "([B)Z", (void*)connectHidNative},
514     {"disconnectHidNative", "([B)Z", (void*)disconnectHidNative},
515     {"getProtocolModeNative", "([B)Z", (void*)getProtocolModeNative},
516     {"virtualUnPlugNative", "([B)Z", (void*)virtualUnPlugNative},
517     {"setProtocolModeNative", "([BB)Z", (void*)setProtocolModeNative},
518     {"getReportNative", "([BBBI)Z", (void*)getReportNative},
519     {"setReportNative", "([BBLjava/lang/String;)Z", (void*)setReportNative},
520     {"sendDataNative", "([BLjava/lang/String;)Z", (void*)sendDataNative},
521     {"getIdleTimeNative", "([B)Z", (void*)getIdleTimeNative},
522     {"setIdleTimeNative", "([BB)Z", (void*)setIdleTimeNative},
523 };
524 
register_com_android_bluetooth_hid_host(JNIEnv * env)525 int register_com_android_bluetooth_hid_host(JNIEnv* env) {
526   return jniRegisterNativeMethods(env,
527                                   "com/android/bluetooth/hid/HidHostService",
528                                   sMethods, NELEM(sMethods));
529 }
530 }  // namespace android
531