1 /* 2 ** Copyright 2008, 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 "BluetoothEventLoop.cpp" 18 19 #include "android_bluetooth_common.h" 20 #include "android_runtime/AndroidRuntime.h" 21 #include "cutils/sockets.h" 22 #include "JNIHelp.h" 23 #include "jni.h" 24 #include "utils/Log.h" 25 #include "utils/misc.h" 26 27 #include <stdio.h> 28 #include <string.h> 29 #include <stdlib.h> 30 #include <errno.h> 31 #include <unistd.h> 32 33 #ifdef HAVE_BLUETOOTH 34 #include <dbus/dbus.h> 35 #endif 36 37 namespace android { 38 39 #define CREATE_DEVICE_ALREADY_EXISTS 1 40 #define CREATE_DEVICE_SUCCESS 0 41 #define CREATE_DEVICE_FAILED -1 42 43 #ifdef HAVE_BLUETOOTH 44 static jfieldID field_mNativeData; 45 46 static jmethodID method_onPropertyChanged; 47 static jmethodID method_onDevicePropertyChanged; 48 static jmethodID method_onDeviceFound; 49 static jmethodID method_onDeviceDisappeared; 50 static jmethodID method_onDeviceCreated; 51 static jmethodID method_onDeviceRemoved; 52 static jmethodID method_onDeviceDisconnectRequested; 53 54 static jmethodID method_onCreatePairedDeviceResult; 55 static jmethodID method_onCreateDeviceResult; 56 static jmethodID method_onDiscoverServicesResult; 57 static jmethodID method_onGetDeviceServiceChannelResult; 58 59 static jmethodID method_onRequestPinCode; 60 static jmethodID method_onRequestPasskey; 61 static jmethodID method_onRequestPasskeyConfirmation; 62 static jmethodID method_onRequestPairingConsent; 63 static jmethodID method_onDisplayPasskey; 64 static jmethodID method_onRequestOobData; 65 static jmethodID method_onAgentOutOfBandDataAvailable; 66 static jmethodID method_onAgentAuthorize; 67 static jmethodID method_onAgentCancel; 68 69 typedef event_loop_native_data_t native_data_t; 70 71 #define EVENT_LOOP_REFS 10 72 73 static inline native_data_t * get_native_data(JNIEnv *env, jobject object) { 74 return (native_data_t *)(env->GetIntField(object, 75 field_mNativeData)); 76 } 77 78 native_data_t *get_EventLoop_native_data(JNIEnv *env, jobject object) { 79 return get_native_data(env, object); 80 } 81 82 #endif 83 static void classInitNative(JNIEnv* env, jclass clazz) { 84 LOGV(__FUNCTION__); 85 86 #ifdef HAVE_BLUETOOTH 87 method_onPropertyChanged = env->GetMethodID(clazz, "onPropertyChanged", 88 "([Ljava/lang/String;)V"); 89 method_onDevicePropertyChanged = env->GetMethodID(clazz, 90 "onDevicePropertyChanged", 91 "(Ljava/lang/String;[Ljava/lang/String;)V"); 92 method_onDeviceFound = env->GetMethodID(clazz, "onDeviceFound", 93 "(Ljava/lang/String;[Ljava/lang/String;)V"); 94 method_onDeviceDisappeared = env->GetMethodID(clazz, "onDeviceDisappeared", 95 "(Ljava/lang/String;)V"); 96 method_onDeviceCreated = env->GetMethodID(clazz, "onDeviceCreated", "(Ljava/lang/String;)V"); 97 method_onDeviceRemoved = env->GetMethodID(clazz, "onDeviceRemoved", "(Ljava/lang/String;)V"); 98 method_onDeviceDisconnectRequested = env->GetMethodID(clazz, "onDeviceDisconnectRequested", 99 "(Ljava/lang/String;)V"); 100 101 method_onCreatePairedDeviceResult = env->GetMethodID(clazz, "onCreatePairedDeviceResult", 102 "(Ljava/lang/String;I)V"); 103 method_onCreateDeviceResult = env->GetMethodID(clazz, "onCreateDeviceResult", 104 "(Ljava/lang/String;I)V"); 105 method_onDiscoverServicesResult = env->GetMethodID(clazz, "onDiscoverServicesResult", 106 "(Ljava/lang/String;Z)V"); 107 108 method_onAgentAuthorize = env->GetMethodID(clazz, "onAgentAuthorize", 109 "(Ljava/lang/String;Ljava/lang/String;)Z"); 110 method_onAgentOutOfBandDataAvailable = env->GetMethodID(clazz, "onAgentOutOfBandDataAvailable", 111 "(Ljava/lang/String;)Z"); 112 method_onAgentCancel = env->GetMethodID(clazz, "onAgentCancel", "()V"); 113 method_onRequestPinCode = env->GetMethodID(clazz, "onRequestPinCode", 114 "(Ljava/lang/String;I)V"); 115 method_onRequestPasskey = env->GetMethodID(clazz, "onRequestPasskey", 116 "(Ljava/lang/String;I)V"); 117 method_onRequestPasskeyConfirmation = env->GetMethodID(clazz, "onRequestPasskeyConfirmation", 118 "(Ljava/lang/String;II)V"); 119 method_onRequestPairingConsent = env->GetMethodID(clazz, "onRequestPairingConsent", 120 "(Ljava/lang/String;I)V"); 121 method_onDisplayPasskey = env->GetMethodID(clazz, "onDisplayPasskey", 122 "(Ljava/lang/String;II)V"); 123 method_onRequestOobData = env->GetMethodID(clazz, "onRequestOobData", 124 "(Ljava/lang/String;I)V"); 125 126 field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I"); 127 #endif 128 } 129 130 static void initializeNativeDataNative(JNIEnv* env, jobject object) { 131 LOGV(__FUNCTION__); 132 #ifdef HAVE_BLUETOOTH 133 native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t)); 134 if (NULL == nat) { 135 LOGE("%s: out of memory!", __FUNCTION__); 136 return; 137 } 138 memset(nat, 0, sizeof(native_data_t)); 139 140 pthread_mutex_init(&(nat->thread_mutex), NULL); 141 142 env->SetIntField(object, field_mNativeData, (jint)nat); 143 144 { 145 DBusError err; 146 dbus_error_init(&err); 147 dbus_threads_init_default(); 148 nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); 149 if (dbus_error_is_set(&err)) { 150 LOGE("%s: Could not get onto the system bus!", __FUNCTION__); 151 dbus_error_free(&err); 152 } 153 dbus_connection_set_exit_on_disconnect(nat->conn, FALSE); 154 } 155 #endif 156 } 157 158 static void cleanupNativeDataNative(JNIEnv* env, jobject object) { 159 LOGV(__FUNCTION__); 160 #ifdef HAVE_BLUETOOTH 161 native_data_t *nat = 162 (native_data_t *)env->GetIntField(object, field_mNativeData); 163 164 pthread_mutex_destroy(&(nat->thread_mutex)); 165 166 if (nat) { 167 free(nat); 168 } 169 #endif 170 } 171 172 #ifdef HAVE_BLUETOOTH 173 static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, 174 void *data); 175 DBusHandlerResult agent_event_filter(DBusConnection *conn, 176 DBusMessage *msg, 177 void *data); 178 static int register_agent(native_data_t *nat, 179 const char *agent_path, const char *capabilities); 180 181 static const DBusObjectPathVTable agent_vtable = { 182 NULL, agent_event_filter, NULL, NULL, NULL, NULL 183 }; 184 185 static unsigned int unix_events_to_dbus_flags(short events) { 186 return (events & DBUS_WATCH_READABLE ? POLLIN : 0) | 187 (events & DBUS_WATCH_WRITABLE ? POLLOUT : 0) | 188 (events & DBUS_WATCH_ERROR ? POLLERR : 0) | 189 (events & DBUS_WATCH_HANGUP ? POLLHUP : 0); 190 } 191 192 static short dbus_flags_to_unix_events(unsigned int flags) { 193 return (flags & POLLIN ? DBUS_WATCH_READABLE : 0) | 194 (flags & POLLOUT ? DBUS_WATCH_WRITABLE : 0) | 195 (flags & POLLERR ? DBUS_WATCH_ERROR : 0) | 196 (flags & POLLHUP ? DBUS_WATCH_HANGUP : 0); 197 } 198 199 static jboolean setUpEventLoop(native_data_t *nat) { 200 LOGV(__FUNCTION__); 201 202 if (nat != NULL && nat->conn != NULL) { 203 dbus_threads_init_default(); 204 DBusError err; 205 dbus_error_init(&err); 206 207 // Add a filter for all incoming messages 208 if (!dbus_connection_add_filter(nat->conn, event_filter, nat, NULL)){ 209 return JNI_FALSE; 210 } 211 212 // Set which messages will be processed by this dbus connection 213 dbus_bus_add_match(nat->conn, 214 "type='signal',interface='org.freedesktop.DBus'", 215 &err); 216 if (dbus_error_is_set(&err)) { 217 LOG_AND_FREE_DBUS_ERROR(&err); 218 return JNI_FALSE; 219 } 220 dbus_bus_add_match(nat->conn, 221 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'", 222 &err); 223 if (dbus_error_is_set(&err)) { 224 LOG_AND_FREE_DBUS_ERROR(&err); 225 return JNI_FALSE; 226 } 227 dbus_bus_add_match(nat->conn, 228 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Device'", 229 &err); 230 if (dbus_error_is_set(&err)) { 231 LOG_AND_FREE_DBUS_ERROR(&err); 232 return JNI_FALSE; 233 } 234 dbus_bus_add_match(nat->conn, 235 "type='signal',interface='org.bluez.AudioSink'", 236 &err); 237 if (dbus_error_is_set(&err)) { 238 LOG_AND_FREE_DBUS_ERROR(&err); 239 return JNI_FALSE; 240 } 241 242 const char *agent_path = "/android/bluetooth/agent"; 243 const char *capabilities = "DisplayYesNo"; 244 if (register_agent(nat, agent_path, capabilities) < 0) { 245 dbus_connection_unregister_object_path (nat->conn, agent_path); 246 return JNI_FALSE; 247 } 248 return JNI_TRUE; 249 } 250 return JNI_FALSE; 251 } 252 253 254 const char * get_adapter_path(DBusConnection *conn) { 255 DBusMessage *msg = NULL, *reply = NULL; 256 DBusError err; 257 const char *device_path = NULL; 258 int attempt = 0; 259 260 for (attempt = 0; attempt < 1000 && reply == NULL; attempt ++) { 261 msg = dbus_message_new_method_call("org.bluez", "/", 262 "org.bluez.Manager", "DefaultAdapter"); 263 if (!msg) { 264 LOGE("%s: Can't allocate new method call for get_adapter_path!", 265 __FUNCTION__); 266 return NULL; 267 } 268 dbus_message_append_args(msg, DBUS_TYPE_INVALID); 269 dbus_error_init(&err); 270 reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err); 271 272 if (!reply) { 273 if (dbus_error_is_set(&err)) { 274 if (dbus_error_has_name(&err, 275 "org.freedesktop.DBus.Error.ServiceUnknown")) { 276 // bluetoothd is still down, retry 277 LOG_AND_FREE_DBUS_ERROR(&err); 278 usleep(10000); // 10 ms 279 continue; 280 } else { 281 // Some other error we weren't expecting 282 LOG_AND_FREE_DBUS_ERROR(&err); 283 } 284 } 285 goto failed; 286 } 287 } 288 if (attempt == 1000) { 289 LOGE("Time out while trying to get Adapter path, is bluetoothd up ?"); 290 goto failed; 291 } 292 293 if (!dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH, 294 &device_path, DBUS_TYPE_INVALID) 295 || !device_path){ 296 if (dbus_error_is_set(&err)) { 297 LOG_AND_FREE_DBUS_ERROR(&err); 298 } 299 goto failed; 300 } 301 dbus_message_unref(msg); 302 return device_path; 303 304 failed: 305 dbus_message_unref(msg); 306 return NULL; 307 } 308 309 static int register_agent(native_data_t *nat, 310 const char * agent_path, const char * capabilities) 311 { 312 DBusMessage *msg, *reply; 313 DBusError err; 314 bool oob = TRUE; 315 316 if (!dbus_connection_register_object_path(nat->conn, agent_path, 317 &agent_vtable, nat)) { 318 LOGE("%s: Can't register object path %s for agent!", 319 __FUNCTION__, agent_path); 320 return -1; 321 } 322 323 nat->adapter = get_adapter_path(nat->conn); 324 if (nat->adapter == NULL) { 325 return -1; 326 } 327 msg = dbus_message_new_method_call("org.bluez", nat->adapter, 328 "org.bluez.Adapter", "RegisterAgent"); 329 if (!msg) { 330 LOGE("%s: Can't allocate new method call for agent!", 331 __FUNCTION__); 332 return -1; 333 } 334 dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path, 335 DBUS_TYPE_STRING, &capabilities, 336 DBUS_TYPE_BOOLEAN, &oob, 337 DBUS_TYPE_INVALID); 338 339 dbus_error_init(&err); 340 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err); 341 dbus_message_unref(msg); 342 343 if (!reply) { 344 LOGE("%s: Can't register agent!", __FUNCTION__); 345 if (dbus_error_is_set(&err)) { 346 LOG_AND_FREE_DBUS_ERROR(&err); 347 } 348 return -1; 349 } 350 351 dbus_message_unref(reply); 352 dbus_connection_flush(nat->conn); 353 354 return 0; 355 } 356 357 static void tearDownEventLoop(native_data_t *nat) { 358 LOGV(__FUNCTION__); 359 if (nat != NULL && nat->conn != NULL) { 360 361 DBusMessage *msg, *reply; 362 DBusError err; 363 dbus_error_init(&err); 364 const char * agent_path = "/android/bluetooth/agent"; 365 366 msg = dbus_message_new_method_call("org.bluez", 367 nat->adapter, 368 "org.bluez.Adapter", 369 "UnregisterAgent"); 370 if (msg != NULL) { 371 dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path, 372 DBUS_TYPE_INVALID); 373 reply = dbus_connection_send_with_reply_and_block(nat->conn, 374 msg, -1, &err); 375 376 if (!reply) { 377 if (dbus_error_is_set(&err)) { 378 LOG_AND_FREE_DBUS_ERROR(&err); 379 dbus_error_free(&err); 380 } 381 } else { 382 dbus_message_unref(reply); 383 } 384 dbus_message_unref(msg); 385 } else { 386 LOGE("%s: Can't create new method call!", __FUNCTION__); 387 } 388 389 dbus_connection_flush(nat->conn); 390 dbus_connection_unregister_object_path(nat->conn, agent_path); 391 392 dbus_bus_remove_match(nat->conn, 393 "type='signal',interface='org.bluez.AudioSink'", 394 &err); 395 if (dbus_error_is_set(&err)) { 396 LOG_AND_FREE_DBUS_ERROR(&err); 397 } 398 dbus_bus_remove_match(nat->conn, 399 "type='signal',interface='org.bluez.Device'", 400 &err); 401 if (dbus_error_is_set(&err)) { 402 LOG_AND_FREE_DBUS_ERROR(&err); 403 } 404 dbus_bus_remove_match(nat->conn, 405 "type='signal',interface='org.bluez.audio.Manager'", 406 &err); 407 if (dbus_error_is_set(&err)) { 408 LOG_AND_FREE_DBUS_ERROR(&err); 409 } 410 dbus_bus_remove_match(nat->conn, 411 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'", 412 &err); 413 if (dbus_error_is_set(&err)) { 414 LOG_AND_FREE_DBUS_ERROR(&err); 415 } 416 dbus_bus_remove_match(nat->conn, 417 "type='signal',interface='org.freedesktop.DBus'", 418 &err); 419 if (dbus_error_is_set(&err)) { 420 LOG_AND_FREE_DBUS_ERROR(&err); 421 } 422 423 dbus_connection_remove_filter(nat->conn, event_filter, nat); 424 } 425 } 426 427 428 #define EVENT_LOOP_EXIT 1 429 #define EVENT_LOOP_ADD 2 430 #define EVENT_LOOP_REMOVE 3 431 432 dbus_bool_t dbusAddWatch(DBusWatch *watch, void *data) { 433 native_data_t *nat = (native_data_t *)data; 434 435 if (dbus_watch_get_enabled(watch)) { 436 // note that we can't just send the watch and inspect it later 437 // because we may get a removeWatch call before this data is reacted 438 // to by our eventloop and remove this watch.. reading the add first 439 // and then inspecting the recently deceased watch would be bad. 440 char control = EVENT_LOOP_ADD; 441 write(nat->controlFdW, &control, sizeof(char)); 442 443 int fd = dbus_watch_get_fd(watch); 444 write(nat->controlFdW, &fd, sizeof(int)); 445 446 unsigned int flags = dbus_watch_get_flags(watch); 447 write(nat->controlFdW, &flags, sizeof(unsigned int)); 448 449 write(nat->controlFdW, &watch, sizeof(DBusWatch*)); 450 } 451 return true; 452 } 453 454 void dbusRemoveWatch(DBusWatch *watch, void *data) { 455 native_data_t *nat = (native_data_t *)data; 456 457 char control = EVENT_LOOP_REMOVE; 458 write(nat->controlFdW, &control, sizeof(char)); 459 460 int fd = dbus_watch_get_fd(watch); 461 write(nat->controlFdW, &fd, sizeof(int)); 462 463 unsigned int flags = dbus_watch_get_flags(watch); 464 write(nat->controlFdW, &flags, sizeof(unsigned int)); 465 } 466 467 void dbusToggleWatch(DBusWatch *watch, void *data) { 468 if (dbus_watch_get_enabled(watch)) { 469 dbusAddWatch(watch, data); 470 } else { 471 dbusRemoveWatch(watch, data); 472 } 473 } 474 475 static void handleWatchAdd(native_data_t *nat) { 476 DBusWatch *watch; 477 int newFD; 478 unsigned int flags; 479 480 read(nat->controlFdR, &newFD, sizeof(int)); 481 read(nat->controlFdR, &flags, sizeof(unsigned int)); 482 read(nat->controlFdR, &watch, sizeof(DBusWatch *)); 483 short events = dbus_flags_to_unix_events(flags); 484 485 for (int y = 0; y<nat->pollMemberCount; y++) { 486 if ((nat->pollData[y].fd == newFD) && 487 (nat->pollData[y].events == events)) { 488 LOGV("DBusWatch duplicate add"); 489 return; 490 } 491 } 492 if (nat->pollMemberCount == nat->pollDataSize) { 493 LOGV("Bluetooth EventLoop poll struct growing"); 494 struct pollfd *temp = (struct pollfd *)malloc( 495 sizeof(struct pollfd) * (nat->pollMemberCount+1)); 496 if (!temp) { 497 return; 498 } 499 memcpy(temp, nat->pollData, sizeof(struct pollfd) * 500 nat->pollMemberCount); 501 free(nat->pollData); 502 nat->pollData = temp; 503 DBusWatch **temp2 = (DBusWatch **)malloc(sizeof(DBusWatch *) * 504 (nat->pollMemberCount+1)); 505 if (!temp2) { 506 return; 507 } 508 memcpy(temp2, nat->watchData, sizeof(DBusWatch *) * 509 nat->pollMemberCount); 510 free(nat->watchData); 511 nat->watchData = temp2; 512 nat->pollDataSize++; 513 } 514 nat->pollData[nat->pollMemberCount].fd = newFD; 515 nat->pollData[nat->pollMemberCount].revents = 0; 516 nat->pollData[nat->pollMemberCount].events = events; 517 nat->watchData[nat->pollMemberCount] = watch; 518 nat->pollMemberCount++; 519 } 520 521 static void handleWatchRemove(native_data_t *nat) { 522 int removeFD; 523 unsigned int flags; 524 525 read(nat->controlFdR, &removeFD, sizeof(int)); 526 read(nat->controlFdR, &flags, sizeof(unsigned int)); 527 short events = dbus_flags_to_unix_events(flags); 528 529 for (int y = 0; y < nat->pollMemberCount; y++) { 530 if ((nat->pollData[y].fd == removeFD) && 531 (nat->pollData[y].events == events)) { 532 int newCount = --nat->pollMemberCount; 533 // copy the last live member over this one 534 nat->pollData[y].fd = nat->pollData[newCount].fd; 535 nat->pollData[y].events = nat->pollData[newCount].events; 536 nat->pollData[y].revents = nat->pollData[newCount].revents; 537 nat->watchData[y] = nat->watchData[newCount]; 538 return; 539 } 540 } 541 LOGW("WatchRemove given with unknown watch"); 542 } 543 544 static void *eventLoopMain(void *ptr) { 545 native_data_t *nat = (native_data_t *)ptr; 546 JNIEnv *env; 547 548 JavaVMAttachArgs args; 549 char name[] = "BT EventLoop"; 550 args.version = nat->envVer; 551 args.name = name; 552 args.group = NULL; 553 554 nat->vm->AttachCurrentThread(&env, &args); 555 556 dbus_connection_set_watch_functions(nat->conn, dbusAddWatch, 557 dbusRemoveWatch, dbusToggleWatch, ptr, NULL); 558 559 nat->running = true; 560 561 while (1) { 562 for (int i = 0; i < nat->pollMemberCount; i++) { 563 if (!nat->pollData[i].revents) { 564 continue; 565 } 566 if (nat->pollData[i].fd == nat->controlFdR) { 567 char data; 568 while (recv(nat->controlFdR, &data, sizeof(char), MSG_DONTWAIT) 569 != -1) { 570 switch (data) { 571 case EVENT_LOOP_EXIT: 572 { 573 dbus_connection_set_watch_functions(nat->conn, 574 NULL, NULL, NULL, NULL, NULL); 575 tearDownEventLoop(nat); 576 nat->vm->DetachCurrentThread(); 577 578 int fd = nat->controlFdR; 579 nat->controlFdR = 0; 580 close(fd); 581 return NULL; 582 } 583 case EVENT_LOOP_ADD: 584 { 585 handleWatchAdd(nat); 586 break; 587 } 588 case EVENT_LOOP_REMOVE: 589 { 590 handleWatchRemove(nat); 591 break; 592 } 593 } 594 } 595 } else { 596 short events = nat->pollData[i].revents; 597 unsigned int flags = unix_events_to_dbus_flags(events); 598 dbus_watch_handle(nat->watchData[i], flags); 599 nat->pollData[i].revents = 0; 600 // can only do one - it may have caused a 'remove' 601 break; 602 } 603 } 604 while (dbus_connection_dispatch(nat->conn) == 605 DBUS_DISPATCH_DATA_REMAINS) { 606 } 607 608 poll(nat->pollData, nat->pollMemberCount, -1); 609 } 610 } 611 #endif // HAVE_BLUETOOTH 612 613 static jboolean startEventLoopNative(JNIEnv *env, jobject object) { 614 jboolean result = JNI_FALSE; 615 #ifdef HAVE_BLUETOOTH 616 event_loop_native_data_t *nat = get_native_data(env, object); 617 618 pthread_mutex_lock(&(nat->thread_mutex)); 619 620 nat->running = false; 621 622 if (nat->pollData) { 623 LOGW("trying to start EventLoop a second time!"); 624 pthread_mutex_unlock( &(nat->thread_mutex) ); 625 return JNI_FALSE; 626 } 627 628 nat->pollData = (struct pollfd *)malloc(sizeof(struct pollfd) * 629 DEFAULT_INITIAL_POLLFD_COUNT); 630 if (!nat->pollData) { 631 LOGE("out of memory error starting EventLoop!"); 632 goto done; 633 } 634 635 nat->watchData = (DBusWatch **)malloc(sizeof(DBusWatch *) * 636 DEFAULT_INITIAL_POLLFD_COUNT); 637 if (!nat->watchData) { 638 LOGE("out of memory error starting EventLoop!"); 639 goto done; 640 } 641 642 memset(nat->pollData, 0, sizeof(struct pollfd) * 643 DEFAULT_INITIAL_POLLFD_COUNT); 644 memset(nat->watchData, 0, sizeof(DBusWatch *) * 645 DEFAULT_INITIAL_POLLFD_COUNT); 646 nat->pollDataSize = DEFAULT_INITIAL_POLLFD_COUNT; 647 nat->pollMemberCount = 1; 648 649 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, &(nat->controlFdR))) { 650 LOGE("Error getting BT control socket"); 651 goto done; 652 } 653 nat->pollData[0].fd = nat->controlFdR; 654 nat->pollData[0].events = POLLIN; 655 656 env->GetJavaVM( &(nat->vm) ); 657 nat->envVer = env->GetVersion(); 658 659 nat->me = env->NewGlobalRef(object); 660 661 if (setUpEventLoop(nat) != JNI_TRUE) { 662 LOGE("failure setting up Event Loop!"); 663 goto done; 664 } 665 666 pthread_create(&(nat->thread), NULL, eventLoopMain, nat); 667 result = JNI_TRUE; 668 669 done: 670 if (JNI_FALSE == result) { 671 if (nat->controlFdW) { 672 close(nat->controlFdW); 673 nat->controlFdW = 0; 674 } 675 if (nat->controlFdR) { 676 close(nat->controlFdR); 677 nat->controlFdR = 0; 678 } 679 if (nat->me) env->DeleteGlobalRef(nat->me); 680 nat->me = NULL; 681 if (nat->pollData) free(nat->pollData); 682 nat->pollData = NULL; 683 if (nat->watchData) free(nat->watchData); 684 nat->watchData = NULL; 685 nat->pollDataSize = 0; 686 nat->pollMemberCount = 0; 687 } 688 689 pthread_mutex_unlock(&(nat->thread_mutex)); 690 #endif // HAVE_BLUETOOTH 691 return result; 692 } 693 694 static void stopEventLoopNative(JNIEnv *env, jobject object) { 695 #ifdef HAVE_BLUETOOTH 696 native_data_t *nat = get_native_data(env, object); 697 698 pthread_mutex_lock(&(nat->thread_mutex)); 699 if (nat->pollData) { 700 char data = EVENT_LOOP_EXIT; 701 ssize_t t = write(nat->controlFdW, &data, sizeof(char)); 702 void *ret; 703 pthread_join(nat->thread, &ret); 704 705 env->DeleteGlobalRef(nat->me); 706 nat->me = NULL; 707 free(nat->pollData); 708 nat->pollData = NULL; 709 free(nat->watchData); 710 nat->watchData = NULL; 711 nat->pollDataSize = 0; 712 nat->pollMemberCount = 0; 713 714 int fd = nat->controlFdW; 715 nat->controlFdW = 0; 716 close(fd); 717 } 718 nat->running = false; 719 pthread_mutex_unlock(&(nat->thread_mutex)); 720 #endif // HAVE_BLUETOOTH 721 } 722 723 static jboolean isEventLoopRunningNative(JNIEnv *env, jobject object) { 724 jboolean result = JNI_FALSE; 725 #ifdef HAVE_BLUETOOTH 726 native_data_t *nat = get_native_data(env, object); 727 728 pthread_mutex_lock(&(nat->thread_mutex)); 729 if (nat->running) { 730 result = JNI_TRUE; 731 } 732 pthread_mutex_unlock(&(nat->thread_mutex)); 733 734 #endif // HAVE_BLUETOOTH 735 return result; 736 } 737 738 #ifdef HAVE_BLUETOOTH 739 extern DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env); 740 741 // Called by dbus during WaitForAndDispatchEventNative() 742 static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, 743 void *data) { 744 native_data_t *nat; 745 JNIEnv *env; 746 DBusError err; 747 DBusHandlerResult ret; 748 749 dbus_error_init(&err); 750 751 nat = (native_data_t *)data; 752 nat->vm->GetEnv((void**)&env, nat->envVer); 753 if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) { 754 LOGV("%s: not interested (not a signal).", __FUNCTION__); 755 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 756 } 757 758 LOGE("%s: Received signal %s:%s from %s", __FUNCTION__, 759 dbus_message_get_interface(msg), dbus_message_get_member(msg), 760 dbus_message_get_path(msg)); 761 762 env->PushLocalFrame(EVENT_LOOP_REFS); 763 if (dbus_message_is_signal(msg, 764 "org.bluez.Adapter", 765 "DeviceFound")) { 766 char *c_address; 767 DBusMessageIter iter; 768 jobjectArray str_array = NULL; 769 if (dbus_message_iter_init(msg, &iter)) { 770 dbus_message_iter_get_basic(&iter, &c_address); 771 if (dbus_message_iter_next(&iter)) 772 str_array = 773 parse_remote_device_properties(env, &iter); 774 } 775 if (str_array != NULL) { 776 env->CallVoidMethod(nat->me, 777 method_onDeviceFound, 778 env->NewStringUTF(c_address), 779 str_array); 780 } else 781 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); 782 goto success; 783 } else if (dbus_message_is_signal(msg, 784 "org.bluez.Adapter", 785 "DeviceDisappeared")) { 786 char *c_address; 787 if (dbus_message_get_args(msg, &err, 788 DBUS_TYPE_STRING, &c_address, 789 DBUS_TYPE_INVALID)) { 790 LOGV("... address = %s", c_address); 791 env->CallVoidMethod(nat->me, method_onDeviceDisappeared, 792 env->NewStringUTF(c_address)); 793 } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); 794 goto success; 795 } else if (dbus_message_is_signal(msg, 796 "org.bluez.Adapter", 797 "DeviceCreated")) { 798 char *c_object_path; 799 if (dbus_message_get_args(msg, &err, 800 DBUS_TYPE_OBJECT_PATH, &c_object_path, 801 DBUS_TYPE_INVALID)) { 802 LOGV("... address = %s", c_object_path); 803 env->CallVoidMethod(nat->me, 804 method_onDeviceCreated, 805 env->NewStringUTF(c_object_path)); 806 } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); 807 goto success; 808 } else if (dbus_message_is_signal(msg, 809 "org.bluez.Adapter", 810 "DeviceRemoved")) { 811 char *c_object_path; 812 if (dbus_message_get_args(msg, &err, 813 DBUS_TYPE_OBJECT_PATH, &c_object_path, 814 DBUS_TYPE_INVALID)) { 815 LOGV("... Object Path = %s", c_object_path); 816 env->CallVoidMethod(nat->me, 817 method_onDeviceRemoved, 818 env->NewStringUTF(c_object_path)); 819 } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); 820 goto success; 821 } else if (dbus_message_is_signal(msg, 822 "org.bluez.Adapter", 823 "PropertyChanged")) { 824 jobjectArray str_array = parse_adapter_property_change(env, msg); 825 if (str_array != NULL) { 826 /* Check if bluetoothd has (re)started, if so update the path. */ 827 jstring property =(jstring) env->GetObjectArrayElement(str_array, 0); 828 const char *c_property = env->GetStringUTFChars(property, NULL); 829 if (!strncmp(c_property, "Powered", strlen("Powered"))) { 830 jstring value = 831 (jstring) env->GetObjectArrayElement(str_array, 1); 832 const char *c_value = env->GetStringUTFChars(value, NULL); 833 if (!strncmp(c_value, "true", strlen("true"))) 834 nat->adapter = get_adapter_path(nat->conn); 835 env->ReleaseStringUTFChars(value, c_value); 836 } 837 env->ReleaseStringUTFChars(property, c_property); 838 839 env->CallVoidMethod(nat->me, 840 method_onPropertyChanged, 841 str_array); 842 } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); 843 goto success; 844 } else if (dbus_message_is_signal(msg, 845 "org.bluez.Device", 846 "PropertyChanged")) { 847 jobjectArray str_array = parse_remote_device_property_change(env, msg); 848 if (str_array != NULL) { 849 const char *remote_device_path = dbus_message_get_path(msg); 850 env->CallVoidMethod(nat->me, 851 method_onDevicePropertyChanged, 852 env->NewStringUTF(remote_device_path), 853 str_array); 854 } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); 855 goto success; 856 } else if (dbus_message_is_signal(msg, 857 "org.bluez.Device", 858 "DisconnectRequested")) { 859 const char *remote_device_path = dbus_message_get_path(msg); 860 env->CallVoidMethod(nat->me, 861 method_onDeviceDisconnectRequested, 862 env->NewStringUTF(remote_device_path)); 863 goto success; 864 } 865 866 ret = a2dp_event_filter(msg, env); 867 env->PopLocalFrame(NULL); 868 return ret; 869 870 success: 871 env->PopLocalFrame(NULL); 872 return DBUS_HANDLER_RESULT_HANDLED; 873 } 874 875 // Called by dbus during WaitForAndDispatchEventNative() 876 DBusHandlerResult agent_event_filter(DBusConnection *conn, 877 DBusMessage *msg, void *data) { 878 native_data_t *nat = (native_data_t *)data; 879 JNIEnv *env; 880 if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) { 881 LOGV("%s: not interested (not a method call).", __FUNCTION__); 882 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 883 } 884 LOGI("%s: Received method %s:%s", __FUNCTION__, 885 dbus_message_get_interface(msg), dbus_message_get_member(msg)); 886 887 if (nat == NULL) return DBUS_HANDLER_RESULT_HANDLED; 888 889 nat->vm->GetEnv((void**)&env, nat->envVer); 890 env->PushLocalFrame(EVENT_LOOP_REFS); 891 892 if (dbus_message_is_method_call(msg, 893 "org.bluez.Agent", "Cancel")) { 894 env->CallVoidMethod(nat->me, method_onAgentCancel); 895 // reply 896 DBusMessage *reply = dbus_message_new_method_return(msg); 897 if (!reply) { 898 LOGE("%s: Cannot create message reply\n", __FUNCTION__); 899 goto failure; 900 } 901 dbus_connection_send(nat->conn, reply, NULL); 902 dbus_message_unref(reply); 903 goto success; 904 905 } else if (dbus_message_is_method_call(msg, 906 "org.bluez.Agent", "Authorize")) { 907 char *object_path; 908 const char *uuid; 909 if (!dbus_message_get_args(msg, NULL, 910 DBUS_TYPE_OBJECT_PATH, &object_path, 911 DBUS_TYPE_STRING, &uuid, 912 DBUS_TYPE_INVALID)) { 913 LOGE("%s: Invalid arguments for Authorize() method", __FUNCTION__); 914 goto failure; 915 } 916 917 LOGV("... object_path = %s", object_path); 918 LOGV("... uuid = %s", uuid); 919 920 bool auth_granted = 921 env->CallBooleanMethod(nat->me, method_onAgentAuthorize, 922 env->NewStringUTF(object_path), env->NewStringUTF(uuid)); 923 924 // reply 925 if (auth_granted) { 926 DBusMessage *reply = dbus_message_new_method_return(msg); 927 if (!reply) { 928 LOGE("%s: Cannot create message reply\n", __FUNCTION__); 929 goto failure; 930 } 931 dbus_connection_send(nat->conn, reply, NULL); 932 dbus_message_unref(reply); 933 } else { 934 DBusMessage *reply = dbus_message_new_error(msg, 935 "org.bluez.Error.Rejected", "Authorization rejected"); 936 if (!reply) { 937 LOGE("%s: Cannot create message reply\n", __FUNCTION__); 938 goto failure; 939 } 940 dbus_connection_send(nat->conn, reply, NULL); 941 dbus_message_unref(reply); 942 } 943 goto success; 944 } else if (dbus_message_is_method_call(msg, 945 "org.bluez.Agent", "OutOfBandAvailable")) { 946 char *object_path; 947 if (!dbus_message_get_args(msg, NULL, 948 DBUS_TYPE_OBJECT_PATH, &object_path, 949 DBUS_TYPE_INVALID)) { 950 LOGE("%s: Invalid arguments for OutOfBandData available() method", __FUNCTION__); 951 goto failure; 952 } 953 954 LOGV("... object_path = %s", object_path); 955 956 bool available = 957 env->CallBooleanMethod(nat->me, method_onAgentOutOfBandDataAvailable, 958 env->NewStringUTF(object_path)); 959 960 961 // reply 962 if (available) { 963 DBusMessage *reply = dbus_message_new_method_return(msg); 964 if (!reply) { 965 LOGE("%s: Cannot create message reply\n", __FUNCTION__); 966 goto failure; 967 } 968 dbus_connection_send(nat->conn, reply, NULL); 969 dbus_message_unref(reply); 970 } else { 971 DBusMessage *reply = dbus_message_new_error(msg, 972 "org.bluez.Error.DoesNotExist", "OutofBand data not available"); 973 if (!reply) { 974 LOGE("%s: Cannot create message reply\n", __FUNCTION__); 975 goto failure; 976 } 977 dbus_connection_send(nat->conn, reply, NULL); 978 dbus_message_unref(reply); 979 } 980 goto success; 981 } else if (dbus_message_is_method_call(msg, 982 "org.bluez.Agent", "RequestPinCode")) { 983 char *object_path; 984 if (!dbus_message_get_args(msg, NULL, 985 DBUS_TYPE_OBJECT_PATH, &object_path, 986 DBUS_TYPE_INVALID)) { 987 LOGE("%s: Invalid arguments for RequestPinCode() method", __FUNCTION__); 988 goto failure; 989 } 990 991 dbus_message_ref(msg); // increment refcount because we pass to java 992 env->CallVoidMethod(nat->me, method_onRequestPinCode, 993 env->NewStringUTF(object_path), 994 int(msg)); 995 goto success; 996 } else if (dbus_message_is_method_call(msg, 997 "org.bluez.Agent", "RequestPasskey")) { 998 char *object_path; 999 if (!dbus_message_get_args(msg, NULL, 1000 DBUS_TYPE_OBJECT_PATH, &object_path, 1001 DBUS_TYPE_INVALID)) { 1002 LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__); 1003 goto failure; 1004 } 1005 1006 dbus_message_ref(msg); // increment refcount because we pass to java 1007 env->CallVoidMethod(nat->me, method_onRequestPasskey, 1008 env->NewStringUTF(object_path), 1009 int(msg)); 1010 goto success; 1011 } else if (dbus_message_is_method_call(msg, 1012 "org.bluez.Agent", "RequestOobData")) { 1013 char *object_path; 1014 if (!dbus_message_get_args(msg, NULL, 1015 DBUS_TYPE_OBJECT_PATH, &object_path, 1016 DBUS_TYPE_INVALID)) { 1017 LOGE("%s: Invalid arguments for RequestOobData() method", __FUNCTION__); 1018 goto failure; 1019 } 1020 1021 dbus_message_ref(msg); // increment refcount because we pass to java 1022 env->CallVoidMethod(nat->me, method_onRequestOobData, 1023 env->NewStringUTF(object_path), 1024 int(msg)); 1025 goto success; 1026 } else if (dbus_message_is_method_call(msg, 1027 "org.bluez.Agent", "DisplayPasskey")) { 1028 char *object_path; 1029 uint32_t passkey; 1030 if (!dbus_message_get_args(msg, NULL, 1031 DBUS_TYPE_OBJECT_PATH, &object_path, 1032 DBUS_TYPE_UINT32, &passkey, 1033 DBUS_TYPE_INVALID)) { 1034 LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__); 1035 goto failure; 1036 } 1037 1038 dbus_message_ref(msg); // increment refcount because we pass to java 1039 env->CallVoidMethod(nat->me, method_onDisplayPasskey, 1040 env->NewStringUTF(object_path), 1041 passkey, 1042 int(msg)); 1043 goto success; 1044 } else if (dbus_message_is_method_call(msg, 1045 "org.bluez.Agent", "RequestConfirmation")) { 1046 char *object_path; 1047 uint32_t passkey; 1048 if (!dbus_message_get_args(msg, NULL, 1049 DBUS_TYPE_OBJECT_PATH, &object_path, 1050 DBUS_TYPE_UINT32, &passkey, 1051 DBUS_TYPE_INVALID)) { 1052 LOGE("%s: Invalid arguments for RequestConfirmation() method", __FUNCTION__); 1053 goto failure; 1054 } 1055 1056 dbus_message_ref(msg); // increment refcount because we pass to java 1057 env->CallVoidMethod(nat->me, method_onRequestPasskeyConfirmation, 1058 env->NewStringUTF(object_path), 1059 passkey, 1060 int(msg)); 1061 goto success; 1062 } else if (dbus_message_is_method_call(msg, 1063 "org.bluez.Agent", "RequestPairingConsent")) { 1064 char *object_path; 1065 if (!dbus_message_get_args(msg, NULL, 1066 DBUS_TYPE_OBJECT_PATH, &object_path, 1067 DBUS_TYPE_INVALID)) { 1068 LOGE("%s: Invalid arguments for RequestPairingConsent() method", __FUNCTION__); 1069 goto failure; 1070 } 1071 1072 dbus_message_ref(msg); // increment refcount because we pass to java 1073 env->CallVoidMethod(nat->me, method_onRequestPairingConsent, 1074 env->NewStringUTF(object_path), 1075 int(msg)); 1076 goto success; 1077 } else if (dbus_message_is_method_call(msg, 1078 "org.bluez.Agent", "Release")) { 1079 // reply 1080 DBusMessage *reply = dbus_message_new_method_return(msg); 1081 if (!reply) { 1082 LOGE("%s: Cannot create message reply\n", __FUNCTION__); 1083 goto failure; 1084 } 1085 dbus_connection_send(nat->conn, reply, NULL); 1086 dbus_message_unref(reply); 1087 goto success; 1088 } else { 1089 LOGV("%s:%s is ignored", dbus_message_get_interface(msg), dbus_message_get_member(msg)); 1090 } 1091 1092 failure: 1093 env->PopLocalFrame(NULL); 1094 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 1095 1096 success: 1097 env->PopLocalFrame(NULL); 1098 return DBUS_HANDLER_RESULT_HANDLED; 1099 1100 } 1101 #endif 1102 1103 1104 #ifdef HAVE_BLUETOOTH 1105 //TODO: Unify result codes in a header 1106 #define BOND_RESULT_ERROR -1000 1107 #define BOND_RESULT_SUCCESS 0 1108 #define BOND_RESULT_AUTH_FAILED 1 1109 #define BOND_RESULT_AUTH_REJECTED 2 1110 #define BOND_RESULT_AUTH_CANCELED 3 1111 #define BOND_RESULT_REMOTE_DEVICE_DOWN 4 1112 #define BOND_RESULT_DISCOVERY_IN_PROGRESS 5 1113 #define BOND_RESULT_AUTH_TIMEOUT 6 1114 #define BOND_RESULT_REPEATED_ATTEMPTS 7 1115 1116 void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) { 1117 LOGV(__FUNCTION__); 1118 1119 native_data_t *nat = (native_data_t *)n; 1120 const char *address = (const char *)user; 1121 DBusError err; 1122 dbus_error_init(&err); 1123 JNIEnv *env; 1124 jstring addr; 1125 1126 nat->vm->GetEnv((void**)&env, nat->envVer); 1127 1128 LOGV("... address = %s", address); 1129 1130 jint result = BOND_RESULT_SUCCESS; 1131 if (dbus_set_error_from_message(&err, msg)) { 1132 if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) { 1133 // Pins did not match, or remote device did not respond to pin 1134 // request in time 1135 LOGV("... error = %s (%s)\n", err.name, err.message); 1136 result = BOND_RESULT_AUTH_FAILED; 1137 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationRejected")) { 1138 // We rejected pairing, or the remote side rejected pairing. This 1139 // happens if either side presses 'cancel' at the pairing dialog. 1140 LOGV("... error = %s (%s)\n", err.name, err.message); 1141 result = BOND_RESULT_AUTH_REJECTED; 1142 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationCanceled")) { 1143 // Not sure if this happens 1144 LOGV("... error = %s (%s)\n", err.name, err.message); 1145 result = BOND_RESULT_AUTH_CANCELED; 1146 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.ConnectionAttemptFailed")) { 1147 // Other device is not responding at all 1148 LOGV("... error = %s (%s)\n", err.name, err.message); 1149 result = BOND_RESULT_REMOTE_DEVICE_DOWN; 1150 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AlreadyExists")) { 1151 // already bonded 1152 LOGV("... error = %s (%s)\n", err.name, err.message); 1153 result = BOND_RESULT_SUCCESS; 1154 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") && 1155 !strcmp(err.message, "Bonding in progress")) { 1156 LOGV("... error = %s (%s)\n", err.name, err.message); 1157 goto done; 1158 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") && 1159 !strcmp(err.message, "Discover in progress")) { 1160 LOGV("... error = %s (%s)\n", err.name, err.message); 1161 result = BOND_RESULT_DISCOVERY_IN_PROGRESS; 1162 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.RepeatedAttempts")) { 1163 LOGV("... error = %s (%s)\n", err.name, err.message); 1164 result = BOND_RESULT_REPEATED_ATTEMPTS; 1165 } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationTimeout")) { 1166 LOGV("... error = %s (%s)\n", err.name, err.message); 1167 result = BOND_RESULT_AUTH_TIMEOUT; 1168 } else { 1169 LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message); 1170 result = BOND_RESULT_ERROR; 1171 } 1172 } 1173 1174 addr = env->NewStringUTF(address); 1175 env->CallVoidMethod(nat->me, 1176 method_onCreatePairedDeviceResult, 1177 addr, 1178 result); 1179 env->DeleteLocalRef(addr); 1180 done: 1181 dbus_error_free(&err); 1182 free(user); 1183 } 1184 1185 void onCreateDeviceResult(DBusMessage *msg, void *user, void *n) { 1186 LOGV(__FUNCTION__); 1187 1188 native_data_t *nat = (native_data_t *)n; 1189 const char *address= (const char *)user; 1190 DBusError err; 1191 dbus_error_init(&err); 1192 JNIEnv *env; 1193 nat->vm->GetEnv((void**)&env, nat->envVer); 1194 1195 LOGV("... Address = %s", address); 1196 1197 jint result = CREATE_DEVICE_SUCCESS; 1198 if (dbus_set_error_from_message(&err, msg)) { 1199 if (dbus_error_has_name(&err, "org.bluez.Error.AlreadyExists")) { 1200 result = CREATE_DEVICE_ALREADY_EXISTS; 1201 } else { 1202 result = CREATE_DEVICE_FAILED; 1203 } 1204 LOG_AND_FREE_DBUS_ERROR(&err); 1205 } 1206 jstring addr = env->NewStringUTF(address); 1207 env->CallVoidMethod(nat->me, 1208 method_onCreateDeviceResult, 1209 addr, 1210 result); 1211 env->DeleteLocalRef(addr); 1212 free(user); 1213 } 1214 1215 void onDiscoverServicesResult(DBusMessage *msg, void *user, void *n) { 1216 LOGV(__FUNCTION__); 1217 1218 native_data_t *nat = (native_data_t *)n; 1219 const char *path = (const char *)user; 1220 DBusError err; 1221 dbus_error_init(&err); 1222 JNIEnv *env; 1223 nat->vm->GetEnv((void**)&env, nat->envVer); 1224 1225 LOGV("... Device Path = %s", path); 1226 1227 bool result = JNI_TRUE; 1228 if (dbus_set_error_from_message(&err, msg)) { 1229 LOG_AND_FREE_DBUS_ERROR(&err); 1230 result = JNI_FALSE; 1231 } 1232 jstring jPath = env->NewStringUTF(path); 1233 env->CallVoidMethod(nat->me, 1234 method_onDiscoverServicesResult, 1235 jPath, 1236 result); 1237 env->DeleteLocalRef(jPath); 1238 free(user); 1239 } 1240 1241 void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) { 1242 LOGV(__FUNCTION__); 1243 1244 const char *address = (const char *) user; 1245 native_data_t *nat = (native_data_t *) n; 1246 1247 DBusError err; 1248 dbus_error_init(&err); 1249 JNIEnv *env; 1250 nat->vm->GetEnv((void**)&env, nat->envVer); 1251 1252 jint channel = -2; 1253 1254 LOGV("... address = %s", address); 1255 1256 if (dbus_set_error_from_message(&err, msg) || 1257 !dbus_message_get_args(msg, &err, 1258 DBUS_TYPE_INT32, &channel, 1259 DBUS_TYPE_INVALID)) { 1260 LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message); 1261 dbus_error_free(&err); 1262 } 1263 1264 done: 1265 jstring addr = env->NewStringUTF(address); 1266 env->CallVoidMethod(nat->me, 1267 method_onGetDeviceServiceChannelResult, 1268 addr, 1269 channel); 1270 env->DeleteLocalRef(addr); 1271 free(user); 1272 } 1273 #endif 1274 1275 static JNINativeMethod sMethods[] = { 1276 /* name, signature, funcPtr */ 1277 {"classInitNative", "()V", (void *)classInitNative}, 1278 {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative}, 1279 {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative}, 1280 {"startEventLoopNative", "()V", (void *)startEventLoopNative}, 1281 {"stopEventLoopNative", "()V", (void *)stopEventLoopNative}, 1282 {"isEventLoopRunningNative", "()Z", (void *)isEventLoopRunningNative} 1283 }; 1284 1285 int register_android_server_BluetoothEventLoop(JNIEnv *env) { 1286 return AndroidRuntime::registerNativeMethods(env, 1287 "android/server/BluetoothEventLoop", sMethods, NELEM(sMethods)); 1288 } 1289 1290 } /* namespace android */ 1291