1 /* 2 * Copyright (C) 2015 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 "BluetoothSdpJni" 18 19 #define LOG_NDEBUG 0 20 21 #include "android_runtime/AndroidRuntime.h" 22 #include "com_android_bluetooth.h" 23 #include "hardware/bt_sdp.h" 24 #include "utils/Log.h" 25 26 #include <string.h> 27 28 static const uint8_t UUID_OBEX_OBJECT_PUSH[] = { 29 0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00, 30 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}; 31 static const uint8_t UUID_PBAP_PSE[] = {0x00, 0x00, 0x11, 0x2F, 0x00, 0x00, 32 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 33 0x5F, 0x9B, 0x34, 0xFB}; 34 static const uint8_t UUID_MAP_MAS[] = {0x00, 0x00, 0x11, 0x32, 0x00, 0x00, 35 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 36 0x5F, 0x9B, 0x34, 0xFB}; 37 static const uint8_t UUID_MAP_MNS[] = {0x00, 0x00, 0x11, 0x33, 0x00, 0x00, 38 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 39 0x5F, 0x9B, 0x34, 0xFB}; 40 static const uint8_t UUID_SAP[] = {0x00, 0x00, 0x11, 0x2D, 0x00, 0x00, 41 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 42 0x5F, 0x9B, 0x34, 0xFB}; 43 // TODO: 44 // Both the fact that the UUIDs are declared in multiple places, plus the fact 45 // that there is a mess of UUID comparison and shortening methods will have to 46 // be fixed. 47 // The btcore->uuid module should be used for all instances. 48 49 #define UUID_MAX_LENGTH 16 50 #define IS_UUID(u1, u2) !memcmp(u1, u2, UUID_MAX_LENGTH) 51 52 namespace android { 53 static jmethodID method_sdpRecordFoundCallback; 54 static jmethodID method_sdpMasRecordFoundCallback; 55 static jmethodID method_sdpMnsRecordFoundCallback; 56 static jmethodID method_sdpPseRecordFoundCallback; 57 static jmethodID method_sdpOppOpsRecordFoundCallback; 58 static jmethodID method_sdpSapsRecordFoundCallback; 59 60 static const btsdp_interface_t* sBluetoothSdpInterface = NULL; 61 62 static void sdp_search_callback(bt_status_t status, RawAddress* bd_addr, 63 uint8_t* uuid_in, int record_size, 64 bluetooth_sdp_record* record); 65 66 btsdp_callbacks_t sBluetoothSdpCallbacks = {sizeof(sBluetoothSdpCallbacks), 67 sdp_search_callback}; 68 69 static jobject sCallbacksObj = NULL; 70 71 static void initializeNative(JNIEnv* env, jobject object) { 72 const bt_interface_t* btInf = getBluetoothInterface(); 73 74 if (btInf == NULL) { 75 ALOGE("Bluetooth module is not loaded"); 76 return; 77 } 78 if (sBluetoothSdpInterface != NULL) { 79 ALOGW("Cleaning up Bluetooth SDP Interface before initializing..."); 80 sBluetoothSdpInterface->deinit(); 81 sBluetoothSdpInterface = NULL; 82 } 83 84 sBluetoothSdpInterface = (btsdp_interface_t*)btInf->get_profile_interface( 85 BT_PROFILE_SDP_CLIENT_ID); 86 if (sBluetoothSdpInterface == NULL) { 87 ALOGE("Error getting SDP client interface"); 88 } else { 89 sBluetoothSdpInterface->init(&sBluetoothSdpCallbacks); 90 } 91 92 sCallbacksObj = env->NewGlobalRef(object); 93 } 94 95 static void classInitNative(JNIEnv* env, jclass clazz) { 96 /* generic SDP record (raw data)*/ 97 method_sdpRecordFoundCallback = 98 env->GetMethodID(clazz, "sdpRecordFoundCallback", "(I[B[BI[B)V"); 99 100 /* MAS SDP record*/ 101 method_sdpMasRecordFoundCallback = env->GetMethodID( 102 clazz, "sdpMasRecordFoundCallback", "(I[B[BIIIIIILjava/lang/String;Z)V"); 103 /* MNS SDP record*/ 104 method_sdpMnsRecordFoundCallback = env->GetMethodID( 105 clazz, "sdpMnsRecordFoundCallback", "(I[B[BIIIILjava/lang/String;Z)V"); 106 /* PBAP PSE record */ 107 method_sdpPseRecordFoundCallback = env->GetMethodID( 108 clazz, "sdpPseRecordFoundCallback", "(I[B[BIIIIILjava/lang/String;Z)V"); 109 /* OPP Server record */ 110 method_sdpOppOpsRecordFoundCallback = 111 env->GetMethodID(clazz, "sdpOppOpsRecordFoundCallback", 112 "(I[B[BIIILjava/lang/String;[BZ)V"); 113 /* SAP Server record */ 114 method_sdpSapsRecordFoundCallback = env->GetMethodID( 115 clazz, "sdpSapsRecordFoundCallback", "(I[B[BIILjava/lang/String;Z)V"); 116 } 117 118 static jboolean sdpSearchNative(JNIEnv* env, jobject obj, jbyteArray address, 119 jbyteArray uuidObj) { 120 ALOGD("%s", __func__); 121 122 if (!sBluetoothSdpInterface) return JNI_FALSE; 123 124 jbyte* addr = env->GetByteArrayElements(address, NULL); 125 if (addr == NULL) { 126 jniThrowIOException(env, EINVAL); 127 return JNI_FALSE; 128 } 129 130 jbyte* uuid = env->GetByteArrayElements(uuidObj, NULL); 131 if (!uuid) { 132 ALOGE("failed to get uuid"); 133 env->ReleaseByteArrayElements(address, addr, 0); 134 return JNI_FALSE; 135 } 136 ALOGD("%s UUID %.*s", __func__, 16, (uint8_t*)uuid); 137 138 int ret = sBluetoothSdpInterface->sdp_search((RawAddress*)addr, 139 (const uint8_t*)uuid); 140 if (ret != BT_STATUS_SUCCESS) { 141 ALOGE("SDP Search initialization failed: %d", ret); 142 } 143 144 if (addr) env->ReleaseByteArrayElements(address, addr, 0); 145 if (uuid) env->ReleaseByteArrayElements(uuidObj, uuid, 0); 146 return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 147 } 148 149 static void sdp_search_callback(bt_status_t status, RawAddress* bd_addr, 150 uint8_t* uuid_in, int count, 151 bluetooth_sdp_record* records) { 152 CallbackEnv sCallbackEnv(__func__); 153 if (!sCallbackEnv.valid()) return; 154 155 ScopedLocalRef<jbyteArray> addr( 156 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 157 if (!addr.get()) return; 158 159 ScopedLocalRef<jbyteArray> uuid( 160 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_uuid_t))); 161 if (!uuid.get()) return; 162 163 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 164 (jbyte*)bd_addr); 165 sCallbackEnv->SetByteArrayRegion(uuid.get(), 0, sizeof(bt_uuid_t), 166 (jbyte*)uuid_in); 167 168 ALOGD("%s: Status is: %d, Record count: %d", __func__, status, count); 169 170 // Ensure we run the loop at least once, to also signal errors if they occur 171 for (int i = 0; i < count || i == 0; i++) { 172 bool more_results = (i < (count - 1)) ? true : false; 173 bluetooth_sdp_record* record = &records[i]; 174 ScopedLocalRef<jstring> service_name(sCallbackEnv.get(), NULL); 175 if (record->hdr.service_name_length > 0) { 176 ALOGD("%s, ServiceName: %s", __func__, record->mas.hdr.service_name); 177 service_name.reset( 178 (jstring)sCallbackEnv->NewStringUTF(record->mas.hdr.service_name)); 179 } 180 181 /* call the right callback according to the uuid*/ 182 if (IS_UUID(UUID_MAP_MAS, uuid_in)) { 183 sCallbackEnv->CallVoidMethod( 184 sCallbacksObj, method_sdpMasRecordFoundCallback, (jint)status, 185 addr.get(), uuid.get(), (jint)record->mas.mas_instance_id, 186 (jint)record->mas.hdr.l2cap_psm, 187 (jint)record->mas.hdr.rfcomm_channel_number, 188 (jint)record->mas.hdr.profile_version, 189 (jint)record->mas.supported_features, 190 (jint)record->mas.supported_message_types, service_name.get(), 191 more_results); 192 193 } else if (IS_UUID(UUID_MAP_MNS, uuid_in)) { 194 sCallbackEnv->CallVoidMethod( 195 sCallbacksObj, method_sdpMnsRecordFoundCallback, (jint)status, 196 addr.get(), uuid.get(), (jint)record->mns.hdr.l2cap_psm, 197 (jint)record->mns.hdr.rfcomm_channel_number, 198 (jint)record->mns.hdr.profile_version, 199 (jint)record->mns.supported_features, service_name.get(), 200 more_results); 201 202 } else if (IS_UUID(UUID_PBAP_PSE, uuid_in)) { 203 sCallbackEnv->CallVoidMethod( 204 sCallbacksObj, method_sdpPseRecordFoundCallback, (jint)status, 205 addr.get(), uuid.get(), (jint)record->pse.hdr.l2cap_psm, 206 (jint)record->pse.hdr.rfcomm_channel_number, 207 (jint)record->pse.hdr.profile_version, 208 (jint)record->pse.supported_features, 209 (jint)record->pse.supported_repositories, service_name.get(), 210 more_results); 211 212 } else if (IS_UUID(UUID_OBEX_OBJECT_PUSH, uuid_in)) { 213 jint formats_list_size = record->ops.supported_formats_list_len; 214 ScopedLocalRef<jbyteArray> formats_list( 215 sCallbackEnv.get(), sCallbackEnv->NewByteArray(formats_list_size)); 216 if (!formats_list.get()) return; 217 sCallbackEnv->SetByteArrayRegion( 218 formats_list.get(), 0, formats_list_size, 219 (jbyte*)record->ops.supported_formats_list); 220 221 sCallbackEnv->CallVoidMethod( 222 sCallbacksObj, method_sdpOppOpsRecordFoundCallback, (jint)status, 223 addr.get(), uuid.get(), (jint)record->ops.hdr.l2cap_psm, 224 (jint)record->ops.hdr.rfcomm_channel_number, 225 (jint)record->ops.hdr.profile_version, service_name.get(), 226 formats_list.get(), more_results); 227 228 } else if (IS_UUID(UUID_SAP, uuid_in)) { 229 sCallbackEnv->CallVoidMethod( 230 sCallbacksObj, method_sdpSapsRecordFoundCallback, (jint)status, 231 addr.get(), uuid.get(), (jint)record->mas.hdr.rfcomm_channel_number, 232 (jint)record->mas.hdr.profile_version, service_name.get(), 233 more_results); 234 } else { 235 // we don't have a wrapper for this uuid, send as raw data 236 jint record_data_size = record->hdr.user1_ptr_len; 237 ScopedLocalRef<jbyteArray> record_data( 238 sCallbackEnv.get(), sCallbackEnv->NewByteArray(record_data_size)); 239 if (!record_data.get()) return; 240 241 sCallbackEnv->SetByteArrayRegion(record_data.get(), 0, record_data_size, 242 (jbyte*)record->hdr.user1_ptr); 243 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_sdpRecordFoundCallback, 244 (jint)status, addr.get(), uuid.get(), 245 record_data_size, record_data.get()); 246 } 247 } // End of for-loop 248 } 249 250 static jint sdpCreateMapMasRecordNative(JNIEnv* env, jobject obj, 251 jstring name_str, jint mas_id, jint scn, 252 jint l2cap_psm, jint version, 253 jint msg_types, jint features) { 254 ALOGD("%s", __func__); 255 if (!sBluetoothSdpInterface) return -1; 256 257 bluetooth_sdp_record record = {}; // Must be zero initialized 258 record.mas.hdr.type = SDP_TYPE_MAP_MAS; 259 260 const char* service_name = NULL; 261 if (name_str != NULL) { 262 service_name = env->GetStringUTFChars(name_str, NULL); 263 record.mas.hdr.service_name = (char*)service_name; 264 record.mas.hdr.service_name_length = strlen(service_name); 265 } else { 266 record.mas.hdr.service_name = NULL; 267 record.mas.hdr.service_name_length = 0; 268 } 269 record.mas.hdr.rfcomm_channel_number = scn; 270 record.mas.hdr.l2cap_psm = l2cap_psm; 271 record.mas.hdr.profile_version = version; 272 273 record.mas.mas_instance_id = mas_id; 274 record.mas.supported_features = features; 275 record.mas.supported_message_types = msg_types; 276 277 int handle = -1; 278 int ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle); 279 if (ret != BT_STATUS_SUCCESS) { 280 ALOGE("SDP Create record failed: %d", ret); 281 } else { 282 ALOGD("SDP Create record success - handle: %d", handle); 283 } 284 285 if (service_name) env->ReleaseStringUTFChars(name_str, service_name); 286 return handle; 287 } 288 289 static jint sdpCreateMapMnsRecordNative(JNIEnv* env, jobject obj, 290 jstring name_str, jint scn, 291 jint l2cap_psm, jint version, 292 jint features) { 293 ALOGD("%s", __func__); 294 if (!sBluetoothSdpInterface) return -1; 295 296 bluetooth_sdp_record record = {}; // Must be zero initialized 297 record.mns.hdr.type = SDP_TYPE_MAP_MNS; 298 299 const char* service_name = NULL; 300 if (name_str != NULL) { 301 service_name = env->GetStringUTFChars(name_str, NULL); 302 record.mns.hdr.service_name = (char*)service_name; 303 record.mns.hdr.service_name_length = strlen(service_name); 304 } else { 305 record.mns.hdr.service_name = NULL; 306 record.mns.hdr.service_name_length = 0; 307 } 308 record.mns.hdr.rfcomm_channel_number = scn; 309 record.mns.hdr.l2cap_psm = l2cap_psm; 310 record.mns.hdr.profile_version = version; 311 312 record.mns.supported_features = features; 313 314 int handle = -1; 315 int ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle); 316 if (ret != BT_STATUS_SUCCESS) { 317 ALOGE("SDP Create record failed: %d", ret); 318 } else { 319 ALOGD("SDP Create record success - handle: %d", handle); 320 } 321 322 if (service_name) env->ReleaseStringUTFChars(name_str, service_name); 323 return handle; 324 } 325 326 static jint sdpCreatePbapPseRecordNative(JNIEnv* env, jobject obj, 327 jstring name_str, jint scn, 328 jint l2cap_psm, jint version, 329 jint supported_repositories, 330 jint features) { 331 ALOGD("%s", __func__); 332 if (!sBluetoothSdpInterface) return -1; 333 334 bluetooth_sdp_record record = {}; // Must be zero initialized 335 record.pse.hdr.type = SDP_TYPE_PBAP_PSE; 336 337 const char* service_name = NULL; 338 if (name_str != NULL) { 339 service_name = env->GetStringUTFChars(name_str, NULL); 340 record.pse.hdr.service_name = (char*)service_name; 341 record.pse.hdr.service_name_length = strlen(service_name); 342 } else { 343 record.pse.hdr.service_name = NULL; 344 record.pse.hdr.service_name_length = 0; 345 } 346 record.pse.hdr.rfcomm_channel_number = scn; 347 record.pse.hdr.l2cap_psm = l2cap_psm; 348 record.pse.hdr.profile_version = version; 349 350 record.pse.supported_features = features; 351 record.pse.supported_repositories = supported_repositories; 352 353 int handle = -1; 354 int ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle); 355 if (ret != BT_STATUS_SUCCESS) { 356 ALOGE("SDP Create record failed: %d", ret); 357 } else { 358 ALOGD("SDP Create record success - handle: %d", handle); 359 } 360 361 if (service_name) env->ReleaseStringUTFChars(name_str, service_name); 362 return handle; 363 } 364 365 static jint sdpCreateOppOpsRecordNative(JNIEnv* env, jobject obj, 366 jstring name_str, jint scn, 367 jint l2cap_psm, jint version, 368 jbyteArray supported_formats_list) { 369 ALOGD("%s", __func__); 370 if (!sBluetoothSdpInterface) return -1; 371 372 bluetooth_sdp_record record = {}; // Must be zero initialized 373 record.ops.hdr.type = SDP_TYPE_OPP_SERVER; 374 375 const char* service_name = NULL; 376 if (name_str != NULL) { 377 service_name = env->GetStringUTFChars(name_str, NULL); 378 record.ops.hdr.service_name = (char*)service_name; 379 record.ops.hdr.service_name_length = strlen(service_name); 380 } else { 381 record.ops.hdr.service_name = NULL; 382 record.ops.hdr.service_name_length = 0; 383 } 384 record.ops.hdr.rfcomm_channel_number = scn; 385 record.ops.hdr.l2cap_psm = l2cap_psm; 386 record.ops.hdr.profile_version = version; 387 388 int formats_list_len = 0; 389 jbyte* formats_list = env->GetByteArrayElements(supported_formats_list, NULL); 390 if (formats_list != NULL) { 391 formats_list_len = env->GetArrayLength(supported_formats_list); 392 if (formats_list_len > SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH) { 393 formats_list_len = SDP_OPP_SUPPORTED_FORMATS_MAX_LENGTH; 394 } 395 memcpy(record.ops.supported_formats_list, formats_list, formats_list_len); 396 } 397 398 record.ops.supported_formats_list_len = formats_list_len; 399 400 int handle = -1; 401 int ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle); 402 if (ret != BT_STATUS_SUCCESS) { 403 ALOGE("SDP Create record failed: %d", ret); 404 } else { 405 ALOGD("SDP Create record success - handle: %d", handle); 406 } 407 408 if (service_name) env->ReleaseStringUTFChars(name_str, service_name); 409 if (formats_list) 410 env->ReleaseByteArrayElements(supported_formats_list, formats_list, 0); 411 return handle; 412 } 413 414 static jint sdpCreateSapsRecordNative(JNIEnv* env, jobject obj, 415 jstring name_str, jint scn, 416 jint version) { 417 ALOGD("%s", __func__); 418 if (!sBluetoothSdpInterface) return -1; 419 420 bluetooth_sdp_record record = {}; // Must be zero initialized 421 record.sap.hdr.type = SDP_TYPE_SAP_SERVER; 422 423 const char* service_name = NULL; 424 if (name_str != NULL) { 425 service_name = env->GetStringUTFChars(name_str, NULL); 426 record.mas.hdr.service_name = (char*)service_name; 427 record.mas.hdr.service_name_length = strlen(service_name); 428 } else { 429 record.mas.hdr.service_name = NULL; 430 record.mas.hdr.service_name_length = 0; 431 } 432 record.mas.hdr.rfcomm_channel_number = scn; 433 record.mas.hdr.profile_version = version; 434 435 int handle = -1; 436 int ret = sBluetoothSdpInterface->create_sdp_record(&record, &handle); 437 if (ret != BT_STATUS_SUCCESS) { 438 ALOGE("SDP Create record failed: %d", ret); 439 } else { 440 ALOGD("SDP Create record success - handle: %d", handle); 441 } 442 443 if (service_name) env->ReleaseStringUTFChars(name_str, service_name); 444 return handle; 445 } 446 447 static jboolean sdpRemoveSdpRecordNative(JNIEnv* env, jobject obj, 448 jint record_id) { 449 ALOGD("%s", __func__); 450 if (!sBluetoothSdpInterface) return false; 451 452 int ret = sBluetoothSdpInterface->remove_sdp_record(record_id); 453 if (ret != BT_STATUS_SUCCESS) { 454 ALOGE("SDP Remove record failed: %d", ret); 455 return false; 456 } 457 458 ALOGD("SDP Remove record success - handle: %d", record_id); 459 return true; 460 } 461 462 static void cleanupNative(JNIEnv* env, jobject object) { 463 const bt_interface_t* btInf = getBluetoothInterface(); 464 465 if (btInf == NULL) { 466 ALOGE("Bluetooth module is not loaded"); 467 return; 468 } 469 470 if (sBluetoothSdpInterface != NULL) { 471 ALOGW("Cleaning up Bluetooth SDP Interface..."); 472 sBluetoothSdpInterface->deinit(); 473 sBluetoothSdpInterface = NULL; 474 } 475 476 if (sCallbacksObj != NULL) { 477 ALOGW("Cleaning up Bluetooth SDP object"); 478 env->DeleteGlobalRef(sCallbacksObj); 479 sCallbacksObj = NULL; 480 } 481 } 482 483 static JNINativeMethod sMethods[] = { 484 /* name, signature, funcPtr */ 485 {"classInitNative", "()V", (void*)classInitNative}, 486 {"initializeNative", "()V", (void*)initializeNative}, 487 {"cleanupNative", "()V", (void*)cleanupNative}, 488 {"sdpSearchNative", "([B[B)Z", (void*)sdpSearchNative}, 489 {"sdpCreateMapMasRecordNative", "(Ljava/lang/String;IIIIII)I", 490 (void*)sdpCreateMapMasRecordNative}, 491 {"sdpCreateMapMnsRecordNative", "(Ljava/lang/String;IIII)I", 492 (void*)sdpCreateMapMnsRecordNative}, 493 {"sdpCreatePbapPseRecordNative", "(Ljava/lang/String;IIIII)I", 494 (void*)sdpCreatePbapPseRecordNative}, 495 {"sdpCreateOppOpsRecordNative", "(Ljava/lang/String;III[B)I", 496 (void*)sdpCreateOppOpsRecordNative}, 497 {"sdpCreateSapsRecordNative", "(Ljava/lang/String;II)I", 498 (void*)sdpCreateSapsRecordNative}, 499 {"sdpRemoveSdpRecordNative", "(I)Z", (void*)sdpRemoveSdpRecordNative}}; 500 501 int register_com_android_bluetooth_sdp(JNIEnv* env) { 502 return jniRegisterNativeMethods(env, "com/android/bluetooth/sdp/SdpManager", 503 sMethods, NELEM(sMethods)); 504 } 505 } 506