Home | History | Annotate | Download | only in jni
      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 "BluetoothHidDevServiceJni"
     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_onIntrData;
     36 static jmethodID method_onVirtualCableUnplug;
     37 
     38 static const bthd_interface_t* sHiddIf = NULL;
     39 static jobject mCallbacksObj = NULL;
     40 
     41 static jbyteArray marshall_bda(bt_bdaddr_t* bd_addr) {
     42   CallbackEnv sCallbackEnv(__func__);
     43   if (!sCallbackEnv.valid()) return NULL;
     44 
     45   jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
     46   if (!addr) {
     47     ALOGE("Fail to new jbyteArray bd addr");
     48     return NULL;
     49   }
     50   sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t),
     51                                    (jbyte*)bd_addr);
     52   return addr;
     53 }
     54 
     55 static void application_state_callback(bt_bdaddr_t* 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 
     79 static void connection_state_callback(bt_bdaddr_t* 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 
     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 
    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 
    117 static void set_protocol_callback(uint8_t protocol) {
    118   CallbackEnv sCallbackEnv(__func__);
    119 
    120   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSetProtocol, protocol);
    121 }
    122 
    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_onIntrData,
    136                                (jbyte)report_id, data.get());
    137 }
    138 
    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 
    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_onIntrData = env->GetMethodID(clazz, "onIntrData", "(B[B)V");
    167   method_onVirtualCableUnplug =
    168       env->GetMethodID(clazz, "onVirtualCableUnplug", "()V");
    169 }
    170 
    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 
    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 
    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 
    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   jboolean result = JNI_FALSE;
    265   bthd_app_param_t app_param;
    266   bthd_qos_param_t in_qos;
    267   bthd_qos_param_t out_qos;
    268   jsize size;
    269   uint8_t* data;
    270 
    271   size = env->GetArrayLength(descriptors);
    272   data = (uint8_t*)malloc(size);
    273 
    274   if (data != NULL) {
    275     env->GetByteArrayRegion(descriptors, 0, size, (jbyte*)data);
    276 
    277     app_param.name = env->GetStringUTFChars(name, NULL);
    278     app_param.description = env->GetStringUTFChars(description, NULL);
    279     app_param.provider = env->GetStringUTFChars(provider, NULL);
    280     app_param.subclass = subclass;
    281     app_param.desc_list = data;
    282     app_param.desc_list_len = size;
    283 
    284     fill_qos(env, p_in_qos, &in_qos);
    285     fill_qos(env, p_out_qos, &out_qos);
    286 
    287     bt_status_t ret = sHiddIf->register_app(&app_param, &in_qos, &out_qos);
    288 
    289     ALOGV("%s: register_app() returned %d", __FUNCTION__, ret);
    290 
    291     if (ret == BT_STATUS_SUCCESS) {
    292       result = JNI_TRUE;
    293     }
    294 
    295     env->ReleaseStringUTFChars(name, app_param.name);
    296     env->ReleaseStringUTFChars(description, app_param.description);
    297     env->ReleaseStringUTFChars(provider, app_param.provider);
    298 
    299     free(data);
    300   }
    301 
    302   ALOGV("%s done (%d)", __FUNCTION__, result);
    303 
    304   return result;
    305 }
    306 
    307 static jboolean unregisterAppNative(JNIEnv* env, jobject thiz) {
    308   ALOGV("%s enter", __FUNCTION__);
    309 
    310   jboolean result = JNI_FALSE;
    311 
    312   bt_status_t ret = sHiddIf->unregister_app();
    313 
    314   ALOGV("%s: unregister_app() returned %d", __FUNCTION__, ret);
    315 
    316   if (ret == BT_STATUS_SUCCESS) {
    317     result = JNI_TRUE;
    318   }
    319 
    320   ALOGV("%s done (%d)", __FUNCTION__, result);
    321 
    322   return result;
    323 }
    324 
    325 static jboolean sendReportNative(JNIEnv* env, jobject thiz, jint id,
    326                                  jbyteArray data) {
    327   jboolean result = JNI_FALSE;
    328   jsize size;
    329   uint8_t* buf;
    330 
    331   size = env->GetArrayLength(data);
    332   buf = (uint8_t*)malloc(size);
    333 
    334   if (buf != NULL) {
    335     env->GetByteArrayRegion(data, 0, size, (jbyte*)buf);
    336 
    337     bt_status_t ret =
    338         sHiddIf->send_report(BTHD_REPORT_TYPE_INTRDATA, id, size, buf);
    339 
    340     if (ret == BT_STATUS_SUCCESS) {
    341       result = JNI_TRUE;
    342     }
    343 
    344     free(buf);
    345   }
    346 
    347   return result;
    348 }
    349 
    350 static jboolean replyReportNative(JNIEnv* env, jobject thiz, jbyte type,
    351                                   jbyte id, jbyteArray data) {
    352   ALOGV("%s enter", __FUNCTION__);
    353 
    354   jboolean result = JNI_FALSE;
    355   jsize size;
    356   uint8_t* buf;
    357 
    358   size = env->GetArrayLength(data);
    359   buf = (uint8_t*)malloc(size);
    360 
    361   if (buf != NULL) {
    362     int report_type = (type & 0x03);
    363     env->GetByteArrayRegion(data, 0, size, (jbyte*)buf);
    364 
    365     bt_status_t ret =
    366         sHiddIf->send_report((bthd_report_type_t)report_type, id, size, buf);
    367 
    368     ALOGV("%s: send_report() returned %d", __FUNCTION__, ret);
    369 
    370     if (ret == BT_STATUS_SUCCESS) {
    371       result = JNI_TRUE;
    372     }
    373 
    374     free(buf);
    375   }
    376 
    377   ALOGV("%s done (%d)", __FUNCTION__, result);
    378 
    379   return result;
    380 }
    381 
    382 static jboolean reportErrorNative(JNIEnv* env, jobject thiz, jbyte error) {
    383   ALOGV("%s enter", __FUNCTION__);
    384 
    385   jboolean result = JNI_FALSE;
    386 
    387   bt_status_t ret = sHiddIf->report_error(error);
    388 
    389   ALOGV("%s: report_error() returned %d", __FUNCTION__, ret);
    390 
    391   if (ret == BT_STATUS_SUCCESS) {
    392     result = JNI_TRUE;
    393   }
    394 
    395   ALOGV("%s done (%d)", __FUNCTION__, result);
    396 
    397   return result;
    398 }
    399 
    400 static jboolean unplugNative(JNIEnv* env, jobject thiz) {
    401   ALOGV("%s enter", __FUNCTION__);
    402 
    403   jboolean result = JNI_FALSE;
    404 
    405   bt_status_t ret = sHiddIf->virtual_cable_unplug();
    406 
    407   ALOGV("%s: virtual_cable_unplug() returned %d", __FUNCTION__, ret);
    408 
    409   if (ret == BT_STATUS_SUCCESS) {
    410     result = JNI_TRUE;
    411   }
    412 
    413   ALOGV("%s done (%d)", __FUNCTION__, result);
    414 
    415   return result;
    416 }
    417 
    418 static jboolean connectNative(JNIEnv* env, jobject thiz, jbyteArray address) {
    419   ALOGV("%s enter", __FUNCTION__);
    420 
    421   jboolean result = JNI_FALSE;
    422 
    423   jbyte* addr = env->GetByteArrayElements(address, NULL);
    424   if (!addr) {
    425     ALOGE("Bluetooth device address null");
    426     return JNI_FALSE;
    427   }
    428 
    429   bt_status_t ret = sHiddIf->connect((bt_bdaddr_t*)addr);
    430 
    431   ALOGV("%s: connect() returned %d", __FUNCTION__, ret);
    432 
    433   if (ret == BT_STATUS_SUCCESS) {
    434     result = JNI_TRUE;
    435   }
    436 
    437   ALOGV("%s done (%d)", __FUNCTION__, result);
    438 
    439   return result;
    440 }
    441 
    442 static jboolean disconnectNative(JNIEnv* env, jobject thiz) {
    443   ALOGV("%s enter", __FUNCTION__);
    444 
    445   jboolean result = JNI_FALSE;
    446 
    447   bt_status_t ret = sHiddIf->disconnect();
    448 
    449   ALOGV("%s: disconnect() returned %d", __FUNCTION__, ret);
    450 
    451   if (ret == BT_STATUS_SUCCESS) {
    452     result = JNI_TRUE;
    453   }
    454 
    455   ALOGV("%s done (%d)", __FUNCTION__, result);
    456 
    457   return result;
    458 }
    459 
    460 static JNINativeMethod sMethods[] = {
    461     {"classInitNative", "()V", (void*)classInitNative},
    462     {"initNative", "()V", (void*)initNative},
    463     {"cleanupNative", "()V", (void*)cleanupNative},
    464     {"registerAppNative",
    465      "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;B[B[I[I)Z",
    466      (void*)registerAppNative},
    467     {"unregisterAppNative", "()Z", (void*)unregisterAppNative},
    468     {"sendReportNative", "(I[B)Z", (void*)sendReportNative},
    469     {"replyReportNative", "(BB[B)Z", (void*)replyReportNative},
    470     {"reportErrorNative", "(B)Z", (void*)reportErrorNative},
    471     {"unplugNative", "()Z", (void*)unplugNative},
    472     {"connectNative", "([B)Z", (void*)connectNative},
    473     {"disconnectNative", "()Z", (void*)disconnectNative},
    474 };
    475 
    476 int register_com_android_bluetooth_hidd(JNIEnv* env) {
    477   return jniRegisterNativeMethods(env,
    478                                   "com/android/bluetooth/hid/HidDevService",
    479                                   sMethods, NELEM(sMethods));
    480 }
    481 }
    482