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