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 #define LOG_TAG "BluetoothHidDeviceServiceJni"
18
19 #define LOG_NDEBUG 0
20
21 #include "android_runtime/AndroidRuntime.h"
22 #include "com_android_bluetooth.h"
23 #include "hardware/bt_hd.h"
24 #include "utils/Log.h"
25
26 #include <string.h>
27
28 namespace android {
29
30 static jmethodID method_onApplicationStateChanged;
31 static jmethodID method_onConnectStateChanged;
32 static jmethodID method_onGetReport;
33 static jmethodID method_onSetReport;
34 static jmethodID method_onSetProtocol;
35 static jmethodID method_onInterruptData;
36 static jmethodID method_onVirtualCableUnplug;
37
38 static const bthd_interface_t* sHiddIf = NULL;
39 static jobject mCallbacksObj = NULL;
40
marshall_bda(RawAddress * bd_addr)41 static jbyteArray marshall_bda(RawAddress* bd_addr) {
42 CallbackEnv sCallbackEnv(__func__);
43 if (!sCallbackEnv.valid()) return NULL;
44
45 jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(RawAddress));
46 if (!addr) {
47 ALOGE("Fail to new jbyteArray bd addr");
48 return NULL;
49 }
50 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(RawAddress),
51 (jbyte*)bd_addr);
52 return addr;
53 }
54
application_state_callback(RawAddress * bd_addr,bthd_application_state_t state)55 static void application_state_callback(RawAddress* bd_addr,
56 bthd_application_state_t state) {
57 jboolean registered = JNI_FALSE;
58
59 CallbackEnv sCallbackEnv(__func__);
60
61 if (state == BTHD_APP_STATE_REGISTERED) {
62 registered = JNI_TRUE;
63 }
64
65 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), NULL);
66
67 if (bd_addr) {
68 addr.reset(marshall_bda(bd_addr));
69 if (!addr.get()) {
70 ALOGE("%s: failed to allocate storage for bt_addr", __FUNCTION__);
71 return;
72 }
73 }
74
75 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onApplicationStateChanged,
76 addr.get(), registered);
77 }
78
connection_state_callback(RawAddress * bd_addr,bthd_connection_state_t state)79 static void connection_state_callback(RawAddress* bd_addr,
80 bthd_connection_state_t state) {
81 CallbackEnv sCallbackEnv(__func__);
82
83 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
84 if (!addr.get()) {
85 ALOGE("%s: failed to allocate storage for bt_addr", __FUNCTION__);
86 return;
87 }
88
89 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged,
90 addr.get(), (jint)state);
91 }
92
get_report_callback(uint8_t type,uint8_t id,uint16_t buffer_size)93 static void get_report_callback(uint8_t type, uint8_t id,
94 uint16_t buffer_size) {
95 CallbackEnv sCallbackEnv(__func__);
96
97 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetReport, type, id,
98 buffer_size);
99 }
100
set_report_callback(uint8_t type,uint8_t id,uint16_t len,uint8_t * p_data)101 static void set_report_callback(uint8_t type, uint8_t id, uint16_t len,
102 uint8_t* p_data) {
103 CallbackEnv sCallbackEnv(__func__);
104
105 ScopedLocalRef<jbyteArray> data(sCallbackEnv.get(),
106 sCallbackEnv->NewByteArray(len));
107 if (!data.get()) {
108 ALOGE("%s: failed to allocate storage for report data", __FUNCTION__);
109 return;
110 }
111 sCallbackEnv->SetByteArrayRegion(data.get(), 0, len, (jbyte*)p_data);
112
113 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSetReport, (jbyte)type,
114 (jbyte)id, data.get());
115 }
116
set_protocol_callback(uint8_t protocol)117 static void set_protocol_callback(uint8_t protocol) {
118 CallbackEnv sCallbackEnv(__func__);
119
120 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSetProtocol, protocol);
121 }
122
intr_data_callback(uint8_t report_id,uint16_t len,uint8_t * p_data)123 static void intr_data_callback(uint8_t report_id, uint16_t len,
124 uint8_t* p_data) {
125 CallbackEnv sCallbackEnv(__func__);
126
127 ScopedLocalRef<jbyteArray> data(sCallbackEnv.get(),
128 sCallbackEnv->NewByteArray(len));
129 if (!data.get()) {
130 ALOGE("%s: failed to allocate storage for report data", __FUNCTION__);
131 return;
132 }
133 sCallbackEnv->SetByteArrayRegion(data.get(), 0, len, (jbyte*)p_data);
134
135 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onInterruptData,
136 (jbyte)report_id, data.get());
137 }
138
vc_unplug_callback(void)139 static void vc_unplug_callback(void) {
140 CallbackEnv sCallbackEnv(__func__);
141 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualCableUnplug);
142 }
143
144 static bthd_callbacks_t sHiddCb = {
145 sizeof(sHiddCb),
146
147 application_state_callback,
148 connection_state_callback,
149 get_report_callback,
150 set_report_callback,
151 set_protocol_callback,
152 intr_data_callback,
153 vc_unplug_callback,
154 };
155
classInitNative(JNIEnv * env,jclass clazz)156 static void classInitNative(JNIEnv* env, jclass clazz) {
157 ALOGV("%s: done", __FUNCTION__);
158
159 method_onApplicationStateChanged =
160 env->GetMethodID(clazz, "onApplicationStateChanged", "([BZ)V");
161 method_onConnectStateChanged =
162 env->GetMethodID(clazz, "onConnectStateChanged", "([BI)V");
163 method_onGetReport = env->GetMethodID(clazz, "onGetReport", "(BBS)V");
164 method_onSetReport = env->GetMethodID(clazz, "onSetReport", "(BB[B)V");
165 method_onSetProtocol = env->GetMethodID(clazz, "onSetProtocol", "(B)V");
166 method_onInterruptData = env->GetMethodID(clazz, "onInterruptData", "(B[B)V");
167 method_onVirtualCableUnplug =
168 env->GetMethodID(clazz, "onVirtualCableUnplug", "()V");
169 }
170
initNative(JNIEnv * env,jobject object)171 static void initNative(JNIEnv* env, jobject object) {
172 const bt_interface_t* btif;
173 bt_status_t status;
174
175 ALOGV("%s enter", __FUNCTION__);
176
177 if ((btif = getBluetoothInterface()) == NULL) {
178 ALOGE("Cannot obtain BT interface");
179 return;
180 }
181
182 if (sHiddIf != NULL) {
183 ALOGW("Cleaning up interface");
184 sHiddIf->cleanup();
185 sHiddIf = NULL;
186 }
187
188 if (mCallbacksObj != NULL) {
189 ALOGW("Cleaning up callback object");
190 env->DeleteGlobalRef(mCallbacksObj);
191 mCallbacksObj = NULL;
192 }
193
194 if ((sHiddIf = (bthd_interface_t*)btif->get_profile_interface(
195 BT_PROFILE_HIDDEV_ID)) == NULL) {
196 ALOGE("Cannot obtain interface");
197 return;
198 }
199
200 if ((status = sHiddIf->init(&sHiddCb)) != BT_STATUS_SUCCESS) {
201 ALOGE("Failed to initialize interface (%d)", status);
202 sHiddIf = NULL;
203 return;
204 }
205
206 mCallbacksObj = env->NewGlobalRef(object);
207
208 ALOGV("%s done", __FUNCTION__);
209 }
210
cleanupNative(JNIEnv * env,jobject object)211 static void cleanupNative(JNIEnv* env, jobject object) {
212 ALOGV("%s enter", __FUNCTION__);
213
214 if (sHiddIf != NULL) {
215 ALOGI("Cleaning up interface");
216 sHiddIf->cleanup();
217 sHiddIf = NULL;
218 }
219
220 if (mCallbacksObj != NULL) {
221 ALOGI("Cleaning up callback object");
222 env->DeleteGlobalRef(mCallbacksObj);
223 mCallbacksObj = NULL;
224 }
225
226 ALOGV("%s done", __FUNCTION__);
227 }
228
fill_qos(JNIEnv * env,jintArray in,bthd_qos_param_t * out)229 static void fill_qos(JNIEnv* env, jintArray in, bthd_qos_param_t* out) {
230 // set default values
231 out->service_type = 0x01; // best effort
232 out->token_rate = out->token_bucket_size = out->peak_bandwidth =
233 0; // don't care
234 out->access_latency = out->delay_variation = 0xffffffff; // don't care
235
236 if (in == NULL) return;
237
238 jsize len = env->GetArrayLength(in);
239
240 if (len != 6) return;
241
242 uint32_t* buf = (uint32_t*)calloc(len, sizeof(uint32_t));
243
244 if (buf == NULL) return;
245
246 env->GetIntArrayRegion(in, 0, len, (jint*)buf);
247
248 out->service_type = (uint8_t)buf[0];
249 out->token_rate = buf[1];
250 out->token_bucket_size = buf[2];
251 out->peak_bandwidth = buf[3];
252 out->access_latency = buf[4];
253 out->delay_variation = buf[5];
254
255 free(buf);
256 }
257
registerAppNative(JNIEnv * env,jobject thiz,jstring name,jstring description,jstring provider,jbyte subclass,jbyteArray descriptors,jintArray p_in_qos,jintArray p_out_qos)258 static jboolean registerAppNative(JNIEnv* env, jobject thiz, jstring name,
259 jstring description, jstring provider,
260 jbyte subclass, jbyteArray descriptors,
261 jintArray p_in_qos, jintArray p_out_qos) {
262 ALOGV("%s enter", __FUNCTION__);
263
264 if (!sHiddIf) {
265 ALOGE("%s: Failed to get the Bluetooth HIDD Interface", __func__);
266 return JNI_FALSE;
267 }
268
269 jboolean result = JNI_FALSE;
270 bthd_app_param_t app_param;
271 bthd_qos_param_t in_qos;
272 bthd_qos_param_t out_qos;
273 jsize size;
274 uint8_t* data;
275
276 size = env->GetArrayLength(descriptors);
277 data = (uint8_t*)malloc(size);
278
279 if (data != NULL) {
280 env->GetByteArrayRegion(descriptors, 0, size, (jbyte*)data);
281
282 app_param.name = env->GetStringUTFChars(name, NULL);
283 app_param.description = env->GetStringUTFChars(description, NULL);
284 app_param.provider = env->GetStringUTFChars(provider, NULL);
285 app_param.subclass = subclass;
286 app_param.desc_list = data;
287 app_param.desc_list_len = size;
288
289 fill_qos(env, p_in_qos, &in_qos);
290 fill_qos(env, p_out_qos, &out_qos);
291
292 bt_status_t ret = sHiddIf->register_app(&app_param, &in_qos, &out_qos);
293
294 ALOGV("%s: register_app() returned %d", __FUNCTION__, ret);
295
296 if (ret == BT_STATUS_SUCCESS) {
297 result = JNI_TRUE;
298 }
299
300 env->ReleaseStringUTFChars(name, app_param.name);
301 env->ReleaseStringUTFChars(description, app_param.description);
302 env->ReleaseStringUTFChars(provider, app_param.provider);
303
304 free(data);
305 }
306
307 ALOGV("%s done (%d)", __FUNCTION__, result);
308
309 return result;
310 }
311
unregisterAppNative(JNIEnv * env,jobject thiz)312 static jboolean unregisterAppNative(JNIEnv* env, jobject thiz) {
313 ALOGV("%s enter", __FUNCTION__);
314
315 jboolean result = JNI_FALSE;
316
317 if (!sHiddIf) {
318 ALOGE("%s: Failed to get the Bluetooth HIDD Interface", __func__);
319 return JNI_FALSE;
320 }
321
322 bt_status_t ret = sHiddIf->unregister_app();
323
324 ALOGV("%s: unregister_app() returned %d", __FUNCTION__, ret);
325
326 if (ret == BT_STATUS_SUCCESS) {
327 result = JNI_TRUE;
328 }
329
330 ALOGV("%s done (%d)", __FUNCTION__, result);
331
332 return result;
333 }
334
sendReportNative(JNIEnv * env,jobject thiz,jint id,jbyteArray data)335 static jboolean sendReportNative(JNIEnv* env, jobject thiz, jint id,
336 jbyteArray data) {
337 jboolean result = JNI_FALSE;
338
339 if (!sHiddIf) {
340 ALOGE("%s: Failed to get the Bluetooth HIDD Interface", __func__);
341 return JNI_FALSE;
342 }
343
344 jsize size;
345 uint8_t* buf;
346
347 size = env->GetArrayLength(data);
348 buf = (uint8_t*)malloc(size);
349
350 if (buf != NULL) {
351 env->GetByteArrayRegion(data, 0, size, (jbyte*)buf);
352
353 bt_status_t ret =
354 sHiddIf->send_report(BTHD_REPORT_TYPE_INTRDATA, id, size, buf);
355
356 if (ret == BT_STATUS_SUCCESS) {
357 result = JNI_TRUE;
358 }
359
360 free(buf);
361 }
362
363 return result;
364 }
365
replyReportNative(JNIEnv * env,jobject thiz,jbyte type,jbyte id,jbyteArray data)366 static jboolean replyReportNative(JNIEnv* env, jobject thiz, jbyte type,
367 jbyte id, jbyteArray data) {
368 ALOGV("%s enter", __FUNCTION__);
369
370 if (!sHiddIf) {
371 ALOGE("%s: Failed to get the Bluetooth HIDD Interface", __func__);
372 return JNI_FALSE;
373 }
374
375 jboolean result = JNI_FALSE;
376 jsize size;
377 uint8_t* buf;
378
379 size = env->GetArrayLength(data);
380 buf = (uint8_t*)malloc(size);
381
382 if (buf != NULL) {
383 int report_type = (type & 0x03);
384 env->GetByteArrayRegion(data, 0, size, (jbyte*)buf);
385
386 bt_status_t ret =
387 sHiddIf->send_report((bthd_report_type_t)report_type, id, size, buf);
388
389 ALOGV("%s: send_report() returned %d", __FUNCTION__, ret);
390
391 if (ret == BT_STATUS_SUCCESS) {
392 result = JNI_TRUE;
393 }
394
395 free(buf);
396 }
397
398 ALOGV("%s done (%d)", __FUNCTION__, result);
399
400 return result;
401 }
402
reportErrorNative(JNIEnv * env,jobject thiz,jbyte error)403 static jboolean reportErrorNative(JNIEnv* env, jobject thiz, jbyte error) {
404 ALOGV("%s enter", __FUNCTION__);
405
406 if (!sHiddIf) {
407 ALOGE("%s: Failed to get the Bluetooth HIDD Interface", __func__);
408 return JNI_FALSE;
409 }
410
411 jboolean result = JNI_FALSE;
412
413 bt_status_t ret = sHiddIf->report_error(error);
414
415 ALOGV("%s: report_error() returned %d", __FUNCTION__, ret);
416
417 if (ret == BT_STATUS_SUCCESS) {
418 result = JNI_TRUE;
419 }
420
421 ALOGV("%s done (%d)", __FUNCTION__, result);
422
423 return result;
424 }
425
unplugNative(JNIEnv * env,jobject thiz)426 static jboolean unplugNative(JNIEnv* env, jobject thiz) {
427 ALOGV("%s enter", __FUNCTION__);
428
429 if (!sHiddIf) {
430 ALOGE("%s: Failed to get the Bluetooth HIDD Interface", __func__);
431 return JNI_FALSE;
432 }
433
434 jboolean result = JNI_FALSE;
435
436 bt_status_t ret = sHiddIf->virtual_cable_unplug();
437
438 ALOGV("%s: virtual_cable_unplug() returned %d", __FUNCTION__, ret);
439
440 if (ret == BT_STATUS_SUCCESS) {
441 result = JNI_TRUE;
442 }
443
444 ALOGV("%s done (%d)", __FUNCTION__, result);
445
446 return result;
447 }
448
connectNative(JNIEnv * env,jobject thiz,jbyteArray address)449 static jboolean connectNative(JNIEnv* env, jobject thiz, jbyteArray address) {
450 ALOGV("%s enter", __FUNCTION__);
451
452 if (!sHiddIf) {
453 ALOGE("%s: Failed to get the Bluetooth HIDD Interface", __func__);
454 return JNI_FALSE;
455 }
456
457 jboolean result = JNI_FALSE;
458
459 jbyte* addr = env->GetByteArrayElements(address, NULL);
460 if (!addr) {
461 ALOGE("Bluetooth device address null");
462 return JNI_FALSE;
463 }
464
465 bt_status_t ret = sHiddIf->connect((RawAddress*)addr);
466
467 ALOGV("%s: connect() returned %d", __FUNCTION__, ret);
468
469 if (ret == BT_STATUS_SUCCESS) {
470 result = JNI_TRUE;
471 }
472
473 ALOGV("%s done (%d)", __FUNCTION__, result);
474
475 return result;
476 }
477
disconnectNative(JNIEnv * env,jobject thiz)478 static jboolean disconnectNative(JNIEnv* env, jobject thiz) {
479 ALOGV("%s enter", __FUNCTION__);
480
481 if (!sHiddIf) {
482 ALOGE("%s: Failed to get the Bluetooth HIDD Interface", __func__);
483 return JNI_FALSE;
484 }
485
486 jboolean result = JNI_FALSE;
487
488 bt_status_t ret = sHiddIf->disconnect();
489
490 ALOGV("%s: disconnect() returned %d", __FUNCTION__, ret);
491
492 if (ret == BT_STATUS_SUCCESS) {
493 result = JNI_TRUE;
494 }
495
496 ALOGV("%s done (%d)", __FUNCTION__, result);
497
498 return result;
499 }
500
501 static JNINativeMethod sMethods[] = {
502 {"classInitNative", "()V", (void*)classInitNative},
503 {"initNative", "()V", (void*)initNative},
504 {"cleanupNative", "()V", (void*)cleanupNative},
505 {"registerAppNative",
506 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;B[B[I[I)Z",
507 (void*)registerAppNative},
508 {"unregisterAppNative", "()Z", (void*)unregisterAppNative},
509 {"sendReportNative", "(I[B)Z", (void*)sendReportNative},
510 {"replyReportNative", "(BB[B)Z", (void*)replyReportNative},
511 {"reportErrorNative", "(B)Z", (void*)reportErrorNative},
512 {"unplugNative", "()Z", (void*)unplugNative},
513 {"connectNative", "([B)Z", (void*)connectNative},
514 {"disconnectNative", "()Z", (void*)disconnectNative},
515 };
516
register_com_android_bluetooth_hid_device(JNIEnv * env)517 int register_com_android_bluetooth_hid_device(JNIEnv* env) {
518 return jniRegisterNativeMethods(
519 env, "com/android/bluetooth/hid/HidDeviceNativeInterface", sMethods,
520 NELEM(sMethods));
521 }
522 } // namespace android
523