summaryrefslogtreecommitdiffstats
path: root/jni
diff options
context:
space:
mode:
authorCasper Bonde <c.bonde@samsung.com>2015-04-09 09:20:50 +0200
committerCasper Bonde <c.bonde@samsung.com>2015-04-09 09:20:50 +0200
commitbbb4110b455b3aa29106d5b4f0a37e1be8e09475 (patch)
treee3f845fa32e2bb48f5ae5b076042cf785dcb4d8b /jni
parent2e85ea37c1ba495d3f0fd702f0a3920f3faf2848 (diff)
downloadandroid_packages_apps_Bluetooth-bbb4110b455b3aa29106d5b4f0a37e1be8e09475.tar.gz
android_packages_apps_Bluetooth-bbb4110b455b3aa29106d5b4f0a37e1be8e09475.tar.bz2
android_packages_apps_Bluetooth-bbb4110b455b3aa29106d5b4f0a37e1be8e09475.zip
Obex over L2CAP + SDP search API
Each profile had its own implementation of ObexTransport. These implementations were implemented very similar, and could easily be merged into a common implementation. Additionally it will make it easier to adopt the transport to support L2CAP. The SDP functionality is implemented in a way that is scalable, hence adding new record types is easy. Intents are currently used to distribute the SDP search results, as we have observed that the new client side profiles have been located outside the Bluetooth package. We strongly recommend to keep all bluetooth profiles within the Bluetooth package, to acoid the need for exposing all bluetooth interfaces through the Android framework. For instance this new SDP create API is internal to Bluetooth, hence cannot be used by the external profiles - hence they cannot use OBEX over L2CAP. The SDP search currently supports: - MAP both sides - OPP server (only the server needs an SDP record) - PBAP server (only the server needs SDP record) The SDP create record currently supports: - MAP both sides - OPP server - PBAP server The new l2cap sockets introduces a new wrapper class for a rfcomm and an l2cap socket. The wrapper design: - Creates two accept threads running while bluetooth is turned on. - When a connection is accepted the owner is asked wether or not to accept the connection if rejected, the connection will be rejected at obex level, else it will be accepted and the state is changed to busy. - Any further connections will be rejected at Obex level, until the state is changed back to idle. Notes tor executing the test cases: Test OBEX using local pipes(no BT) or two bluetooth enabled devices. Test SDP using two Bluetooth enabled devices Start server testcase first on one device, then start the matching client test on the other device. You cannot run all tests in one go, as they need to run on multiple devices. Edit the test sequesce to add/remove/modify the sequence of OBEX operations to perform. Use the new SDP record create interface. Change-Id: I3941793f9843abf4afa5ffbee40d1d01c118b29b Signed-off-by: Casper Bonde <c.bonde@samsung.com>
Diffstat (limited to 'jni')
-rw-r--r--jni/Android.mk3
-rw-r--r--jni/com_android_bluetooth.h2
-rw-r--r--jni/com_android_bluetooth_avrcp.cpp3
-rw-r--r--jni/com_android_bluetooth_btservice_AdapterService.cpp152
-rw-r--r--jni/com_android_bluetooth_sdp.cpp513
5 files changed, 544 insertions, 129 deletions
diff --git a/jni/Android.mk b/jni/Android.mk
index e1c63b297..fc4d8718d 100644
--- a/jni/Android.mk
+++ b/jni/Android.mk
@@ -13,7 +13,8 @@ LOCAL_SRC_FILES:= \
com_android_bluetooth_hid.cpp \
com_android_bluetooth_hdp.cpp \
com_android_bluetooth_pan.cpp \
- com_android_bluetooth_gatt.cpp
+ com_android_bluetooth_gatt.cpp \
+ com_android_bluetooth_sdp.cpp
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
diff --git a/jni/com_android_bluetooth.h b/jni/com_android_bluetooth.h
index 74dcddb27..4f55c06c3 100644
--- a/jni/com_android_bluetooth.h
+++ b/jni/com_android_bluetooth.h
@@ -52,6 +52,8 @@ int register_com_android_bluetooth_pan(JNIEnv* env);
int register_com_android_bluetooth_gatt (JNIEnv* env);
+int register_com_android_bluetooth_sdp (JNIEnv* env);
+
}
#endif /* COM_ANDROID_BLUETOOTH_H */
diff --git a/jni/com_android_bluetooth_avrcp.cpp b/jni/com_android_bluetooth_avrcp.cpp
index fb6f2fdff..e9a7bc90d 100644
--- a/jni/com_android_bluetooth_avrcp.cpp
+++ b/jni/com_android_bluetooth_avrcp.cpp
@@ -67,7 +67,8 @@ static void btavrcp_remote_features_callback(bt_bdaddr_t* bd_addr, btrc_remote_f
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getRcFeatures, addr, (jint)features);
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
- sCallbackEnv->DeleteLocalRef(addr);
+ /* TODO: I think we leak the addr object, we should add a
+ * sCallbackEnv->DeleteLocalRef(addr) */
}
static void btavrcp_get_play_status_callback() {
diff --git a/jni/com_android_bluetooth_btservice_AdapterService.cpp b/jni/com_android_bluetooth_btservice_AdapterService.cpp
index f780364ac..02c293e05 100644
--- a/jni/com_android_bluetooth_btservice_AdapterService.cpp
+++ b/jni/com_android_bluetooth_btservice_AdapterService.cpp
@@ -17,16 +17,14 @@
#define LOG_TAG "BluetoothServiceJni"
#include "com_android_bluetooth.h"
#include "hardware/bt_sock.h"
-#include "hardware/bt_mce.h"
#include "utils/Log.h"
#include "utils/misc.h"
#include "cutils/properties.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
-
#include <string.h>
#include <pthread.h>
-
+#include <binder/Parcel.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -45,12 +43,10 @@ static jmethodID method_discoveryStateChangeCallback;
static jmethodID method_setWakeAlarm;
static jmethodID method_acquireWakeLock;
static jmethodID method_releaseWakeLock;
-static jmethodID method_deviceMasInstancesFoundCallback;
static jmethodID method_energyInfo;
static const bt_interface_t *sBluetoothInterface = NULL;
static const btsock_interface_t *sBluetoothSocketInterface = NULL;
-static const btmce_interface_t *sBluetoothMceInterface = NULL;
static JNIEnv *callbackEnv = NULL;
static jobject sJniAdapterServiceObj;
@@ -528,12 +524,10 @@ static int acquire_wake_lock_callout(const char *lock_name) {
JNIEnv *env;
JavaVM *vm = AndroidRuntime::getJavaVM();
jint status = vm->GetEnv((void **)&env, JNI_VERSION_1_6);
-
if (status != JNI_OK && status != JNI_EDETACHED) {
ALOGE("%s unable to get environment for JNI call", __func__);
return BT_STATUS_FAIL;
}
-
if (status == JNI_EDETACHED && vm->AttachCurrentThread(&env, &sAttachArgs) != 0) {
ALOGE("%s unable to attach thread to VM", __func__);
return BT_STATUS_FAIL;
@@ -564,12 +558,10 @@ static int release_wake_lock_callout(const char *lock_name) {
ALOGE("%s unable to get environment for JNI call", __func__);
return BT_STATUS_FAIL;
}
-
if (status == JNI_EDETACHED && vm->AttachCurrentThread(&env, &sAttachArgs) != 0) {
ALOGE("%s unable to attach thread to VM", __func__);
return BT_STATUS_FAIL;
}
-
jboolean ret = JNI_FALSE;
jstring lock_name_jni = env->NewStringUTF(lock_name);
if (lock_name_jni) {
@@ -578,11 +570,9 @@ static int release_wake_lock_callout(const char *lock_name) {
} else {
ALOGE("%s unable to allocate string: %s", __func__, lock_name);
}
-
if (status == JNI_EDETACHED) {
vm->DetachCurrentThread();
}
-
return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}
@@ -596,73 +586,6 @@ static void alarmFiredNative(JNIEnv *env, jobject obj) {
}
}
-static void remote_mas_instances_callback(bt_status_t status, bt_bdaddr_t *bd_addr,
- int num_instances, btmce_mas_instance_t *instances)
-{
- if (!checkCallbackThread()) {
- ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
- return;
- }
-
- ALOGV("%s: Status is: %d, Instances: %d", __FUNCTION__, status, num_instances);
-
- if (status != BT_STATUS_SUCCESS) {
- ALOGE("%s: Status %d is incorrect", __FUNCTION__, status);
- return;
- }
-
- callbackEnv->PushLocalFrame(ADDITIONAL_NREFS);
-
- jbyteArray addr = NULL;
- jobjectArray a_name = NULL;
- jintArray a_scn = NULL;
- jintArray a_masid = NULL;
- jintArray a_msgtype = NULL;
- jclass mclass;
-
- mclass = callbackEnv->FindClass("java/lang/String");
-
- addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
- if (addr == NULL) goto clean;
-
- callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr);
-
- a_name = callbackEnv->NewObjectArray(num_instances, mclass, NULL);
- if (a_name == NULL) goto clean;
-
- a_scn = callbackEnv->NewIntArray(num_instances);
- if (a_scn == NULL) goto clean;
-
- a_masid = callbackEnv->NewIntArray(num_instances);
- if (a_masid == NULL) goto clean;
-
- a_msgtype = callbackEnv->NewIntArray(num_instances);
- if (a_msgtype == NULL) goto clean;
-
- for (int i = 0; i < num_instances; i++) {
- jstring name = callbackEnv->NewStringUTF(instances[i].p_name);
-
- callbackEnv->SetObjectArrayElement(a_name, i, name);
- callbackEnv->SetIntArrayRegion(a_scn, i, 1, &instances[i].scn);
- callbackEnv->SetIntArrayRegion(a_masid, i, 1, &instances[i].id);
- callbackEnv->SetIntArrayRegion(a_msgtype, i, 1, &instances[i].msg_types);
-
- callbackEnv->DeleteLocalRef(name);
- }
-
- callbackEnv->CallVoidMethod(sJniCallbacksObj, method_deviceMasInstancesFoundCallback,
- (jint) status, addr, a_name, a_scn, a_masid, a_msgtype);
- checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
-
-clean:
- if (addr != NULL) callbackEnv->DeleteLocalRef(addr);
- if (a_name != NULL) callbackEnv->DeleteLocalRef(a_name);
- if (a_scn != NULL) callbackEnv->DeleteLocalRef(a_scn);
- if (a_masid != NULL) callbackEnv->DeleteLocalRef(a_masid);
- if (a_msgtype != NULL) callbackEnv->DeleteLocalRef(a_msgtype);
- callbackEnv->PopLocalFrame(NULL);
-}
-
static bt_os_callouts_t sBluetoothOsCallouts = {
sizeof(sBluetoothOsCallouts),
set_wake_alarm_callout,
@@ -670,10 +593,7 @@ static bt_os_callouts_t sBluetoothOsCallouts = {
release_wake_lock_callout,
};
-static btmce_callbacks_t sBluetoothMceCallbacks = {
- sizeof(sBluetoothMceCallbacks),
- remote_mas_instances_callback,
-};
+
static void classInitNative(JNIEnv* env, jclass clazz) {
int err;
@@ -710,9 +630,6 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
method_setWakeAlarm = env->GetMethodID(clazz, "setWakeAlarm", "(JZ)Z");
method_acquireWakeLock = env->GetMethodID(clazz, "acquireWakeLock", "(Ljava/lang/String;)Z");
method_releaseWakeLock = env->GetMethodID(clazz, "releaseWakeLock", "(Ljava/lang/String;)Z");
- method_deviceMasInstancesFoundCallback = env->GetMethodID(jniCallbackClass,
- "deviceMasInstancesFoundCallback",
- "(I[B[Ljava/lang/String;[I[I[I)V");
method_energyInfo = env->GetMethodID(clazz, "energyInfoCallback", "(IIJJJJ)V");
char value[PROPERTY_VALUE_MAX];
@@ -762,16 +679,6 @@ static bool initNative(JNIEnv* env, jobject obj) {
ALOGE("Error getting socket interface");
}
- if ( (sBluetoothMceInterface = (btmce_interface_t *)
- sBluetoothInterface->get_profile_interface(BT_PROFILE_MAP_CLIENT_ID)) == NULL) {
- ALOGE("Error getting mapclient interface");
- } else {
- if ( (sBluetoothMceInterface->init(&sBluetoothMceCallbacks)) != BT_STATUS_SUCCESS) {
- ALOGE("Failed to initialize Bluetooth MCE");
- sBluetoothMceInterface = NULL;
- }
- }
-
return JNI_TRUE;
}
return JNI_FALSE;
@@ -1090,25 +997,6 @@ static jboolean getRemoteServicesNative(JNIEnv *env, jobject obj, jbyteArray add
return result;
}
-static jboolean getRemoteMasInstancesNative(JNIEnv *env, jobject obj, jbyteArray address) {
- ALOGV("%s:",__FUNCTION__);
-
- jbyte *addr = NULL;
- jboolean result = JNI_FALSE;
- if (!sBluetoothMceInterface) return result;
-
- addr = env->GetByteArrayElements(address, NULL);
- if (addr == NULL) {
- jniThrowIOException(env, EINVAL);
- return result;
- }
-
- int ret = sBluetoothMceInterface->get_remote_mas_instances((bt_bdaddr_t *)addr);
- env->ReleaseByteArrayElements(address, addr, NULL);
- result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
- return result;
-}
-
static int connectSocketNative(JNIEnv *env, jobject object, jbyteArray address, jint type,
jbyteArray uuidObj, jint channel, jint flag) {
jbyte *addr = NULL, *uuid = NULL;
@@ -1123,10 +1011,12 @@ static int connectSocketNative(JNIEnv *env, jobject object, jbyteArray address,
goto Fail;
}
- uuid = env->GetByteArrayElements(uuidObj, NULL);
- if (!uuid) {
- ALOGE("failed to get uuid");
- goto Fail;
+ if(uuidObj != NULL) {
+ uuid = env->GetByteArrayElements(uuidObj, NULL);
+ if (!uuid) {
+ ALOGE("failed to get uuid");
+ goto Fail;
+ }
}
if ( (status = sBluetoothSocketInterface->connect((bt_bdaddr_t *) addr, (btsock_type_t) type,
@@ -1137,7 +1027,7 @@ static int connectSocketNative(JNIEnv *env, jobject object, jbyteArray address,
if (socket_fd < 0) {
- ALOGE("Fail to creat file descriptor on socket fd");
+ ALOGE("Fail to create file descriptor on socket fd");
goto Fail;
}
env->ReleaseByteArrayElements(address, addr, 0);
@@ -1153,7 +1043,7 @@ Fail:
static int createSocketChannelNative(JNIEnv *env, jobject object, jint type,
jstring name_str, jbyteArray uuidObj, jint channel, jint flag) {
- const char *service_name;
+ const char *service_name = NULL;
jbyte *uuid = NULL;
int socket_fd;
bt_status_t status;
@@ -1162,12 +1052,16 @@ static int createSocketChannelNative(JNIEnv *env, jobject object, jint type,
ALOGV("%s: SOCK FLAG = %x", __FUNCTION__, flag);
- service_name = env->GetStringUTFChars(name_str, NULL);
+ if(name_str != NULL) {
+ service_name = env->GetStringUTFChars(name_str, NULL);
+ }
- uuid = env->GetByteArrayElements(uuidObj, NULL);
- if (!uuid) {
- ALOGE("failed to get uuid");
- goto Fail;
+ if(uuidObj != NULL) {
+ uuid = env->GetByteArrayElements(uuidObj, NULL);
+ if (!uuid) {
+ ALOGE("failed to get uuid");
+ goto Fail;
+ }
}
if ( (status = sBluetoothSocketInterface->listen((btsock_type_t) type, service_name,
(const uint8_t*) uuid, channel, &socket_fd, flag)) != BT_STATUS_SUCCESS) {
@@ -1186,7 +1080,6 @@ static int createSocketChannelNative(JNIEnv *env, jobject object, jint type,
Fail:
if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
if (uuid) env->ReleaseByteArrayElements(uuidObj, uuid, 0);
-
return -1;
}
@@ -1235,7 +1128,6 @@ static JNINativeMethod sMethods[] = {
{"pinReplyNative", "([BZI[B)Z", (void*) pinReplyNative},
{"sspReplyNative", "([BIZI)Z", (void*) sspReplyNative},
{"getRemoteServicesNative", "([B)Z", (void*) getRemoteServicesNative},
- {"getRemoteMasInstancesNative", "([B)Z", (void*) getRemoteMasInstancesNative},
{"connectSocketNative", "([BI[BII)I", (void*) connectSocketNative},
{"createSocketChannelNative", "(ILjava/lang/String;[BII)I",
(void*) createSocketChannelNative},
@@ -1323,5 +1215,11 @@ jint JNI_OnLoad(JavaVM *jvm, void *reserved)
ALOGE("jni gatt registration failure: %d", status);
return JNI_ERR;
}
+
+ if ((status = android::register_com_android_bluetooth_sdp(e)) < 0) {
+ ALOGE("jni sdp registration failure: %d", status);
+ return JNI_ERR;
+ }
+
return JNI_VERSION_1_6;
}
diff --git a/jni/com_android_bluetooth_sdp.cpp b/jni/com_android_bluetooth_sdp.cpp
new file mode 100644
index 000000000..19c38a610
--- /dev/null
+++ b/jni/com_android_bluetooth_sdp.cpp
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BluetoothSdpJni"
+
+#define LOG_NDEBUG 0
+
+#include "com_android_bluetooth.h"
+#include "hardware/bt_sdp.h"
+#include "utils/Log.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <string.h>
+
+
+namespace android {
+static jmethodID method_sdpRecordFoundCallback;
+static jmethodID method_sdpMasRecordFoundCallback;
+static jmethodID method_sdpMnsRecordFoundCallback;
+static jmethodID method_sdpPseRecordFoundCallback;
+static jmethodID method_sdpOppOpsRecordFoundCallback;
+
+static const btsdp_interface_t *sBluetoothSdpInterface = NULL;
+
+static void sdp_search_callback(bt_status_t status, bt_bdaddr_t *bd_addr, uint8_t* uuid_in,
+ int record_size, bluetooth_sdp_record* record);
+
+btsdp_callbacks_t sBluetoothSdpCallbacks = {
+ sizeof(sBluetoothSdpCallbacks),
+ sdp_search_callback
+};
+
+static jobject sCallbacksObj = NULL;
+static JNIEnv *sCallbackEnv = NULL;
+
+static bool checkCallbackThread() {
+ sCallbackEnv = getCallbackEnv();
+
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (sCallbackEnv != env || sCallbackEnv == NULL) {
+ ALOGE("Callback env check fail: env: %p, callback: %p", env, sCallbackEnv);
+ return false;
+ }
+ return true;
+}
+
+static void initializeNative(JNIEnv *env, jobject object) {
+ const bt_interface_t* btInf;
+ bt_status_t status;
+
+ if ( (btInf = getBluetoothInterface()) == NULL) {
+ ALOGE("Bluetooth module is not loaded");
+ return;
+ }
+ if (sBluetoothSdpInterface !=NULL) {
+ ALOGW("Cleaning up Bluetooth SDP Interface before initializing...");
+ sBluetoothSdpInterface->deinit();
+ sBluetoothSdpInterface = NULL;
+ }
+ if ( (sBluetoothSdpInterface = (btsdp_interface_t *)
+ btInf->get_profile_interface(BT_PROFILE_SDP_CLIENT_ID)) == NULL) {
+ ALOGE("Error getting SDP client interface");
+ }else{
+ sBluetoothSdpInterface->init(&sBluetoothSdpCallbacks);
+ }
+
+ sCallbacksObj = env->NewGlobalRef(object);
+}
+
+static void classInitNative(JNIEnv* env, jclass clazz) {
+
+ /* generic SDP record (raw data)*/
+ method_sdpRecordFoundCallback = env->GetMethodID(clazz,
+ "sdpRecordFoundCallback",
+ "(I[B[BI[B)V");
+
+ /* MAS SDP record*/
+ method_sdpMasRecordFoundCallback = env->GetMethodID(clazz,
+ "sdpMasRecordFoundCallback",
+ "(I[B[BIIIIIILjava/lang/String;Z)V");
+ /* MNS SDP record*/
+ method_sdpMnsRecordFoundCallback = env->GetMethodID(clazz,
+ "sdpMnsRecordFoundCallback",
+ "(I[B[BIIIILjava/lang/String;Z)V");
+ /* PBAP PSE record */
+ method_sdpPseRecordFoundCallback = env->GetMethodID(clazz,
+ "sdpPseRecordFoundCallback",
+ "(I[B[BIIIIILjava/lang/String;Z)V");
+ /* OPP Server record */
+ method_sdpOppOpsRecordFoundCallback = env->GetMethodID(clazz,
+ "sdpOppOpsRecordFoundCallback",
+ "(I[B[BIIILjava/lang/String;[BZ)V");
+
+}
+
+static jboolean sdpSearchNative(JNIEnv *env, jobject obj, jbyteArray address, jbyteArray uuidObj) {
+ ALOGD("%s:",__FUNCTION__);
+
+ jbyte *addr = NULL, *uuid = NULL;
+ jboolean result = JNI_FALSE;
+ int ret;
+ if (!sBluetoothSdpInterface)
+ goto Fail;
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (addr == NULL) {
+ jniThrowIOException(env, EINVAL);
+ goto Fail;
+ }
+ uuid = env->GetByteArrayElements(uuidObj, NULL);
+ if (!uuid) {
+ ALOGE("failed to get uuid");
+ goto Fail;
+ }
+ ALOGD("%s UUID %.*X",__FUNCTION__,16, (uint8_t*)uuid);
+
+
+ if ( (ret = sBluetoothSdpInterface->sdp_search((bt_bdaddr_t *)addr,
+ (const uint8_t*)uuid)) != BT_STATUS_SUCCESS) {
+ ALOGE("SDP Search initialization failed: %d", ret);
+ goto Fail;
+ }
+
+ result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
+
+ Fail:
+ if (addr) env->ReleaseByteArrayElements(address, addr, 0);
+ if (uuid) env->ReleaseByteArrayElements(uuidObj, uuid, 0);
+ return result;
+}
+
+static void sdp_search_callback(bt_status_t status, bt_bdaddr_t *bd_addr, uint8_t* uuid_in,
+ int count, bluetooth_sdp_record* records)
+{
+
+ jbyteArray addr = NULL;
+ jbyteArray uuid = NULL;
+ jstring service_name = NULL;
+ int i = 0;
+ bluetooth_sdp_record* record;
+
+ if (!checkCallbackThread()) {
+ ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
+ goto clean;
+ }
+
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (addr == NULL) goto clean;
+
+ uuid = sCallbackEnv->NewByteArray(sizeof(bt_uuid_t));
+ if (uuid == NULL) goto clean;
+
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr);
+ sCallbackEnv->SetByteArrayRegion(uuid, 0, sizeof(bt_uuid_t), (jbyte*)uuid_in);
+
+ ALOGD("%s: Status is: %d, Record count: %d", __FUNCTION__, status, count);
+
+ // Ensure we run the loop at least once, to also signal errors if they occure
+ for(i = 0; i < count || i==0; i++) {
+ bool more_results = (i<(count-1))?true:false;
+ record = &records[i];
+ service_name = NULL;
+ if (record->hdr.service_name_length > 0) {
+ ALOGD("%s, ServiceName: %s", __FUNCTION__, record->mas.hdr.service_name);
+ service_name = (jstring)sCallbackEnv->NewStringUTF(record->mas.hdr.service_name);
+ }
+
+ /* call the right callback according to the uuid*/
+ if (IS_UUID(UUID_MAP_MAS,uuid_in)){
+
+ sCallbackEnv->CallVoidMethod(sCallbacksObj, method_sdpMasRecordFoundCallback,
+ (jint) status,
+ addr,
+ uuid,
+ (jint)record->mas.mas_instance_id,
+ (jint)record->mas.hdr.l2cap_psm,
+ (jint)record->mas.hdr.rfcomm_channel_number,
+ (jint)record->mas.hdr.profile_version,
+ (jint)record->mas.supported_features,
+ (jint)record->mas.supported_message_types,
+ service_name,
+ more_results);
+
+ }else if (IS_UUID(UUID_MAP_MNS,uuid_in)){
+
+ sCallbackEnv->CallVoidMethod(sCallbacksObj, method_sdpMnsRecordFoundCallback,
+ (jint) status,
+ addr,
+ uuid,
+ (jint)record->mns.hdr.l2cap_psm,
+ (jint)record->mns.hdr.rfcomm_channel_number,
+ (jint)record->mns.hdr.profile_version,
+ (jint)record->mns.supported_features,
+ service_name,
+ more_results);
+
+ } else if (IS_UUID(UUID_PBAP_PSE, uuid_in)) {
+
+ sCallbackEnv->CallVoidMethod(sCallbacksObj, method_sdpPseRecordFoundCallback,
+ (jint) status,
+ addr,
+ uuid,
+ (jint)record->pse.hdr.l2cap_psm,
+ (jint)record->pse.hdr.rfcomm_channel_number,
+ (jint)record->pse.hdr.profile_version,
+ (jint)record->pse.supported_features,
+ (jint)record->pse.supported_repositories,
+ service_name,
+ more_results);
+
+ } else if (IS_UUID(UUID_OBEX_OBJECT_PUSH, uuid_in)) {
+
+ jint formats_list_size = record->ops.supported_formats_list_len;
+ jbyteArray formats_list = sCallbackEnv->NewByteArray(formats_list_size);
+ if (formats_list == NULL) goto clean;
+ sCallbackEnv->SetByteArrayRegion(formats_list, 0, formats_list_size,
+ (jbyte*)record->ops.supported_formats_list);
+
+ sCallbackEnv->CallVoidMethod(sCallbacksObj, method_sdpOppOpsRecordFoundCallback,
+ (jint) status,
+ addr,
+ uuid,
+ (jint)record->ops.hdr.l2cap_psm,
+ (jint)record->ops.hdr.rfcomm_channel_number,
+ (jint)record->ops.hdr.profile_version,
+ service_name,
+ formats_list,
+ more_results);
+ sCallbackEnv->DeleteLocalRef(formats_list);
+
+ } else {
+ // we don't have a wrapper for this uuid, send as raw data
+ jint record_data_size = record->hdr.user1_ptr_len;
+ jbyteArray record_data = NULL;
+
+ record_data = sCallbackEnv->NewByteArray(record_data_size);
+ if (record_data == NULL) goto clean;
+
+ sCallbackEnv->SetByteArrayRegion(record_data, 0, record_data_size,
+ (jbyte*)record->hdr.user1_ptr);
+ sCallbackEnv->CallVoidMethod(sCallbacksObj, method_sdpRecordFoundCallback,
+ (jint) status, addr, uuid, record_data_size, record_data);
+
+ sCallbackEnv->DeleteLocalRef(record_data);
+
+ }
+ // Cleanup for each iteration
+ if (service_name != NULL) {
+ sCallbackEnv->DeleteLocalRef(service_name);
+ service_name = NULL;
+ }
+ } // End of for-loop
+
+ clean:
+ if (service_name != NULL)
+ sCallbackEnv->DeleteLocalRef(service_name);
+ if (addr != NULL) sCallbackEnv->DeleteLocalRef(addr);
+ if (uuid != NULL) sCallbackEnv->DeleteLocalRef(uuid);
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+}
+
+static jint sdpCreateMapMasRecordNative(JNIEnv *env, jobject obj, jstring name_str, jint mas_id,
+ jint scn, jint l2cap_psm, jint version,
+ jint msg_types, jint features) {
+ ALOGD("%s:",__FUNCTION__);
+
+ const char* service_name = NULL;
+ bluetooth_sdp_record record = {}; // Must be zero initialized
+ int handle=-1;
+ int ret = 0;
+ if (!sBluetoothSdpInterface) return handle;
+
+ record.mas.hdr.type = SDP_TYPE_MAP_MAS;
+
+ if (name_str != NULL) {
+ service_name = env->GetStringUTFChars(name_str, NULL);
+ record.mas.hdr.service_name = (char *) service_name;
+ record.mas.hdr.service_name_length = strlen(service_name);
+ } else {
+ record.mas.hdr.service_name = NULL;
+ record.mas.hdr.service_name_length = 0;
+ }
+ record.mas.hdr.rfcomm_channel_number = scn;
+ record.mas.hdr.l2cap_psm = l2cap_psm;
+ record.mas.hdr.profile_version = version;
+
+ record.mas.mas_instance_id = mas_id;
+ record.mas.supported_features = features;
+ record.mas.supported_message_types = msg_types;
+
+ if ( (ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle))
+ != BT_STATUS_SUCCESS) {
+ ALOGE("SDP Create record failed: %d", ret);
+ goto Fail;
+ }
+
+ ALOGD("SDP Create record success - handle: %d", handle);
+
+ Fail:
+ if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
+ return handle;
+}
+
+static jint sdpCreateMapMnsRecordNative(JNIEnv *env, jobject obj, jstring name_str,
+ jint scn, jint l2cap_psm, jint version,
+ jint features) {
+ ALOGD("%s:",__FUNCTION__);
+
+ const char* service_name = NULL;
+ bluetooth_sdp_record record = {}; // Must be zero initialized
+ int handle=-1;
+ int ret = 0;
+ if (!sBluetoothSdpInterface) return handle;
+
+ record.mns.hdr.type = SDP_TYPE_MAP_MNS;
+
+ if (name_str != NULL) {
+ service_name = env->GetStringUTFChars(name_str, NULL);
+ record.mns.hdr.service_name = (char *) service_name;
+ record.mns.hdr.service_name_length = strlen(service_name);
+ } else {
+ record.mns.hdr.service_name = NULL;
+ record.mns.hdr.service_name_length = 0;
+ }
+ record.mns.hdr.rfcomm_channel_number = scn;
+ record.mns.hdr.l2cap_psm = l2cap_psm;
+ record.mns.hdr.profile_version = version;
+
+ record.mns.supported_features = features;
+
+ if ( (ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle))
+ != BT_STATUS_SUCCESS) {
+ ALOGE("SDP Create record failed: %d", ret);
+ goto Fail;
+ }
+
+ ALOGD("SDP Create record success - handle: %d", handle);
+
+ Fail:
+ if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
+ return handle;
+}
+
+static jint sdpCreatePbapPseRecordNative(JNIEnv *env, jobject obj, jstring name_str,
+ jint scn, jint l2cap_psm, jint version,
+ jint supported_repositories, jint features) {
+ ALOGD("%s:",__FUNCTION__);
+
+ const char* service_name = NULL;
+ bluetooth_sdp_record record = {}; // Must be zero initialized
+ int handle=-1;
+ int ret = 0;
+ if (!sBluetoothSdpInterface) return handle;
+
+ record.pse.hdr.type = SDP_TYPE_PBAP_PSE;
+
+ if (name_str != NULL) {
+ service_name = env->GetStringUTFChars(name_str, NULL);
+ record.pse.hdr.service_name = (char *) service_name;
+ record.pse.hdr.service_name_length = strlen(service_name);
+ } else {
+ record.pse.hdr.service_name = NULL;
+ record.pse.hdr.service_name_length = 0;
+ }
+ record.pse.hdr.rfcomm_channel_number = scn;
+ record.pse.hdr.l2cap_psm = l2cap_psm;
+ record.pse.hdr.profile_version = version;
+
+ record.pse.supported_features = features;
+ record.pse.supported_repositories = supported_repositories;
+
+ if ( (ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle))
+ != BT_STATUS_SUCCESS) {
+ ALOGE("SDP Create record failed: %d", ret);
+ goto Fail;
+ }
+
+ ALOGD("SDP Create record success - handle: %d", handle);
+
+ Fail:
+ if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
+ return handle;
+}
+
+static jint sdpCreateOppOpsRecordNative(JNIEnv *env, jobject obj, jstring name_str,
+ jint scn, jint l2cap_psm, jint version,
+ jbyteArray supported_formats_list) {
+ ALOGD("%s:",__FUNCTION__);
+
+ const char* service_name = NULL;
+ bluetooth_sdp_record record = {}; // Must be zero initialized
+ jbyte* formats_list;
+ int formats_list_len = 0;
+ int handle=-1;
+ int ret = 0;
+ if (!sBluetoothSdpInterface) return handle;
+
+ record.ops.hdr.type = SDP_TYPE_OPP_SERVER;
+
+ if (name_str != NULL) {
+ service_name = env->GetStringUTFChars(name_str, NULL);
+ record.ops.hdr.service_name = (char *) service_name;
+ record.ops.hdr.service_name_length = strlen(service_name);
+ } else {
+ record.ops.hdr.service_name = NULL;
+ record.ops.hdr.service_name_length = 0;
+ }
+ record.ops.hdr.rfcomm_channel_number = scn;
+ record.ops.hdr.l2cap_psm = l2cap_psm;
+ record.ops.hdr.profile_version = version;
+
+ formats_list = env->GetByteArrayElements(supported_formats_list, NULL);
+ if (formats_list != NULL) {
+ formats_list_len = env->GetArrayLength(supported_formats_list);
+ if (formats_list_len > SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH) {
+ formats_list_len = SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH;
+ }
+ memcpy(record.ops.supported_formats_list, formats_list, formats_list_len);
+ }
+
+ record.ops.supported_formats_list_len = formats_list_len;
+
+ if ( (ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle))
+ != BT_STATUS_SUCCESS) {
+ ALOGE("SDP Create record failed: %d", ret);
+ goto Fail;
+ }
+
+ ALOGD("SDP Create record success - handle: %d", handle);
+
+ Fail:
+ if (service_name) env->ReleaseStringUTFChars(name_str, service_name);
+ if (formats_list) env->ReleaseByteArrayElements(supported_formats_list, formats_list, 0);
+ return handle;
+}
+
+static jboolean sdpRemoveSdpRecordNative(JNIEnv *env, jobject obj, jint record_id) {
+ ALOGD("%s:",__FUNCTION__);
+
+ int ret = 0;
+ if (!sBluetoothSdpInterface) return false;
+
+ if ( (ret = sBluetoothSdpInterface->remove_sdp_record(record_id))
+ != BT_STATUS_SUCCESS) {
+ ALOGE("SDP Remove record failed: %d", ret);
+ return false;
+ }
+
+ ALOGD("SDP Remove record success - handle: %d", record_id);
+ return true;
+}
+
+
+static void cleanupNative(JNIEnv *env, jobject object) {
+ const bt_interface_t* btInf;
+ bt_status_t status;
+
+ if ( (btInf = getBluetoothInterface()) == NULL) {
+ ALOGE("Bluetooth module is not loaded");
+ return;
+ }
+
+ if (sBluetoothSdpInterface !=NULL) {
+ ALOGW("Cleaning up Bluetooth SDP Interface...");
+ sBluetoothSdpInterface->deinit();
+ sBluetoothSdpInterface = NULL;
+ }
+
+ if (sCallbacksObj != NULL) {
+ ALOGW("Cleaning up Bluetooth Health object");
+ env->DeleteGlobalRef(sCallbacksObj);
+ sCallbacksObj = NULL;
+ }
+}
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"classInitNative", "()V", (void *) classInitNative},
+ {"initializeNative", "()V", (void *) initializeNative},
+ {"cleanupNative", "()V", (void*) cleanupNative},
+ {"sdpSearchNative", "([B[B)Z", (void*) sdpSearchNative},
+ {"sdpCreateMapMasRecordNative", "(Ljava/lang/String;IIIIII)I",
+ (void*) sdpCreateMapMasRecordNative},
+ {"sdpCreateMapMnsRecordNative", "(Ljava/lang/String;IIII)I",
+ (void*) sdpCreateMapMnsRecordNative},
+ {"sdpCreatePbapPseRecordNative", "(Ljava/lang/String;IIIII)I",
+ (void*) sdpCreatePbapPseRecordNative},
+ {"sdpCreateOppOpsRecordNative", "(Ljava/lang/String;III[B)I",
+ (void*) sdpCreateOppOpsRecordNative},
+ {"sdpRemoveSdpRecordNative", "(I)Z", (void*) sdpRemoveSdpRecordNative}
+};
+
+int register_com_android_bluetooth_sdp(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "com/android/bluetooth/sdp/SdpManager",
+ sMethods, NELEM(sMethods));
+}
+
+
+}