/* * Copyright (c) 2013, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define LOG_TAG "QBluetoothAdapterServiceJni" #define BD_ADDR_LEN 6 #include "com_android_bluetooth.h" #include "utils/Log.h" #include "utils/misc.h" #include "cutils/properties.h" #include "android_runtime/AndroidRuntime.h" #include #include #include #include namespace android { static jmethodID method_advEnableCallback; static jmethodID method_onLeExtendedScanResultCallback; static jmethodID method_onLeLppWriteRssiThreshold; static jmethodID method_onLeLppReadRssiThreshold; static jmethodID method_onLeLppEnableRssiMonitor; static jmethodID method_onLeLppRssiThresholdEvent; static const bt_interface_t *qBluetoothInterface = NULL; static JNIEnv *qcallbackEnv = NULL; static jobject qJniCallbacksObj=NULL; static jfieldID qJniCallbacksField; static void set_uuid(uint8_t* uuid, jlong uuid_msb, jlong uuid_lsb) { for (int i = 0; i != 8; ++i) { uuid[i] = (uuid_lsb >> (8 * i)) & 0xFF; uuid[i + 8] = (uuid_msb >> (8 * i)) & 0xFF; } } static void bd_addr_str_to_addr(const char* str, uint8_t *bd_addr) { int i; char c; c = *str++; for (i = 0; i < BD_ADDR_LEN; i++) { if (c >= '0' && c <= '9') bd_addr[i] = c - '0'; else if (c >= 'a' && c <= 'z') bd_addr[i] = c - 'a' + 10; else // (c >= 'A' && c <= 'Z') bd_addr[i] = c - 'A' + 10; c = *str++; if (c != ':') { bd_addr[i] <<= 4; if (c >= '0' && c <= '9') bd_addr[i] |= c - '0'; else if (c >= 'a' && c <= 'z') bd_addr[i] |= c - 'a' + 10; else // (c >= 'A' && c <= 'Z') bd_addr[i] |= c - 'A' + 10; c = *str++; } c = *str++; } } static void jstr2bdaddr(JNIEnv* env, bt_bdaddr_t *bda, jstring address) { const char* c_bda = env->GetStringUTFChars(address, NULL); if (c_bda != NULL && bda != NULL && strlen(c_bda) == 17) { bd_addr_str_to_addr(c_bda, bda->address); env->ReleaseStringUTFChars(address, c_bda); } } static bool checkCallbackThread() { qcallbackEnv = getCallbackEnv(); JNIEnv* env = AndroidRuntime::getJNIEnv(); if(env==NULL) ALOGE("checkCallbackThread env is NULL"); if(qcallbackEnv==NULL) ALOGE("checkCallbackThread qcallbackEnv is NULL"); if(env!=qcallbackEnv) ALOGE("env and qcallbackEnv dont match"); if (qcallbackEnv != env || qcallbackEnv == NULL) return false; return true; } static void le_adv_enable_callbacks(uint8_t enable, uint8_t advType) { jbyteArray addr; if (!checkCallbackThread()) { ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); return; } ALOGV("%s: adv enable:%d ", __FUNCTION__, enable); qcallbackEnv->CallVoidMethod(qJniCallbacksObj, method_advEnableCallback, (jint)enable, (jint)advType); checkAndClearExceptionFromCallback(qcallbackEnv, __FUNCTION__); } static void le_extended_scan_result_callbacks(bt_bdaddr_t* bda, int rssi, uint8_t* adv_data) { char c_address[32]; if (!checkCallbackThread()) { ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); } snprintf(c_address, sizeof(c_address),"%02X:%02X:%02X:%02X:%02X:%02X", bda->address[0], bda->address[1], bda->address[2], bda->address[3], bda->address[4], bda->address[5]); jstring address = qcallbackEnv->NewStringUTF(c_address); jbyteArray jb = qcallbackEnv->NewByteArray(62); qcallbackEnv->SetByteArrayRegion(jb, 0, 62, (jbyte *) adv_data); qcallbackEnv->CallVoidMethod(qJniCallbacksObj, method_onLeExtendedScanResultCallback, address, rssi, jb); qcallbackEnv->DeleteLocalRef(address); qcallbackEnv->DeleteLocalRef(jb); checkAndClearExceptionFromCallback(qcallbackEnv, __FUNCTION__); } void le_lpp_write_rssi_thresh_callbacks(bt_bdaddr_t *bda, int status) { char c_address[32] = {0}; if (!checkCallbackThread()) { ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); return; } snprintf(c_address, sizeof(c_address),"%02X:%02X:%02X:%02X:%02X:%02X", bda->address[0], bda->address[1], bda->address[2], bda->address[3], bda->address[4], bda->address[5]); jstring address = qcallbackEnv->NewStringUTF(c_address); qcallbackEnv->CallVoidMethod(qJniCallbacksObj, method_onLeLppWriteRssiThreshold, address, status); qcallbackEnv->DeleteLocalRef(address); checkAndClearExceptionFromCallback(qcallbackEnv, __FUNCTION__); } void le_lpp_read_rssi_thresh_callbacks(bt_bdaddr_t *bda, int low, int upper, int alert, int status) { char c_address[32] = {0}; if (!checkCallbackThread()) { ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); return; } snprintf(c_address, sizeof(c_address),"%02X:%02X:%02X:%02X:%02X:%02X", bda->address[0], bda->address[1], bda->address[2], bda->address[3], bda->address[4], bda->address[5]); jstring address = qcallbackEnv->NewStringUTF(c_address); qcallbackEnv->CallVoidMethod(qJniCallbacksObj, method_onLeLppReadRssiThreshold, address, low, upper, alert, status); qcallbackEnv->DeleteLocalRef(address); checkAndClearExceptionFromCallback(qcallbackEnv, __FUNCTION__); } void le_lpp_enable_rssi_monitor_callbacks(bt_bdaddr_t *bda, int enable, int status) { char c_address[32] = {0}; if (!checkCallbackThread()) { ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); return; } snprintf(c_address, sizeof(c_address),"%02X:%02X:%02X:%02X:%02X:%02X", bda->address[0], bda->address[1], bda->address[2], bda->address[3], bda->address[4], bda->address[5]); jstring address = qcallbackEnv->NewStringUTF(c_address); qcallbackEnv->CallVoidMethod(qJniCallbacksObj, method_onLeLppEnableRssiMonitor, address, enable, status); qcallbackEnv->DeleteLocalRef(address); checkAndClearExceptionFromCallback(qcallbackEnv, __FUNCTION__); } void le_lpp_rssi_threshold_evt_callbacks(bt_bdaddr_t *bda, int evt_type, int rssi) { char c_address[32] = {0}; if (!checkCallbackThread()) { ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); return; } snprintf(c_address, sizeof(c_address),"%02X:%02X:%02X:%02X:%02X:%02X", bda->address[0], bda->address[1], bda->address[2], bda->address[3], bda->address[4], bda->address[5]); jstring address = qcallbackEnv->NewStringUTF(c_address); qcallbackEnv->CallVoidMethod(qJniCallbacksObj, method_onLeLppRssiThresholdEvent, address, evt_type, rssi); qcallbackEnv->DeleteLocalRef(address); checkAndClearExceptionFromCallback(qcallbackEnv, __FUNCTION__); } bt_callbacks_t sQBluetoothCallbacks = { sizeof(sQBluetoothCallbacks), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, le_adv_enable_callbacks, le_extended_scan_result_callbacks, le_lpp_write_rssi_thresh_callbacks, le_lpp_read_rssi_thresh_callbacks, le_lpp_enable_rssi_monitor_callbacks, le_lpp_rssi_threshold_evt_callbacks, }; static void classInitNative(JNIEnv* env, jclass clazz) { int err; hw_module_t* module; ALOGV("%s:",__FUNCTION__); if((qBluetoothInterface=getBluetoothInterface())==NULL){ ALOGE("Bluetooth module is not loaded"); return; } jclass jniCallbackClass = env->FindClass("com/android/bluetooth/btservice/QJniCallbacks"); qJniCallbacksField = env->GetFieldID(clazz, "mJniCallbacks", "Lcom/android/bluetooth/btservice/QJniCallbacks;"); method_advEnableCallback = env->GetMethodID(jniCallbackClass, "advEnableCallback", "(II)V"); method_onLeExtendedScanResultCallback = env->GetMethodID(jniCallbackClass, "onLeExtendedScanResult", "(Ljava/lang/String;I[B)V"); method_onLeLppWriteRssiThreshold = env->GetMethodID(jniCallbackClass, "onLeLppWriteRssiThreshold", "(Ljava/lang/String;I)V"); method_onLeLppReadRssiThreshold = env->GetMethodID(jniCallbackClass, "onLeLppReadRssiThreshold", "(Ljava/lang/String;IIII)V"); method_onLeLppEnableRssiMonitor = env->GetMethodID(jniCallbackClass, "onLeLppEnableRssiMonitor", "(Ljava/lang/String;II)V"); method_onLeLppRssiThresholdEvent = env->GetMethodID(jniCallbackClass, "onLeLppRssiThresholdEvent", "(Ljava/lang/String;II)V"); } static bool initNative(JNIEnv* env, jobject obj) { ALOGV("%s:",__FUNCTION__); if (qBluetoothInterface) { qJniCallbacksObj = env->NewGlobalRef(env->GetObjectField(obj, qJniCallbacksField)); int ret = qBluetoothInterface->initq(&sQBluetoothCallbacks); if (ret != BT_STATUS_SUCCESS) { ALOGE("Error while setting the callbacks \n"); qBluetoothInterface = NULL; return JNI_FALSE; } return JNI_TRUE; } return JNI_FALSE; } static bool cleanupNative(JNIEnv *env, jobject obj) { ALOGV("%s:",__FUNCTION__); jboolean result = JNI_FALSE; if (!qBluetoothInterface) return result; if(qJniCallbacksObj!=NULL){ env->DeleteGlobalRef(qJniCallbacksObj); qJniCallbacksObj=NULL; } return JNI_TRUE; } static jboolean setLEAdvModeNative(JNIEnv *env, jobject obj, jint type, jbyteArray value) { ALOGV("%s:",__FUNCTION__); jbyte *val; jboolean result = JNI_FALSE; if (!qBluetoothInterface) return result; val = env->GetByteArrayElements(value, NULL); bt_property_t prop; prop.type = (bt_property_type_t) type; prop.len = env->GetArrayLength(value); prop.val = val; int ret = qBluetoothInterface->set_adapter_property(&prop); env->ReleaseByteArrayElements(value, val, 0); result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; return result; } static jboolean setLEadvMaskNative(JNIEnv *env, jobject obj,jint mask){ ALOGV("%s:",__FUNCTION__); jboolean result = JNI_FALSE; if (!qBluetoothInterface) return result; int ret = qBluetoothInterface->le_set_adv_data_mask(mask); result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; return result; } static jboolean setLEscanRespMaskNative(JNIEnv *env, jobject obj,jint mask){ ALOGV("%s:",__FUNCTION__); jboolean result = JNI_FALSE; if (!qBluetoothInterface) return result; int ret = qBluetoothInterface->le_set_scan_resp_mask(mask); result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; return result; } static jboolean setLEManuDataNative(JNIEnv *env, jobject obj,jbyteArray buff){ ALOGV("%s:",__FUNCTION__); jbyte *manu_data=NULL; uint8_t size=0; jboolean result = JNI_FALSE; manu_data=env->GetByteArrayElements(buff, NULL); size=env->GetArrayLength(buff); if (!qBluetoothInterface) return result; int ret = qBluetoothInterface->le_set_manu_data((uint8_t *)manu_data, size); result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; return result; } static jboolean setLEServiceDataNative(JNIEnv *env, jobject obj,jbyteArray buff){ ALOGV("%s:",__FUNCTION__); jbyte *service_data=NULL; uint8_t size=0; jboolean result = JNI_FALSE; service_data=env->GetByteArrayElements(buff, NULL); size=env->GetArrayLength(buff); if (!qBluetoothInterface) return result; int ret = qBluetoothInterface->le_set_service_data((uint8_t *)service_data, size); result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; return result; } static jboolean setLEAdvParamsNative(JNIEnv *env, jobject obj, jint min_int, jint max_int, jbyteArray address, jint ad_type){ ALOGV("%s:",__FUNCTION__); jbyte *addr=NULL; jboolean result = JNI_FALSE; addr = env->GetByteArrayElements(address, NULL); if (!qBluetoothInterface) return result; int ret = qBluetoothInterface->le_set_adv_params(min_int, max_int, (bt_bdaddr_t *)addr,ad_type); result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; return result; } static void btLeExtendedScanNative(JNIEnv *env, jobject object, jobjectArray uuids, jboolean start) { int i = 0, entries = 0; uint8_t scan_policy = 0x80; /* 0x80 represent only AD whitelist applied*/ bt_le_service_t *service_list = 0; entries = env->GetArrayLength(uuids); if(qBluetoothInterface && (service_list = (bt_le_service_t*)malloc(entries * sizeof(bt_le_service_t)))) { jclass clazzuuid; jobject uuid; jmethodID getlsb, getmsb, gettype; jlong lsbbits, msbbits; if ((clazzuuid = env->FindClass("android/bluetooth/BluetoothLEServiceUuid")) != NULL && (getlsb = env->GetMethodID(clazzuuid, "getLeastSignificantBits", "()J")) != NULL && (getmsb = env->GetMethodID(clazzuuid, "getMostSignificantBits", "()J")) != NULL && (gettype = env->GetMethodID(clazzuuid, "getType", "()B")) != NULL) { for(i = 0; i < entries; i++) { uuid = env->GetObjectArrayElement(uuids, i); service_list[i].uuidtype = env->CallByteMethod(uuid, gettype); lsbbits = env->CallLongMethod(uuid, getlsb); msbbits = env->CallLongMethod(uuid, getmsb); set_uuid(&service_list[i].uuidval.uu[0], msbbits, lsbbits); } qBluetoothInterface->le_extended_scan(service_list, entries, scan_policy, start?1:0); } } free(service_list); } static void btLeLppWriteRssiThresholdNative(JNIEnv *env, jobject object, jstring address, jbyte min, jbyte max) { bt_bdaddr_t bda; if (!qBluetoothInterface) return; jstr2bdaddr(env, &bda, address); qBluetoothInterface->le_lpp_write_rssi_threshold(&bda, min, max); } static void btLeLppEnableRssiMonitorNative(JNIEnv* env, jobject object, jstring address, jboolean enable) { bt_bdaddr_t bda; if (!qBluetoothInterface) return; jstr2bdaddr(env, &bda, address); qBluetoothInterface->le_lpp_enable_rssi_monitor(&bda, enable); } static void btLeLppReadRssiThresholdNative(JNIEnv* env, jobject object, jstring address) { bt_bdaddr_t bda; if (!qBluetoothInterface) return; jstr2bdaddr(env, &bda, address); qBluetoothInterface->le_lpp_read_rssi_threshold(&bda); } static JNINativeMethod qMethods[] = { /* name, signature, funcPtr */ {"classInitNative", "()V", (void *) classInitNative}, {"initNative", "()Z", (void *) initNative}, {"cleanupNative", "()V", (void*) cleanupNative}, {"setLEAdvParamsNative","(II[BI)Z", (void*) setLEAdvParamsNative}, {"setLEadvMaskNative","(I)Z",(void*) setLEadvMaskNative}, {"setLEscanRespMaskNative","(I)Z",(void*) setLEscanRespMaskNative}, {"setLEManuDataNative","([B)Z",(void*) setLEManuDataNative}, {"setLEServiceDataNative","([B)Z",(void*) setLEServiceDataNative}, {"setLEAdvModeNative", "(I[B)Z", (void*) setLEAdvModeNative}, {"btLeExtendedScanNative", "([Landroid/bluetooth/BluetoothLEServiceUuid;Z)V", (void*) btLeExtendedScanNative}, {"btLeLppWriteRssiThresholdNative", "(Ljava/lang/String;BB)V", (void*)btLeLppWriteRssiThresholdNative}, {"btLeLppEnableRssiMonitorNative", "(Ljava/lang/String;Z)V", (void*)btLeLppEnableRssiMonitorNative}, {"btLeLppReadRssiThresholdNative", "(Ljava/lang/String;)V", (void*)btLeLppReadRssiThresholdNative}, }; int register_com_android_bluetooth_btservice_QAdapterService(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/bluetooth/btservice/QAdapterService", qMethods, NELEM(qMethods)); } }