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