com_android_bluetooth_btservice_AdapterService.cpp revision f5f90873574eefe5f50a7b383fcd8fefb961f66c
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 "BluetoothServiceJni" 18#include "com_android_bluetooth.h" 19#include "hardware/bt_sock.h" 20#include "utils/Log.h" 21#include "utils/misc.h" 22#include "cutils/properties.h" 23#include "android_runtime/AndroidRuntime.h" 24#include "android_runtime/Log.h" 25 26#include <string.h> 27#include <pthread.h> 28 29#include <sys/stat.h> 30#include <fcntl.h> 31 32namespace android { 33 34#define ADDITIONAL_NREFS 50 35static jmethodID method_stateChangeCallback; 36static jmethodID method_adapterPropertyChangedCallback; 37static jmethodID method_devicePropertyChangedCallback; 38static jmethodID method_deviceFoundCallback; 39static jmethodID method_pinRequestCallback; 40static jmethodID method_sspRequestCallback; 41static jmethodID method_bondStateChangeCallback; 42static jmethodID method_aclStateChangeCallback; 43static jmethodID method_discoveryStateChangeCallback; 44static jmethodID method_setWakeAlarm; 45static jmethodID method_acquireWakeLock; 46static jmethodID method_releaseWakeLock; 47static jmethodID method_energyInfo; 48 49static const bt_interface_t *sBluetoothInterface = NULL; 50static const btsock_interface_t *sBluetoothSocketInterface = NULL; 51static JNIEnv *callbackEnv = NULL; 52 53static jobject sJniAdapterServiceObj; 54static jobject sJniCallbacksObj; 55static jfieldID sJniCallbacksField; 56 57 58const bt_interface_t* getBluetoothInterface() { 59 return sBluetoothInterface; 60} 61 62JNIEnv* getCallbackEnv() { 63 return callbackEnv; 64} 65 66void checkAndClearExceptionFromCallback(JNIEnv* env, 67 const char* methodName) { 68 if (env->ExceptionCheck()) { 69 ALOGE("An exception was thrown by callback '%s'.", methodName); 70 LOGE_EX(env); 71 env->ExceptionClear(); 72 } 73} 74 75static bool checkCallbackThread() { 76 JNIEnv* env = AndroidRuntime::getJNIEnv(); 77 if (callbackEnv != env || callbackEnv == NULL) { 78 ALOGE("Callback env check fail: env: %p, callback: %p", env, callbackEnv); 79 return false; 80 } 81 return true; 82} 83 84static void adapter_state_change_callback(bt_state_t status) { 85 if (!checkCallbackThread()) { 86 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); 87 return; 88 } 89 ALOGV("%s: Status is: %d", __FUNCTION__, status); 90 91 callbackEnv->CallVoidMethod(sJniCallbacksObj, method_stateChangeCallback, (jint)status); 92 93 checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__); 94} 95 96static int get_properties(int num_properties, bt_property_t *properties, jintArray *types, 97 jobjectArray *props) { 98 jbyteArray propVal; 99 for (int i = 0; i < num_properties; i++) { 100 propVal = callbackEnv->NewByteArray(properties[i].len); 101 if (propVal == NULL) goto Fail; 102 103 callbackEnv->SetByteArrayRegion(propVal, 0, properties[i].len, 104 (jbyte*)properties[i].val); 105 callbackEnv->SetObjectArrayElement(*props, i, propVal); 106 // Delete reference to propVal 107 callbackEnv->DeleteLocalRef(propVal); 108 callbackEnv->SetIntArrayRegion(*types, i, 1, (jint *)&properties[i].type); 109 } 110 return 0; 111Fail: 112 if (propVal) callbackEnv->DeleteLocalRef(propVal); 113 ALOGE("Error while allocation of array in %s", __FUNCTION__); 114 return -1; 115} 116 117static void adapter_properties_callback(bt_status_t status, int num_properties, 118 bt_property_t *properties) { 119 jobjectArray props; 120 jintArray types; 121 jbyteArray val; 122 jclass mclass; 123 124 if (!checkCallbackThread()) { 125 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); 126 return; 127 } 128 129 ALOGV("%s: Status is: %d, Properties: %d", __FUNCTION__, status, num_properties); 130 131 if (status != BT_STATUS_SUCCESS) { 132 ALOGE("%s: Status %d is incorrect", __FUNCTION__, status); 133 return; 134 } 135 136 val = (jbyteArray) callbackEnv->NewByteArray(num_properties); 137 if (val == NULL) { 138 ALOGE("%s: Error allocating byteArray", __FUNCTION__); 139 return; 140 } 141 142 mclass = callbackEnv->GetObjectClass(val); 143 144 /* (BT) Initialize the jobjectArray and jintArray here itself and send the 145 initialized array pointers alone to get_properties */ 146 147 props = callbackEnv->NewObjectArray(num_properties, mclass, 148 NULL); 149 if (props == NULL) { 150 ALOGE("%s: Error allocating object Array for properties", __FUNCTION__); 151 return; 152 } 153 154 types = (jintArray)callbackEnv->NewIntArray(num_properties); 155 156 if (types == NULL) { 157 ALOGE("%s: Error allocating int Array for values", __FUNCTION__); 158 return; 159 } 160 // Delete the reference to val and mclass 161 callbackEnv->DeleteLocalRef(mclass); 162 callbackEnv->DeleteLocalRef(val); 163 164 if (get_properties(num_properties, properties, &types, &props) < 0) { 165 if (props) callbackEnv->DeleteLocalRef(props); 166 if (types) callbackEnv->DeleteLocalRef(types); 167 return; 168 } 169 170 callbackEnv->CallVoidMethod(sJniCallbacksObj, method_adapterPropertyChangedCallback, types, 171 props); 172 checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__); 173 callbackEnv->DeleteLocalRef(props); 174 callbackEnv->DeleteLocalRef(types); 175 return; 176 177} 178 179static void remote_device_properties_callback(bt_status_t status, bt_bdaddr_t *bd_addr, 180 int num_properties, bt_property_t *properties) { 181 if (!checkCallbackThread()) { 182 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); 183 return; 184 } 185 186 ALOGV("%s: Status is: %d, Properties: %d", __FUNCTION__, status, num_properties); 187 188 if (status != BT_STATUS_SUCCESS) { 189 ALOGE("%s: Status %d is incorrect", __FUNCTION__, status); 190 return; 191 } 192 193 callbackEnv->PushLocalFrame(ADDITIONAL_NREFS); 194 195 jobjectArray props; 196 jbyteArray addr; 197 jintArray types; 198 jbyteArray val; 199 jclass mclass; 200 201 val = (jbyteArray) callbackEnv->NewByteArray(num_properties); 202 if (val == NULL) { 203 ALOGE("%s: Error allocating byteArray", __FUNCTION__); 204 return; 205 } 206 207 mclass = callbackEnv->GetObjectClass(val); 208 209 /* Initialize the jobjectArray and jintArray here itself and send the 210 initialized array pointers alone to get_properties */ 211 212 props = callbackEnv->NewObjectArray(num_properties, mclass, 213 NULL); 214 if (props == NULL) { 215 ALOGE("%s: Error allocating object Array for properties", __FUNCTION__); 216 return; 217 } 218 219 types = (jintArray)callbackEnv->NewIntArray(num_properties); 220 221 if (types == NULL) { 222 ALOGE("%s: Error allocating int Array for values", __FUNCTION__); 223 return; 224 } 225 // Delete the reference to val and mclass 226 callbackEnv->DeleteLocalRef(mclass); 227 callbackEnv->DeleteLocalRef(val); 228 229 addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 230 if (addr == NULL) goto Fail; 231 if (addr) callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr); 232 233 if (get_properties(num_properties, properties, &types, &props) < 0) { 234 if (props) callbackEnv->DeleteLocalRef(props); 235 if (types) callbackEnv->DeleteLocalRef(types); 236 callbackEnv->PopLocalFrame(NULL); 237 return; 238 } 239 240 callbackEnv->CallVoidMethod(sJniCallbacksObj, method_devicePropertyChangedCallback, addr, 241 types, props); 242 checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__); 243 callbackEnv->DeleteLocalRef(props); 244 callbackEnv->DeleteLocalRef(types); 245 callbackEnv->DeleteLocalRef(addr); 246 callbackEnv->PopLocalFrame(NULL); 247 return; 248 249Fail: 250 ALOGE("Error while allocation byte array in %s", __FUNCTION__); 251} 252 253 254static void device_found_callback(int num_properties, bt_property_t *properties) { 255 jbyteArray addr = NULL; 256 int addr_index; 257 258 for (int i = 0; i < num_properties; i++) { 259 if (properties[i].type == BT_PROPERTY_BDADDR) { 260 addr = callbackEnv->NewByteArray(properties[i].len); 261 if (addr) { 262 callbackEnv->SetByteArrayRegion(addr, 0, properties[i].len, 263 (jbyte*)properties[i].val); 264 addr_index = i; 265 } else { 266 ALOGE("Address is NULL (unable to allocate) in %s", __FUNCTION__); 267 return; 268 } 269 } 270 } 271 if (addr == NULL) { 272 ALOGE("Address is NULL in %s", __FUNCTION__); 273 return; 274 } 275 276 ALOGV("%s: Properties: %d, Address: %s", __FUNCTION__, num_properties, 277 (const char *)properties[addr_index].val); 278 279 remote_device_properties_callback(BT_STATUS_SUCCESS, (bt_bdaddr_t *)properties[addr_index].val, 280 num_properties, properties); 281 282 callbackEnv->CallVoidMethod(sJniCallbacksObj, method_deviceFoundCallback, addr); 283 checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__); 284 callbackEnv->DeleteLocalRef(addr); 285} 286 287static void bond_state_changed_callback(bt_status_t status, bt_bdaddr_t *bd_addr, 288 bt_bond_state_t state) { 289 jbyteArray addr; 290 int i; 291 if (!checkCallbackThread()) { 292 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); 293 return; 294 } 295 if (!bd_addr) { 296 ALOGE("Address is null in %s", __FUNCTION__); 297 return; 298 } 299 addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 300 if (addr == NULL) { 301 ALOGE("Address allocation failed in %s", __FUNCTION__); 302 return; 303 } 304 callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *)bd_addr); 305 306 callbackEnv->CallVoidMethod(sJniCallbacksObj, method_bondStateChangeCallback, (jint) status, 307 addr, (jint)state); 308 checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__); 309 callbackEnv->DeleteLocalRef(addr); 310} 311 312static void acl_state_changed_callback(bt_status_t status, bt_bdaddr_t *bd_addr, 313 bt_acl_state_t state) 314{ 315 jbyteArray addr; 316 int i; 317 if (!checkCallbackThread()) { 318 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); 319 return; 320 } 321 if (!bd_addr) { 322 ALOGE("Address is null in %s", __FUNCTION__); 323 return; 324 } 325 addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 326 if (addr == NULL) { 327 ALOGE("Address allocation failed in %s", __FUNCTION__); 328 return; 329 } 330 callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *)bd_addr); 331 332 callbackEnv->CallVoidMethod(sJniCallbacksObj, method_aclStateChangeCallback, (jint) status, 333 addr, (jint)state); 334 checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__); 335 callbackEnv->DeleteLocalRef(addr); 336} 337 338static void discovery_state_changed_callback(bt_discovery_state_t state) { 339 jbyteArray addr; 340 if (!checkCallbackThread()) { 341 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); 342 return; 343 } 344 345 ALOGV("%s: DiscoveryState:%d ", __FUNCTION__, state); 346 347 callbackEnv->CallVoidMethod(sJniCallbacksObj, method_discoveryStateChangeCallback, 348 (jint)state); 349 350 checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__); 351} 352 353static void pin_request_callback(bt_bdaddr_t *bd_addr, bt_bdname_t *bdname, uint32_t cod) { 354 jbyteArray addr, devname; 355 if (!checkCallbackThread()) { 356 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); 357 return; 358 } 359 if (!bd_addr) { 360 ALOGE("Address is null in %s", __FUNCTION__); 361 return; 362 } 363 364 addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 365 if (addr == NULL) goto Fail; 366 callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr); 367 368 devname = callbackEnv->NewByteArray(sizeof(bt_bdname_t)); 369 if (devname == NULL) goto Fail; 370 371 callbackEnv->SetByteArrayRegion(devname, 0, sizeof(bt_bdname_t), (jbyte*)bdname); 372 373 callbackEnv->CallVoidMethod(sJniCallbacksObj, method_pinRequestCallback, addr, devname, cod); 374 375 checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__); 376 callbackEnv->DeleteLocalRef(addr); 377 callbackEnv->DeleteLocalRef(devname); 378 return; 379 380Fail: 381 if (addr) callbackEnv->DeleteLocalRef(addr); 382 if (devname) callbackEnv->DeleteLocalRef(devname); 383 ALOGE("Error while allocating in: %s", __FUNCTION__); 384} 385 386static void ssp_request_callback(bt_bdaddr_t *bd_addr, bt_bdname_t *bdname, uint32_t cod, 387 bt_ssp_variant_t pairing_variant, uint32_t pass_key) { 388 jbyteArray addr, devname; 389 if (!checkCallbackThread()) { 390 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); 391 return; 392 } 393 if (!bd_addr) { 394 ALOGE("Address is null in %s", __FUNCTION__); 395 return; 396 } 397 398 addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 399 if (addr == NULL) goto Fail; 400 callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *)bd_addr); 401 402 devname = callbackEnv->NewByteArray(sizeof(bt_bdname_t)); 403 if (devname == NULL) goto Fail; 404 callbackEnv->SetByteArrayRegion(devname, 0, sizeof(bt_bdname_t), (jbyte*)bdname); 405 406 callbackEnv->CallVoidMethod(sJniCallbacksObj, method_sspRequestCallback, addr, devname, cod, 407 (jint) pairing_variant, pass_key); 408 409 checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__); 410 callbackEnv->DeleteLocalRef(addr); 411 callbackEnv->DeleteLocalRef(devname); 412 return; 413 414Fail: 415 if (addr) callbackEnv->DeleteLocalRef(addr); 416 if (devname) callbackEnv->DeleteLocalRef(devname); 417 418 ALOGE("Error while allocating in: %s", __FUNCTION__); 419} 420 421static void callback_thread_event(bt_cb_thread_evt event) { 422 JavaVM* vm = AndroidRuntime::getJavaVM(); 423 if (event == ASSOCIATE_JVM) { 424 JavaVMAttachArgs args; 425 char name[] = "BT Service Callback Thread"; 426 args.version = JNI_VERSION_1_6; 427 args.name = name; 428 args.group = NULL; 429 vm->AttachCurrentThread(&callbackEnv, &args); 430 ALOGV("Callback thread attached: %p", callbackEnv); 431 } else if (event == DISASSOCIATE_JVM) { 432 if (!checkCallbackThread()) { 433 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); 434 return; 435 } 436 vm->DetachCurrentThread(); 437 } 438} 439 440static void dut_mode_recv_callback (uint16_t opcode, uint8_t *buf, uint8_t len) { 441 442} 443static void le_test_mode_recv_callback (bt_status_t status, uint16_t packet_count) { 444 445 ALOGV("%s: status:%d packet_count:%d ", __FUNCTION__, status, packet_count); 446} 447 448static void energy_info_recv_callback(bt_activity_energy_info *p_energy_info) 449{ 450 if (!checkCallbackThread()) { 451 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); 452 return; 453 } 454 455 callbackEnv->CallVoidMethod(sJniAdapterServiceObj, method_energyInfo, p_energy_info->status, 456 p_energy_info->ctrl_state, p_energy_info->tx_time, p_energy_info->rx_time, 457 p_energy_info->idle_time, p_energy_info->energy_used); 458 459 checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__); 460} 461 462static bt_callbacks_t sBluetoothCallbacks = { 463 sizeof(sBluetoothCallbacks), 464 adapter_state_change_callback, 465 adapter_properties_callback, 466 remote_device_properties_callback, 467 device_found_callback, 468 discovery_state_changed_callback, 469 pin_request_callback, 470 ssp_request_callback, 471 bond_state_changed_callback, 472 acl_state_changed_callback, 473 callback_thread_event, 474 dut_mode_recv_callback, 475 le_test_mode_recv_callback, 476 energy_info_recv_callback 477}; 478 479// The callback to call when the wake alarm fires. 480static alarm_cb sAlarmCallback; 481 482// The data to pass to the wake alarm callback. 483static void *sAlarmCallbackData; 484 485static JavaVMAttachArgs sAttachArgs = { 486 .version = JNI_VERSION_1_6, 487 .name = "bluedroid wake/alarm thread", 488 .group = NULL 489}; 490 491static bool set_wake_alarm_callout(uint64_t delay_millis, bool should_wake, 492 alarm_cb cb, void *data) { 493 JNIEnv *env; 494 JavaVM *vm = AndroidRuntime::getJavaVM(); 495 jint status = vm->GetEnv((void **)&env, JNI_VERSION_1_6); 496 497 if (status != JNI_OK && status != JNI_EDETACHED) { 498 ALOGE("%s unable to get environment for JNI call", __func__); 499 return false; 500 } 501 502 if (status == JNI_EDETACHED && vm->AttachCurrentThread(&env, &sAttachArgs) != 0) { 503 ALOGE("%s unable to attach thread to VM", __func__); 504 return false; 505 } 506 507 sAlarmCallback = cb; 508 sAlarmCallbackData = data; 509 510 jboolean jshould_wake = should_wake ? JNI_TRUE : JNI_FALSE; 511 jboolean ret = env->CallBooleanMethod(sJniAdapterServiceObj, method_setWakeAlarm, 512 (jlong)delay_millis, jshould_wake); 513 if (!ret) { 514 sAlarmCallback = NULL; 515 sAlarmCallbackData = NULL; 516 } 517 518 if (status == JNI_EDETACHED) { 519 vm->DetachCurrentThread(); 520 } 521 522 return !!ret; 523} 524 525static int acquire_wake_lock_callout(const char *lock_name) { 526 JNIEnv *env; 527 JavaVM *vm = AndroidRuntime::getJavaVM(); 528 jint status = vm->GetEnv((void **)&env, JNI_VERSION_1_6); 529 if (status != JNI_OK && status != JNI_EDETACHED) { 530 ALOGE("%s unable to get environment for JNI call", __func__); 531 return BT_STATUS_FAIL; 532 } 533 if (status == JNI_EDETACHED && vm->AttachCurrentThread(&env, &sAttachArgs) != 0) { 534 ALOGE("%s unable to attach thread to VM", __func__); 535 return BT_STATUS_FAIL; 536 } 537 538 jboolean ret = JNI_FALSE; 539 jstring lock_name_jni = env->NewStringUTF(lock_name); 540 if (lock_name_jni) { 541 ret = env->CallBooleanMethod(sJniAdapterServiceObj, method_acquireWakeLock, lock_name_jni); 542 env->DeleteLocalRef(lock_name_jni); 543 } else { 544 ALOGE("%s unable to allocate string: %s", __func__, lock_name); 545 } 546 547 if (status == JNI_EDETACHED) { 548 vm->DetachCurrentThread(); 549 } 550 551 return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; 552} 553 554static int release_wake_lock_callout(const char *lock_name) { 555 JNIEnv *env; 556 JavaVM *vm = AndroidRuntime::getJavaVM(); 557 jint status = vm->GetEnv((void **)&env, JNI_VERSION_1_6); 558 559 if (status != JNI_OK && status != JNI_EDETACHED) { 560 ALOGE("%s unable to get environment for JNI call", __func__); 561 return BT_STATUS_FAIL; 562 } 563 if (status == JNI_EDETACHED && vm->AttachCurrentThread(&env, &sAttachArgs) != 0) { 564 ALOGE("%s unable to attach thread to VM", __func__); 565 return BT_STATUS_FAIL; 566 } 567 jboolean ret = JNI_FALSE; 568 jstring lock_name_jni = env->NewStringUTF(lock_name); 569 if (lock_name_jni) { 570 ret = env->CallBooleanMethod(sJniAdapterServiceObj, method_releaseWakeLock, lock_name_jni); 571 env->DeleteLocalRef(lock_name_jni); 572 } else { 573 ALOGE("%s unable to allocate string: %s", __func__, lock_name); 574 } 575 if (status == JNI_EDETACHED) { 576 vm->DetachCurrentThread(); 577 } 578 return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; 579} 580 581// Called by Java code when alarm is fired. A wake lock is held by the caller 582// over the duration of this callback. 583static void alarmFiredNative(JNIEnv *env, jobject obj) { 584 if (sAlarmCallback) { 585 sAlarmCallback(sAlarmCallbackData); 586 } else { 587 ALOGE("%s() - Alarm fired with callback not set!", __FUNCTION__); 588 } 589} 590 591static bt_os_callouts_t sBluetoothOsCallouts = { 592 sizeof(sBluetoothOsCallouts), 593 set_wake_alarm_callout, 594 acquire_wake_lock_callout, 595 release_wake_lock_callout, 596}; 597 598 599 600static void classInitNative(JNIEnv* env, jclass clazz) { 601 int err; 602 hw_module_t* module; 603 604 jclass jniCallbackClass = 605 env->FindClass("com/android/bluetooth/btservice/JniCallbacks"); 606 sJniCallbacksField = env->GetFieldID(clazz, "mJniCallbacks", 607 "Lcom/android/bluetooth/btservice/JniCallbacks;"); 608 609 method_stateChangeCallback = env->GetMethodID(jniCallbackClass, "stateChangeCallback", "(I)V"); 610 611 method_adapterPropertyChangedCallback = env->GetMethodID(jniCallbackClass, 612 "adapterPropertyChangedCallback", 613 "([I[[B)V"); 614 method_discoveryStateChangeCallback = env->GetMethodID(jniCallbackClass, 615 "discoveryStateChangeCallback", "(I)V"); 616 617 method_devicePropertyChangedCallback = env->GetMethodID(jniCallbackClass, 618 "devicePropertyChangedCallback", 619 "([B[I[[B)V"); 620 method_deviceFoundCallback = env->GetMethodID(jniCallbackClass, "deviceFoundCallback", "([B)V"); 621 method_pinRequestCallback = env->GetMethodID(jniCallbackClass, "pinRequestCallback", 622 "([B[BI)V"); 623 method_sspRequestCallback = env->GetMethodID(jniCallbackClass, "sspRequestCallback", 624 "([B[BIII)V"); 625 626 method_bondStateChangeCallback = env->GetMethodID(jniCallbackClass, 627 "bondStateChangeCallback", "(I[BI)V"); 628 629 method_aclStateChangeCallback = env->GetMethodID(jniCallbackClass, 630 "aclStateChangeCallback", "(I[BI)V"); 631 632 method_setWakeAlarm = env->GetMethodID(clazz, "setWakeAlarm", "(JZ)Z"); 633 method_acquireWakeLock = env->GetMethodID(clazz, "acquireWakeLock", "(Ljava/lang/String;)Z"); 634 method_releaseWakeLock = env->GetMethodID(clazz, "releaseWakeLock", "(Ljava/lang/String;)Z"); 635 method_energyInfo = env->GetMethodID(clazz, "energyInfoCallback", "(IIJJJJ)V"); 636 637 char value[PROPERTY_VALUE_MAX]; 638 property_get("bluetooth.mock_stack", value, ""); 639 640 const char *id = (strcmp(value, "1")? BT_STACK_MODULE_ID : BT_STACK_TEST_MODULE_ID); 641 642 err = hw_get_module(id, (hw_module_t const**)&module); 643 644 if (err == 0) { 645 hw_device_t* abstraction; 646 err = module->methods->open(module, id, &abstraction); 647 if (err == 0) { 648 bluetooth_module_t* btStack = (bluetooth_module_t *)abstraction; 649 sBluetoothInterface = btStack->get_bluetooth_interface(); 650 } else { 651 ALOGE("Error while opening Bluetooth library"); 652 } 653 } else { 654 ALOGE("No Bluetooth Library found"); 655 } 656} 657 658static bool initNative(JNIEnv* env, jobject obj) { 659 ALOGV("%s:",__FUNCTION__); 660 661 sJniAdapterServiceObj = env->NewGlobalRef(obj); 662 sJniCallbacksObj = env->NewGlobalRef(env->GetObjectField(obj, sJniCallbacksField)); 663 664 if (sBluetoothInterface) { 665 int ret = sBluetoothInterface->init(&sBluetoothCallbacks); 666 if (ret != BT_STATUS_SUCCESS) { 667 ALOGE("Error while setting the callbacks: %d\n", ret); 668 sBluetoothInterface = NULL; 669 return JNI_FALSE; 670 } 671 ret = sBluetoothInterface->set_os_callouts(&sBluetoothOsCallouts); 672 if (ret != BT_STATUS_SUCCESS) { 673 ALOGE("Error while setting Bluetooth callouts: %d\n", ret); 674 sBluetoothInterface->cleanup(); 675 sBluetoothInterface = NULL; 676 return JNI_FALSE; 677 } 678 679 if ( (sBluetoothSocketInterface = (btsock_interface_t *) 680 sBluetoothInterface->get_profile_interface(BT_PROFILE_SOCKETS_ID)) == NULL) { 681 ALOGE("Error getting socket interface"); 682 } 683 684 return JNI_TRUE; 685 } 686 return JNI_FALSE; 687} 688 689static bool cleanupNative(JNIEnv *env, jobject obj) { 690 ALOGV("%s:",__FUNCTION__); 691 692 jboolean result = JNI_FALSE; 693 if (!sBluetoothInterface) return result; 694 695 sBluetoothInterface->cleanup(); 696 ALOGI("%s: return from cleanup",__FUNCTION__); 697 698 env->DeleteGlobalRef(sJniCallbacksObj); 699 env->DeleteGlobalRef(sJniAdapterServiceObj); 700 return JNI_TRUE; 701} 702 703static jboolean enableNative(JNIEnv* env, jobject obj) { 704 ALOGV("%s:",__FUNCTION__); 705 706 jboolean result = JNI_FALSE; 707 if (!sBluetoothInterface) return result; 708 709 int ret = sBluetoothInterface->enable(); 710 result = (ret == BT_STATUS_SUCCESS || ret == BT_STATUS_DONE) ? JNI_TRUE : JNI_FALSE; 711 return result; 712} 713 714static jboolean disableNative(JNIEnv* env, jobject obj) { 715 ALOGV("%s:",__FUNCTION__); 716 717 jboolean result = JNI_FALSE; 718 if (!sBluetoothInterface) return result; 719 720 int ret = sBluetoothInterface->disable(); 721 /* Retrun JNI_FALSE only when BTIF explicitly reports 722 BT_STATUS_FAIL. It is fine for the BT_STATUS_NOT_READY 723 case which indicates that stack had not been enabled. 724 */ 725 result = (ret == BT_STATUS_FAIL) ? JNI_FALSE : JNI_TRUE; 726 return result; 727} 728 729static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) { 730 ALOGV("%s:",__FUNCTION__); 731 732 jboolean result = JNI_FALSE; 733 if (!sBluetoothInterface) return result; 734 735 int ret = sBluetoothInterface->start_discovery(); 736 result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 737 return result; 738} 739 740static jboolean cancelDiscoveryNative(JNIEnv* env, jobject obj) { 741 ALOGV("%s:",__FUNCTION__); 742 743 jboolean result = JNI_FALSE; 744 if (!sBluetoothInterface) return result; 745 746 int ret = sBluetoothInterface->cancel_discovery(); 747 result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 748 return result; 749} 750 751static jboolean createBondNative(JNIEnv* env, jobject obj, jbyteArray address, jint transport) { 752 ALOGV("%s:",__FUNCTION__); 753 754 jbyte *addr; 755 jboolean result = JNI_FALSE; 756 757 if (!sBluetoothInterface) return result; 758 759 addr = env->GetByteArrayElements(address, NULL); 760 if (addr == NULL) { 761 jniThrowIOException(env, EINVAL); 762 return result; 763 } 764 765 int ret = sBluetoothInterface->create_bond((bt_bdaddr_t *)addr, transport); 766 env->ReleaseByteArrayElements(address, addr, 0); 767 result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 768 769 return result; 770} 771 772static jboolean removeBondNative(JNIEnv* env, jobject obj, jbyteArray address) { 773 ALOGV("%s:",__FUNCTION__); 774 775 jbyte *addr; 776 jboolean result; 777 if (!sBluetoothInterface) return JNI_FALSE; 778 779 addr = env->GetByteArrayElements(address, NULL); 780 if (addr == NULL) { 781 jniThrowIOException(env, EINVAL); 782 return JNI_FALSE; 783 } 784 785 int ret = sBluetoothInterface->remove_bond((bt_bdaddr_t *)addr); 786 env->ReleaseByteArrayElements(address, addr, 0); 787 result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 788 789 return result; 790} 791 792static jboolean cancelBondNative(JNIEnv* env, jobject obj, jbyteArray address) { 793 ALOGV("%s:",__FUNCTION__); 794 795 jbyte *addr; 796 jboolean result; 797 if (!sBluetoothInterface) return JNI_FALSE; 798 799 addr = env->GetByteArrayElements(address, NULL); 800 if (addr == NULL) { 801 jniThrowIOException(env, EINVAL); 802 return JNI_FALSE; 803 } 804 805 int ret = sBluetoothInterface->cancel_bond((bt_bdaddr_t *)addr); 806 env->ReleaseByteArrayElements(address, addr, 0); 807 result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 808 809 return result; 810} 811 812static int getConnectionStateNative(JNIEnv* env, jobject obj, jbyteArray address) { 813 ALOGV("%s:",__FUNCTION__); 814 if (!sBluetoothInterface) return JNI_FALSE; 815 816 jbyte *addr = env->GetByteArrayElements(address, NULL); 817 if (addr == NULL) { 818 jniThrowIOException(env, EINVAL); 819 return JNI_FALSE; 820 } 821 822 int ret = sBluetoothInterface->get_connection_state((bt_bdaddr_t *)addr); 823 env->ReleaseByteArrayElements(address, addr, 0); 824 825 return ret; 826} 827 828static jboolean pinReplyNative(JNIEnv *env, jobject obj, jbyteArray address, jboolean accept, 829 jint len, jbyteArray pinArray) { 830 ALOGV("%s:",__FUNCTION__); 831 832 jbyte *addr, *pinPtr = NULL; 833 jboolean result = JNI_FALSE; 834 if (!sBluetoothInterface) return result; 835 836 addr = env->GetByteArrayElements(address, NULL); 837 if (addr == NULL) { 838 jniThrowIOException(env, EINVAL); 839 return result; 840 } 841 842 if (accept) { 843 pinPtr = env->GetByteArrayElements(pinArray, NULL); 844 if (pinPtr == NULL) { 845 jniThrowIOException(env, EINVAL); 846 env->ReleaseByteArrayElements(address, addr, 0); 847 return result; 848 } 849 } 850 851 int ret = sBluetoothInterface->pin_reply((bt_bdaddr_t*)addr, accept, len, 852 (bt_pin_code_t *) pinPtr); 853 env->ReleaseByteArrayElements(address, addr, 0); 854 env->ReleaseByteArrayElements(pinArray, pinPtr, 0); 855 result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 856 857 return result; 858} 859 860static jboolean sspReplyNative(JNIEnv *env, jobject obj, jbyteArray address, 861 jint type, jboolean accept, jint passkey) { 862 ALOGV("%s:",__FUNCTION__); 863 864 jbyte *addr; 865 jboolean result = JNI_FALSE; 866 if (!sBluetoothInterface) return result; 867 868 addr = env->GetByteArrayElements(address, NULL); 869 if (addr == NULL) { 870 jniThrowIOException(env, EINVAL); 871 return result; 872 } 873 874 int ret = sBluetoothInterface->ssp_reply((bt_bdaddr_t *)addr, 875 (bt_ssp_variant_t) type, accept, passkey); 876 env->ReleaseByteArrayElements(address, addr, 0); 877 result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 878 879 return result; 880} 881 882static jboolean setAdapterPropertyNative(JNIEnv *env, jobject obj, jint type, jbyteArray value) { 883 ALOGV("%s:",__FUNCTION__); 884 885 jbyte *val; 886 jboolean result = JNI_FALSE; 887 if (!sBluetoothInterface) return result; 888 889 val = env->GetByteArrayElements(value, NULL); 890 bt_property_t prop; 891 prop.type = (bt_property_type_t) type; 892 prop.len = env->GetArrayLength(value); 893 prop.val = val; 894 895 int ret = sBluetoothInterface->set_adapter_property(&prop); 896 env->ReleaseByteArrayElements(value, val, 0); 897 result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 898 899 return result; 900} 901 902static jboolean getAdapterPropertiesNative(JNIEnv *env, jobject obj) { 903 ALOGV("%s:",__FUNCTION__); 904 905 jboolean result = JNI_FALSE; 906 if (!sBluetoothInterface) return result; 907 908 int ret = sBluetoothInterface->get_adapter_properties(); 909 result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 910 911 return result; 912} 913 914static jboolean getAdapterPropertyNative(JNIEnv *env, jobject obj, jint type) { 915 ALOGV("%s:",__FUNCTION__); 916 917 jboolean result = JNI_FALSE; 918 if (!sBluetoothInterface) return result; 919 920 int ret = sBluetoothInterface->get_adapter_property((bt_property_type_t) type); 921 result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 922 923 return result; 924} 925 926static jboolean getDevicePropertyNative(JNIEnv *env, jobject obj, jbyteArray address, jint type) { 927 ALOGV("%s:",__FUNCTION__); 928 929 jbyte *addr = NULL; 930 jboolean result = JNI_FALSE; 931 if (!sBluetoothInterface) return result; 932 933 addr = env->GetByteArrayElements(address, NULL); 934 if (addr == NULL) { 935 jniThrowIOException(env, EINVAL); 936 return result; 937 } 938 939 int ret = sBluetoothInterface->get_remote_device_property((bt_bdaddr_t *)addr, 940 (bt_property_type_t) type); 941 env->ReleaseByteArrayElements(address, addr, 0); 942 result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 943 944 return result; 945} 946 947static jboolean setDevicePropertyNative(JNIEnv *env, jobject obj, jbyteArray address, 948 jint type, jbyteArray value) { 949 ALOGV("%s:",__FUNCTION__); 950 951 jbyte *val, *addr; 952 jboolean result = JNI_FALSE; 953 if (!sBluetoothInterface) return result; 954 955 val = env->GetByteArrayElements(value, NULL); 956 if (val == NULL) { 957 jniThrowIOException(env, EINVAL); 958 return result; 959 } 960 961 addr = env->GetByteArrayElements(address, NULL); 962 if (addr == NULL) { 963 env->ReleaseByteArrayElements(value, val, 0); 964 jniThrowIOException(env, EINVAL); 965 return result; 966 } 967 968 969 bt_property_t prop; 970 prop.type = (bt_property_type_t) type; 971 prop.len = env->GetArrayLength(value); 972 prop.val = val; 973 974 int ret = sBluetoothInterface->set_remote_device_property((bt_bdaddr_t *)addr, &prop); 975 env->ReleaseByteArrayElements(value, val, 0); 976 env->ReleaseByteArrayElements(address, addr, 0); 977 978 result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 979 980 return result; 981} 982 983static jboolean getRemoteServicesNative(JNIEnv *env, jobject obj, jbyteArray address) { 984 ALOGV("%s:",__FUNCTION__); 985 986 jbyte *addr = NULL; 987 jboolean result = JNI_FALSE; 988 if (!sBluetoothInterface) return result; 989 990 addr = env->GetByteArrayElements(address, NULL); 991 if (addr == NULL) { 992 jniThrowIOException(env, EINVAL); 993 return result; 994 } 995 996 int ret = sBluetoothInterface->get_remote_services((bt_bdaddr_t *)addr); 997 env->ReleaseByteArrayElements(address, addr, 0); 998 result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 999 return result; 1000} 1001 1002static int connectSocketNative(JNIEnv *env, jobject object, jbyteArray address, jint type, 1003 jbyteArray uuidObj, jint channel, jint flag) { 1004 jbyte *addr = NULL, *uuid = NULL; 1005 int socket_fd; 1006 bt_status_t status; 1007 1008 if (!sBluetoothSocketInterface) return -1; 1009 1010 addr = env->GetByteArrayElements(address, NULL); 1011 if (!addr) { 1012 ALOGE("failed to get Bluetooth device address"); 1013 goto Fail; 1014 } 1015 1016 if(uuidObj != NULL) { 1017 uuid = env->GetByteArrayElements(uuidObj, NULL); 1018 if (!uuid) { 1019 ALOGE("failed to get uuid"); 1020 goto Fail; 1021 } 1022 } 1023 1024 if ( (status = sBluetoothSocketInterface->connect((bt_bdaddr_t *) addr, (btsock_type_t) type, 1025 (const uint8_t*) uuid, channel, &socket_fd, flag)) != BT_STATUS_SUCCESS) { 1026 ALOGE("Socket connection failed: %d", status); 1027 goto Fail; 1028 } 1029 1030 1031 if (socket_fd < 0) { 1032 ALOGE("Fail to create file descriptor on socket fd"); 1033 goto Fail; 1034 } 1035 env->ReleaseByteArrayElements(address, addr, 0); 1036 env->ReleaseByteArrayElements(uuidObj, uuid, 0); 1037 return socket_fd; 1038 1039Fail: 1040 if (addr) env->ReleaseByteArrayElements(address, addr, 0); 1041 if (uuid) env->ReleaseByteArrayElements(uuidObj, uuid, 0); 1042 1043 return -1; 1044} 1045 1046static int createSocketChannelNative(JNIEnv *env, jobject object, jint type, 1047 jstring name_str, jbyteArray uuidObj, 1048 jint channel, jint flag) { 1049 const char *service_name = NULL; 1050 jbyte *uuid = NULL; 1051 int socket_fd; 1052 bt_status_t status; 1053 1054 if (!sBluetoothSocketInterface) return -1; 1055 1056 ALOGV("%s: SOCK FLAG = %x", __FUNCTION__, flag); 1057 1058 if(name_str != NULL) { 1059 service_name = env->GetStringUTFChars(name_str, NULL); 1060 } 1061 1062 if(uuidObj != NULL) { 1063 uuid = env->GetByteArrayElements(uuidObj, NULL); 1064 if (!uuid) { 1065 ALOGE("failed to get uuid"); 1066 goto Fail; 1067 } 1068 } 1069 if ( (status = sBluetoothSocketInterface->listen((btsock_type_t) type, service_name, 1070 (const uint8_t*) uuid, channel, &socket_fd, flag)) != BT_STATUS_SUCCESS) { 1071 ALOGE("Socket listen failed: %d", status); 1072 goto Fail; 1073 } 1074 1075 if (socket_fd < 0) { 1076 ALOGE("Fail to creat file descriptor on socket fd"); 1077 goto Fail; 1078 } 1079 if (service_name) env->ReleaseStringUTFChars(name_str, service_name); 1080 if (uuid) env->ReleaseByteArrayElements(uuidObj, uuid, 0); 1081 return socket_fd; 1082 1083Fail: 1084 if (service_name) env->ReleaseStringUTFChars(name_str, service_name); 1085 if (uuid) env->ReleaseByteArrayElements(uuidObj, uuid, 0); 1086 return -1; 1087} 1088 1089static jboolean configHciSnoopLogNative(JNIEnv* env, jobject obj, jboolean enable) { 1090 ALOGV("%s:",__FUNCTION__); 1091 1092 jboolean result = JNI_FALSE; 1093 1094 if (!sBluetoothInterface) return result; 1095 1096 int ret = sBluetoothInterface->config_hci_snoop_log(enable); 1097 1098 result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 1099 1100 return result; 1101} 1102 1103static int readEnergyInfo() 1104{ 1105 ALOGV("%s:",__FUNCTION__); 1106 jboolean result = JNI_FALSE; 1107 if (!sBluetoothInterface) return result; 1108 int ret = sBluetoothInterface->read_energy_info(); 1109 result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 1110 return result; 1111} 1112 1113static void dumpNative(JNIEnv *env, jobject obj, jobject fdObj) 1114{ 1115 ALOGV("%s()", __FUNCTION__); 1116 if (!sBluetoothInterface) return; 1117 1118 int fd = jniGetFDFromFileDescriptor(env, fdObj); 1119 if (fd < 0) return; 1120 1121 sBluetoothInterface->dump(fd); 1122} 1123 1124static JNINativeMethod sMethods[] = { 1125 /* name, signature, funcPtr */ 1126 {"classInitNative", "()V", (void *) classInitNative}, 1127 {"initNative", "()Z", (void *) initNative}, 1128 {"cleanupNative", "()V", (void*) cleanupNative}, 1129 {"enableNative", "()Z", (void*) enableNative}, 1130 {"disableNative", "()Z", (void*) disableNative}, 1131 {"setAdapterPropertyNative", "(I[B)Z", (void*) setAdapterPropertyNative}, 1132 {"getAdapterPropertiesNative", "()Z", (void*) getAdapterPropertiesNative}, 1133 {"getAdapterPropertyNative", "(I)Z", (void*) getAdapterPropertyNative}, 1134 {"getDevicePropertyNative", "([BI)Z", (void*) getDevicePropertyNative}, 1135 {"setDevicePropertyNative", "([BI[B)Z", (void*) setDevicePropertyNative}, 1136 {"startDiscoveryNative", "()Z", (void*) startDiscoveryNative}, 1137 {"cancelDiscoveryNative", "()Z", (void*) cancelDiscoveryNative}, 1138 {"createBondNative", "([BI)Z", (void*) createBondNative}, 1139 {"removeBondNative", "([B)Z", (void*) removeBondNative}, 1140 {"cancelBondNative", "([B)Z", (void*) cancelBondNative}, 1141 {"getConnectionStateNative", "([B)I", (void*) getConnectionStateNative}, 1142 {"pinReplyNative", "([BZI[B)Z", (void*) pinReplyNative}, 1143 {"sspReplyNative", "([BIZI)Z", (void*) sspReplyNative}, 1144 {"getRemoteServicesNative", "([B)Z", (void*) getRemoteServicesNative}, 1145 {"connectSocketNative", "([BI[BII)I", (void*) connectSocketNative}, 1146 {"createSocketChannelNative", "(ILjava/lang/String;[BII)I", 1147 (void*) createSocketChannelNative}, 1148 {"configHciSnoopLogNative", "(Z)Z", (void*) configHciSnoopLogNative}, 1149 {"alarmFiredNative", "()V", (void *) alarmFiredNative}, 1150 {"readEnergyInfo", "()I", (void*) readEnergyInfo}, 1151 {"dumpNative", "(Ljava/io/FileDescriptor;)V", (void*) dumpNative}, 1152}; 1153 1154int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env) 1155{ 1156 return jniRegisterNativeMethods(env, "com/android/bluetooth/btservice/AdapterService", 1157 sMethods, NELEM(sMethods)); 1158} 1159 1160} /* namespace android */ 1161 1162 1163/* 1164 * JNI Initialization 1165 */ 1166jint JNI_OnLoad(JavaVM *jvm, void *reserved) 1167{ 1168 JNIEnv *e; 1169 int status; 1170 1171 ALOGV("Bluetooth Adapter Service : loading JNI\n"); 1172 1173 // Check JNI version 1174 if (jvm->GetEnv((void **)&e, JNI_VERSION_1_6)) { 1175 ALOGE("JNI version mismatch error"); 1176 return JNI_ERR; 1177 } 1178 1179 if ((status = android::register_com_android_bluetooth_btservice_AdapterService(e)) < 0) { 1180 ALOGE("jni adapter service registration failure, status: %d", status); 1181 return JNI_ERR; 1182 } 1183 1184 if ((status = android::register_com_android_bluetooth_hfp(e)) < 0) { 1185 ALOGE("jni hfp registration failure, status: %d", status); 1186 return JNI_ERR; 1187 } 1188 1189 if ((status = android::register_com_android_bluetooth_hfpclient(e)) < 0) { 1190 ALOGE("jni hfp client registration failure, status: %d", status); 1191 return JNI_ERR; 1192 } 1193 1194 if ((status = android::register_com_android_bluetooth_a2dp(e)) < 0) { 1195 ALOGE("jni a2dp source registration failure: %d", status); 1196 return JNI_ERR; 1197 } 1198 1199 if ((status = android::register_com_android_bluetooth_a2dp_sink(e)) < 0) { 1200 ALOGE("jni a2dp sink registration failure: %d", status); 1201 return JNI_ERR; 1202 } 1203 1204 if ((status = android::register_com_android_bluetooth_avrcp(e)) < 0) { 1205 ALOGE("jni avrcp target registration failure: %d", status); 1206 return JNI_ERR; 1207 } 1208 1209 if ((status = android::register_com_android_bluetooth_avrcp_controller(e)) < 0) { 1210 ALOGE("jni avrcp controller registration failure: %d", status); 1211 return JNI_ERR; 1212 } 1213 1214 if ((status = android::register_com_android_bluetooth_hid(e)) < 0) { 1215 ALOGE("jni hid registration failure: %d", status); 1216 return JNI_ERR; 1217 } 1218 1219 if ((status = android::register_com_android_bluetooth_hdp(e)) < 0) { 1220 ALOGE("jni hdp registration failure: %d", status); 1221 return JNI_ERR; 1222 } 1223 1224 if ((status = android::register_com_android_bluetooth_pan(e)) < 0) { 1225 ALOGE("jni pan registration failure: %d", status); 1226 return JNI_ERR; 1227 } 1228 1229 if ((status = android::register_com_android_bluetooth_gatt(e)) < 0) { 1230 ALOGE("jni gatt registration failure: %d", status); 1231 return JNI_ERR; 1232 } 1233 1234 if ((status = android::register_com_android_bluetooth_sdp(e)) < 0) { 1235 ALOGE("jni sdp registration failure: %d", status); 1236 return JNI_ERR; 1237 } 1238 1239 return JNI_VERSION_1_6; 1240} 1241