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