• 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 #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