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