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