• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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 "BluetoothHidServiceJni"
18 
19 #define LOG_NDEBUG 1
20 
21 #include "android_runtime/AndroidRuntime.h"
22 #include "com_android_bluetooth.h"
23 #include "hardware/bt_hh.h"
24 #include "utils/Log.h"
25 
26 #include <string.h>
27 
28 namespace android {
29 
30 static jmethodID method_onConnectStateChanged;
31 static jmethodID method_onGetProtocolMode;
32 static jmethodID method_onGetReport;
33 static jmethodID method_onHandshake;
34 static jmethodID method_onVirtualUnplug;
35 static jmethodID method_onGetIdleTime;
36 
37 static const bthh_interface_t* sBluetoothHidInterface = 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 
connection_state_callback(RawAddress * bd_addr,bthh_connection_state_t state)54 static void connection_state_callback(RawAddress* bd_addr,
55                                       bthh_connection_state_t state) {
56   CallbackEnv sCallbackEnv(__func__);
57   if (!sCallbackEnv.valid()) return;
58   if (!mCallbacksObj) {
59     ALOGE("%s: mCallbacksObj is null", __func__);
60     return;
61   }
62   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
63   if (!addr.get()) {
64     ALOGE("Fail to new jbyteArray bd addr for HID channel state");
65     return;
66   }
67 
68   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged,
69                                addr.get(), (jint)state);
70 }
71 
get_protocol_mode_callback(RawAddress * bd_addr,bthh_status_t hh_status,bthh_protocol_mode_t mode)72 static void get_protocol_mode_callback(RawAddress* bd_addr,
73                                        bthh_status_t hh_status,
74                                        bthh_protocol_mode_t mode) {
75   CallbackEnv sCallbackEnv(__func__);
76   if (!sCallbackEnv.valid()) return;
77   if (!mCallbacksObj) {
78     ALOGE("%s: mCallbacksObj is null", __func__);
79     return;
80   }
81   if (hh_status != BTHH_OK) {
82     ALOGE("BTHH Status is not OK!");
83     return;
84   }
85 
86   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
87   if (!addr.get()) {
88     ALOGE("Fail to new jbyteArray bd addr for get protocal mode callback");
89     return;
90   }
91 
92   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetProtocolMode,
93                                addr.get(), (jint)mode);
94 }
95 
get_report_callback(RawAddress * bd_addr,bthh_status_t hh_status,uint8_t * rpt_data,int rpt_size)96 static void get_report_callback(RawAddress* bd_addr, bthh_status_t hh_status,
97                                 uint8_t* rpt_data, int rpt_size) {
98   CallbackEnv sCallbackEnv(__func__);
99   if (!sCallbackEnv.valid()) return;
100   if (!mCallbacksObj) {
101     ALOGE("%s: mCallbacksObj is null", __func__);
102     return;
103   }
104   if (hh_status != BTHH_OK) {
105     ALOGE("BTHH Status is not OK!");
106     return;
107   }
108 
109   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
110   if (!addr.get()) {
111     ALOGE("Fail to new jbyteArray bd addr for get report callback");
112     return;
113   }
114   ScopedLocalRef<jbyteArray> data(sCallbackEnv.get(),
115                                   sCallbackEnv->NewByteArray(rpt_size));
116   if (!data.get()) {
117     ALOGE("Fail to new jbyteArray data for get report callback");
118     return;
119   }
120 
121   sCallbackEnv->SetByteArrayRegion(data.get(), 0, rpt_size, (jbyte*)rpt_data);
122   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetReport, addr.get(),
123                                data.get(), (jint)rpt_size);
124 }
125 
virtual_unplug_callback(RawAddress * bd_addr,bthh_status_t hh_status)126 static void virtual_unplug_callback(RawAddress* bd_addr,
127                                     bthh_status_t hh_status) {
128   ALOGV("call to virtual_unplug_callback");
129   CallbackEnv sCallbackEnv(__func__);
130   if (!sCallbackEnv.valid()) return;
131   if (!mCallbacksObj) {
132     ALOGE("%s: mCallbacksObj is null", __func__);
133     return;
134   }
135   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
136   if (!addr.get()) {
137     ALOGE("Fail to new jbyteArray bd addr for HID channel state");
138     return;
139   }
140   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVirtualUnplug,
141                                addr.get(), (jint)hh_status);
142 }
143 
handshake_callback(RawAddress * bd_addr,bthh_status_t hh_status)144 static void handshake_callback(RawAddress* bd_addr, bthh_status_t hh_status) {
145   CallbackEnv sCallbackEnv(__func__);
146   if (!sCallbackEnv.valid()) return;
147   if (!mCallbacksObj) {
148     ALOGE("%s: mCallbacksObj is null", __func__);
149     return;
150   }
151 
152   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
153   if (!addr.get()) {
154     ALOGE("Fail to new jbyteArray bd addr for handshake callback");
155     return;
156   }
157   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onHandshake, addr.get(),
158                                (jint)hh_status);
159 }
160 
get_idle_time_callback(RawAddress * bd_addr,bthh_status_t hh_status,int idle_time)161 static void get_idle_time_callback(RawAddress* bd_addr, bthh_status_t hh_status,
162                                    int idle_time) {
163   CallbackEnv sCallbackEnv(__func__);
164   if (!sCallbackEnv.valid()) return;
165 
166   ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(), marshall_bda(bd_addr));
167   if (!addr.get()) {
168     ALOGE("%s: Fail to new jbyteArray bd addr", __func__);
169     return;
170   }
171   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetIdleTime, addr.get(),
172                                (jint)idle_time);
173 }
174 
175 static bthh_callbacks_t sBluetoothHidCallbacks = {
176     sizeof(sBluetoothHidCallbacks),
177     connection_state_callback,
178     NULL,
179     get_protocol_mode_callback,
180     get_idle_time_callback,
181     get_report_callback,
182     virtual_unplug_callback,
183     handshake_callback};
184 
185 // Define native functions
186 
classInitNative(JNIEnv * env,jclass clazz)187 static void classInitNative(JNIEnv* env, jclass clazz) {
188   method_onConnectStateChanged =
189       env->GetMethodID(clazz, "onConnectStateChanged", "([BI)V");
190   method_onGetProtocolMode =
191       env->GetMethodID(clazz, "onGetProtocolMode", "([BI)V");
192   method_onGetReport = env->GetMethodID(clazz, "onGetReport", "([B[BI)V");
193   method_onHandshake = env->GetMethodID(clazz, "onHandshake", "([BI)V");
194   method_onVirtualUnplug = env->GetMethodID(clazz, "onVirtualUnplug", "([BI)V");
195   method_onGetIdleTime = env->GetMethodID(clazz, "onGetIdleTime", "([BI)V");
196 
197   ALOGI("%s: succeeds", __func__);
198 }
199 
initializeNative(JNIEnv * env,jobject object)200 static void initializeNative(JNIEnv* env, jobject object) {
201   const bt_interface_t* btInf = getBluetoothInterface();
202   if (btInf == NULL) {
203     ALOGE("Bluetooth module is not loaded");
204     return;
205   }
206 
207   if (sBluetoothHidInterface != NULL) {
208     ALOGW("Cleaning up Bluetooth HID Interface before initializing...");
209     sBluetoothHidInterface->cleanup();
210     sBluetoothHidInterface = NULL;
211   }
212 
213   if (mCallbacksObj != NULL) {
214     ALOGW("Cleaning up Bluetooth GID callback object");
215     env->DeleteGlobalRef(mCallbacksObj);
216     mCallbacksObj = NULL;
217   }
218 
219   sBluetoothHidInterface =
220       (bthh_interface_t*)btInf->get_profile_interface(BT_PROFILE_HIDHOST_ID);
221   if (sBluetoothHidInterface == NULL) {
222     ALOGE("Failed to get Bluetooth HID Interface");
223     return;
224   }
225 
226   bt_status_t status = sBluetoothHidInterface->init(&sBluetoothHidCallbacks);
227   if (status != BT_STATUS_SUCCESS) {
228     ALOGE("Failed to initialize Bluetooth HID, status: %d", status);
229     sBluetoothHidInterface = NULL;
230     return;
231   }
232 
233   mCallbacksObj = env->NewGlobalRef(object);
234 }
235 
cleanupNative(JNIEnv * env,jobject object)236 static void cleanupNative(JNIEnv* env, jobject object) {
237   const bt_interface_t* btInf = getBluetoothInterface();
238 
239   if (btInf == NULL) {
240     ALOGE("Bluetooth module is not loaded");
241     return;
242   }
243 
244   if (sBluetoothHidInterface != NULL) {
245     ALOGW("Cleaning up Bluetooth HID Interface...");
246     sBluetoothHidInterface->cleanup();
247     sBluetoothHidInterface = NULL;
248   }
249 
250   if (mCallbacksObj != NULL) {
251     ALOGW("Cleaning up Bluetooth GID callback object");
252     env->DeleteGlobalRef(mCallbacksObj);
253     mCallbacksObj = NULL;
254   }
255 }
256 
connectHidNative(JNIEnv * env,jobject object,jbyteArray address)257 static jboolean connectHidNative(JNIEnv* env, jobject object,
258                                  jbyteArray address) {
259   if (!sBluetoothHidInterface) return JNI_FALSE;
260 
261   jbyte* addr = env->GetByteArrayElements(address, NULL);
262   if (!addr) {
263     ALOGE("Bluetooth device address null");
264     return JNI_FALSE;
265   }
266 
267   jboolean ret = JNI_TRUE;
268   bt_status_t status = sBluetoothHidInterface->connect((RawAddress*)addr);
269   if (status != BT_STATUS_SUCCESS) {
270     ALOGE("Failed HID channel connection, status: %d", status);
271     ret = JNI_FALSE;
272   }
273   env->ReleaseByteArrayElements(address, addr, 0);
274 
275   return ret;
276 }
277 
disconnectHidNative(JNIEnv * env,jobject object,jbyteArray address)278 static jboolean disconnectHidNative(JNIEnv* env, jobject object,
279                                     jbyteArray address) {
280   jbyte* addr;
281   jboolean ret = JNI_TRUE;
282   if (!sBluetoothHidInterface) return JNI_FALSE;
283 
284   addr = env->GetByteArrayElements(address, NULL);
285   if (!addr) {
286     ALOGE("Bluetooth device address null");
287     return JNI_FALSE;
288   }
289 
290   bt_status_t status = sBluetoothHidInterface->disconnect((RawAddress*)addr);
291   if (status != BT_STATUS_SUCCESS) {
292     ALOGE("Failed disconnect hid channel, status: %d", status);
293     ret = JNI_FALSE;
294   }
295   env->ReleaseByteArrayElements(address, addr, 0);
296 
297   return ret;
298 }
299 
getProtocolModeNative(JNIEnv * env,jobject object,jbyteArray address)300 static jboolean getProtocolModeNative(JNIEnv* env, jobject object,
301                                       jbyteArray address) {
302   if (!sBluetoothHidInterface) return JNI_FALSE;
303 
304   jbyte* addr = env->GetByteArrayElements(address, NULL);
305   if (!addr) {
306     ALOGE("Bluetooth device address null");
307     return JNI_FALSE;
308   }
309 
310   jboolean ret = JNI_TRUE;
311   // TODO: protocolMode is unused by the backend: see b/28908173
312   bthh_protocol_mode_t protocolMode = BTHH_UNSUPPORTED_MODE;
313   bt_status_t status = sBluetoothHidInterface->get_protocol(
314       (RawAddress*)addr, (bthh_protocol_mode_t)protocolMode);
315   if (status != BT_STATUS_SUCCESS) {
316     ALOGE("Failed get protocol mode, status: %d", status);
317     ret = JNI_FALSE;
318   }
319   env->ReleaseByteArrayElements(address, addr, 0);
320 
321   return ret;
322 }
323 
virtualUnPlugNative(JNIEnv * env,jobject object,jbyteArray address)324 static jboolean virtualUnPlugNative(JNIEnv* env, jobject object,
325                                     jbyteArray address) {
326   if (!sBluetoothHidInterface) return JNI_FALSE;
327 
328   jbyte* addr = env->GetByteArrayElements(address, NULL);
329   if (!addr) {
330     ALOGE("Bluetooth device address null");
331     return JNI_FALSE;
332   }
333 
334   jboolean ret = JNI_TRUE;
335   bt_status_t status =
336       sBluetoothHidInterface->virtual_unplug((RawAddress*)addr);
337   if (status != BT_STATUS_SUCCESS) {
338     ALOGE("Failed virual unplug, status: %d", status);
339     ret = JNI_FALSE;
340   }
341   env->ReleaseByteArrayElements(address, addr, 0);
342   return ret;
343 }
344 
setProtocolModeNative(JNIEnv * env,jobject object,jbyteArray address,jint protocolMode)345 static jboolean setProtocolModeNative(JNIEnv* env, jobject object,
346                                       jbyteArray address, jint protocolMode) {
347   if (!sBluetoothHidInterface) return JNI_FALSE;
348 
349   ALOGD("%s: protocolMode = %d", __func__, protocolMode);
350 
351   jbyte* addr = env->GetByteArrayElements(address, NULL);
352   if (!addr) {
353     ALOGE("Bluetooth device address null");
354     return JNI_FALSE;
355   }
356 
357   bthh_protocol_mode_t mode;
358   switch (protocolMode) {
359     case 0:
360       mode = BTHH_REPORT_MODE;
361       break;
362     case 1:
363       mode = BTHH_BOOT_MODE;
364       break;
365     default:
366       ALOGE("Unknown HID protocol mode");
367       return JNI_FALSE;
368   }
369 
370   jboolean ret = JNI_TRUE;
371   bt_status_t status =
372       sBluetoothHidInterface->set_protocol((RawAddress*)addr, mode);
373   if (status != BT_STATUS_SUCCESS) {
374     ALOGE("Failed set protocol mode, status: %d", status);
375     ret = JNI_FALSE;
376   }
377   env->ReleaseByteArrayElements(address, addr, 0);
378 
379   return ret;
380 }
381 
getReportNative(JNIEnv * env,jobject object,jbyteArray address,jbyte reportType,jbyte reportId,jint bufferSize)382 static jboolean getReportNative(JNIEnv* env, jobject object, jbyteArray address,
383                                 jbyte reportType, jbyte reportId,
384                                 jint bufferSize) {
385   ALOGV("%s: reportType = %d, reportId = %d, bufferSize = %d", __func__,
386         reportType, reportId, bufferSize);
387   if (!sBluetoothHidInterface) return JNI_FALSE;
388 
389   jbyte* addr = env->GetByteArrayElements(address, NULL);
390   if (!addr) {
391     ALOGE("Bluetooth device address null");
392     return JNI_FALSE;
393   }
394 
395   jint rType = reportType;
396   jint rId = reportId;
397 
398   bt_status_t status = sBluetoothHidInterface->get_report(
399       (RawAddress*)addr, (bthh_report_type_t)rType, (uint8_t)rId, bufferSize);
400   jboolean ret = JNI_TRUE;
401   if (status != BT_STATUS_SUCCESS) {
402     ALOGE("Failed get report, status: %d", status);
403     ret = JNI_FALSE;
404   }
405   env->ReleaseByteArrayElements(address, addr, 0);
406 
407   return ret;
408 }
409 
setReportNative(JNIEnv * env,jobject object,jbyteArray address,jbyte reportType,jstring report)410 static jboolean setReportNative(JNIEnv* env, jobject object, jbyteArray address,
411                                 jbyte reportType, jstring report) {
412   ALOGV("%s: reportType = %d", __func__, reportType);
413   if (!sBluetoothHidInterface) return JNI_FALSE;
414 
415   jbyte* addr = env->GetByteArrayElements(address, NULL);
416   if (!addr) {
417     ALOGE("Bluetooth device address null");
418     return JNI_FALSE;
419   }
420   jint rType = reportType;
421   const char* c_report = env->GetStringUTFChars(report, NULL);
422 
423   jboolean ret = JNI_TRUE;
424   bt_status_t status = sBluetoothHidInterface->set_report(
425       (RawAddress*)addr, (bthh_report_type_t)rType, (char*)c_report);
426   if (status != BT_STATUS_SUCCESS) {
427     ALOGE("Failed set report, status: %d", status);
428     ret = JNI_FALSE;
429   }
430   env->ReleaseStringUTFChars(report, c_report);
431   env->ReleaseByteArrayElements(address, addr, 0);
432 
433   return ret;
434 }
435 
sendDataNative(JNIEnv * env,jobject object,jbyteArray address,jstring report)436 static jboolean sendDataNative(JNIEnv* env, jobject object, jbyteArray address,
437                                jstring report) {
438   ALOGV("%s", __func__);
439   jboolean ret = JNI_TRUE;
440   if (!sBluetoothHidInterface) return JNI_FALSE;
441 
442   jbyte* addr = env->GetByteArrayElements(address, NULL);
443   if (!addr) {
444     ALOGE("Bluetooth device address null");
445     return JNI_FALSE;
446   }
447 
448   const char* c_report = env->GetStringUTFChars(report, NULL);
449 
450   bt_status_t status =
451       sBluetoothHidInterface->send_data((RawAddress*)addr, (char*)c_report);
452   if (status != BT_STATUS_SUCCESS) {
453     ALOGE("Failed set data, status: %d", status);
454     ret = JNI_FALSE;
455   }
456   env->ReleaseStringUTFChars(report, c_report);
457   env->ReleaseByteArrayElements(address, addr, 0);
458 
459   return ret;
460 }
461 
getIdleTimeNative(JNIEnv * env,jobject object,jbyteArray address)462 static jboolean getIdleTimeNative(JNIEnv* env, jobject object,
463                                   jbyteArray address) {
464   if (!sBluetoothHidInterface) return JNI_FALSE;
465 
466   jbyte* addr = env->GetByteArrayElements(address, NULL);
467   if (!addr) {
468     ALOGE("%s: Bluetooth device address null", __func__);
469     return JNI_FALSE;
470   }
471 
472   bt_status_t status = sBluetoothHidInterface->get_idle_time((RawAddress*)addr);
473   if (status != BT_STATUS_SUCCESS) {
474     ALOGE("%s: Failed get idle time, status: %d", __func__, status);
475   }
476   env->ReleaseByteArrayElements(address, addr, 0);
477 
478   return status == BT_STATUS_SUCCESS ? JNI_TRUE : JNI_FALSE;
479 }
480 
setIdleTimeNative(JNIEnv * env,jobject object,jbyteArray address,jbyte idle_time)481 static jboolean setIdleTimeNative(JNIEnv* env, jobject object,
482                                   jbyteArray address, jbyte idle_time) {
483   if (!sBluetoothHidInterface) return JNI_FALSE;
484 
485   jbyte* addr = env->GetByteArrayElements(address, NULL);
486   if (!addr) {
487     ALOGE("%s: Bluetooth device address null", __func__);
488     return JNI_FALSE;
489   }
490 
491   bt_status_t status =
492       sBluetoothHidInterface->set_idle_time((RawAddress*)addr, idle_time);
493   if (status != BT_STATUS_SUCCESS) {
494     ALOGE("%s: Failed set idle time, status: %d", __func__, status);
495   }
496   env->ReleaseByteArrayElements(address, addr, 0);
497 
498   return status == BT_STATUS_SUCCESS ? JNI_TRUE : JNI_FALSE;
499 }
500 
501 static JNINativeMethod sMethods[] = {
502     {"classInitNative", "()V", (void*)classInitNative},
503     {"initializeNative", "()V", (void*)initializeNative},
504     {"cleanupNative", "()V", (void*)cleanupNative},
505     {"connectHidNative", "([B)Z", (void*)connectHidNative},
506     {"disconnectHidNative", "([B)Z", (void*)disconnectHidNative},
507     {"getProtocolModeNative", "([B)Z", (void*)getProtocolModeNative},
508     {"virtualUnPlugNative", "([B)Z", (void*)virtualUnPlugNative},
509     {"setProtocolModeNative", "([BB)Z", (void*)setProtocolModeNative},
510     {"getReportNative", "([BBBI)Z", (void*)getReportNative},
511     {"setReportNative", "([BBLjava/lang/String;)Z", (void*)setReportNative},
512     {"sendDataNative", "([BLjava/lang/String;)Z", (void*)sendDataNative},
513     {"getIdleTimeNative", "([B)Z", (void*)getIdleTimeNative},
514     {"setIdleTimeNative", "([BB)Z", (void*)setIdleTimeNative},
515 };
516 
register_com_android_bluetooth_hid(JNIEnv * env)517 int register_com_android_bluetooth_hid(JNIEnv* env) {
518   return jniRegisterNativeMethods(env, "com/android/bluetooth/hid/HidService",
519                                   sMethods, NELEM(sMethods));
520 }
521 }
522