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