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