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