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