• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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