1 /* 2 ** Copyright 2006, 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 DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter" 18 #define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device" 19 #define LOG_TAG "BluetoothService.cpp" 20 21 #include "android_bluetooth_common.h" 22 #include "android_runtime/AndroidRuntime.h" 23 #include "JNIHelp.h" 24 #include "jni.h" 25 #include "utils/Log.h" 26 #include "utils/misc.h" 27 28 #include <ctype.h> 29 #include <stdio.h> 30 #include <string.h> 31 #include <stdlib.h> 32 #include <errno.h> 33 #include <unistd.h> 34 35 #include <sys/socket.h> 36 #include <sys/ioctl.h> 37 #include <fcntl.h> 38 39 #ifdef HAVE_BLUETOOTH 40 #include <dbus/dbus.h> 41 #include <bluedroid/bluetooth.h> 42 #endif 43 44 #include <cutils/properties.h> 45 46 namespace android { 47 48 #define BLUETOOTH_CLASS_ERROR 0xFF000000 49 #define PROPERTIES_NREFS 10 50 51 #ifdef HAVE_BLUETOOTH 52 // We initialize these variables when we load class 53 // android.server.BluetoothService 54 static jfieldID field_mNativeData; 55 static jfieldID field_mEventLoop; 56 57 typedef struct { 58 JNIEnv *env; 59 DBusConnection *conn; 60 const char *adapter; // dbus object name of the local adapter 61 } native_data_t; 62 63 extern event_loop_native_data_t *get_EventLoop_native_data(JNIEnv *, 64 jobject); 65 extern DBusHandlerResult agent_event_filter(DBusConnection *conn, 66 DBusMessage *msg, 67 void *data); 68 void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *nat); 69 void onDiscoverServicesResult(DBusMessage *msg, void *user, void *nat); 70 void onCreateDeviceResult(DBusMessage *msg, void *user, void *nat); 71 72 73 /** Get native data stored in the opaque (Java code maintained) pointer mNativeData 74 * Perform quick sanity check, if there are any problems return NULL 75 */ 76 static inline native_data_t * get_native_data(JNIEnv *env, jobject object) { 77 native_data_t *nat = 78 (native_data_t *)(env->GetIntField(object, field_mNativeData)); 79 if (nat == NULL || nat->conn == NULL) { 80 LOGE("Uninitialized native data\n"); 81 return NULL; 82 } 83 return nat; 84 } 85 #endif 86 87 static void classInitNative(JNIEnv* env, jclass clazz) { 88 LOGV(__FUNCTION__); 89 #ifdef HAVE_BLUETOOTH 90 field_mNativeData = get_field(env, clazz, "mNativeData", "I"); 91 field_mEventLoop = get_field(env, clazz, "mEventLoop", 92 "Landroid/server/BluetoothEventLoop;"); 93 #endif 94 } 95 96 /* Returns true on success (even if adapter is present but disabled). 97 * Return false if dbus is down, or another serious error (out of memory) 98 */ 99 static bool initializeNativeDataNative(JNIEnv* env, jobject object) { 100 LOGV(__FUNCTION__); 101 #ifdef HAVE_BLUETOOTH 102 native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t)); 103 if (NULL == nat) { 104 LOGE("%s: out of memory!", __FUNCTION__); 105 return false; 106 } 107 nat->env = env; 108 109 env->SetIntField(object, field_mNativeData, (jint)nat); 110 DBusError err; 111 dbus_error_init(&err); 112 dbus_threads_init_default(); 113 nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); 114 if (dbus_error_is_set(&err)) { 115 LOGE("Could not get onto the system bus: %s", err.message); 116 dbus_error_free(&err); 117 return false; 118 } 119 dbus_connection_set_exit_on_disconnect(nat->conn, FALSE); 120 #endif /*HAVE_BLUETOOTH*/ 121 return true; 122 } 123 124 static const char *get_adapter_path(JNIEnv* env, jobject object) { 125 #ifdef HAVE_BLUETOOTH 126 event_loop_native_data_t *event_nat = 127 get_EventLoop_native_data(env, env->GetObjectField(object, 128 field_mEventLoop)); 129 if (event_nat == NULL) 130 return NULL; 131 return event_nat->adapter; 132 #else 133 return NULL; 134 #endif 135 } 136 137 // This function is called when the adapter is enabled. 138 static jboolean setupNativeDataNative(JNIEnv* env, jobject object) { 139 LOGV(__FUNCTION__); 140 #ifdef HAVE_BLUETOOTH 141 native_data_t *nat = 142 (native_data_t *)env->GetIntField(object, field_mNativeData); 143 event_loop_native_data_t *event_nat = 144 get_EventLoop_native_data(env, env->GetObjectField(object, 145 field_mEventLoop)); 146 // Register agent for remote devices. 147 const char *device_agent_path = "/android/bluetooth/remote_device_agent"; 148 static const DBusObjectPathVTable agent_vtable = { 149 NULL, agent_event_filter, NULL, NULL, NULL, NULL }; 150 151 if (!dbus_connection_register_object_path(nat->conn, device_agent_path, 152 &agent_vtable, event_nat)) { 153 LOGE("%s: Can't register object path %s for remote device agent!", 154 __FUNCTION__, device_agent_path); 155 return JNI_FALSE; 156 } 157 #endif /*HAVE_BLUETOOTH*/ 158 return JNI_TRUE; 159 } 160 161 static jboolean tearDownNativeDataNative(JNIEnv *env, jobject object) { 162 LOGV(__FUNCTION__); 163 #ifdef HAVE_BLUETOOTH 164 native_data_t *nat = 165 (native_data_t *)env->GetIntField(object, field_mNativeData); 166 if (nat != NULL) { 167 const char *device_agent_path = 168 "/android/bluetooth/remote_device_agent"; 169 dbus_connection_unregister_object_path (nat->conn, device_agent_path); 170 } 171 #endif /*HAVE_BLUETOOTH*/ 172 return JNI_TRUE; 173 } 174 175 static void cleanupNativeDataNative(JNIEnv* env, jobject object) { 176 LOGV(__FUNCTION__); 177 #ifdef HAVE_BLUETOOTH 178 native_data_t *nat = 179 (native_data_t *)env->GetIntField(object, field_mNativeData); 180 if (nat) { 181 free(nat); 182 nat = NULL; 183 } 184 #endif 185 } 186 187 static jstring getAdapterPathNative(JNIEnv *env, jobject object) { 188 LOGV(__FUNCTION__); 189 #ifdef HAVE_BLUETOOTH 190 native_data_t *nat = get_native_data(env, object); 191 if (nat) { 192 return (env->NewStringUTF(get_adapter_path(env, object))); 193 } 194 #endif 195 return NULL; 196 } 197 198 199 static jboolean startDiscoveryNative(JNIEnv *env, jobject object) { 200 LOGV(__FUNCTION__); 201 #ifdef HAVE_BLUETOOTH 202 DBusMessage *msg = NULL; 203 DBusMessage *reply = NULL; 204 DBusError err; 205 const char *name; 206 jboolean ret = JNI_FALSE; 207 208 native_data_t *nat = get_native_data(env, object); 209 if (nat == NULL) { 210 goto done; 211 } 212 213 dbus_error_init(&err); 214 215 /* Compose the command */ 216 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, 217 get_adapter_path(env, object), 218 DBUS_ADAPTER_IFACE, "StartDiscovery"); 219 220 if (msg == NULL) { 221 if (dbus_error_is_set(&err)) { 222 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); 223 } 224 goto done; 225 } 226 227 /* Send the command. */ 228 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err); 229 if (dbus_error_is_set(&err)) { 230 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); 231 ret = JNI_FALSE; 232 goto done; 233 } 234 235 ret = JNI_TRUE; 236 done: 237 if (reply) dbus_message_unref(reply); 238 if (msg) dbus_message_unref(msg); 239 return ret; 240 #else 241 return JNI_FALSE; 242 #endif 243 } 244 245 static void stopDiscoveryNative(JNIEnv *env, jobject object) { 246 LOGV(__FUNCTION__); 247 #ifdef HAVE_BLUETOOTH 248 DBusMessage *msg = NULL; 249 DBusMessage *reply = NULL; 250 DBusError err; 251 const char *name; 252 jstring ret; 253 native_data_t *nat; 254 255 dbus_error_init(&err); 256 257 nat = get_native_data(env, object); 258 if (nat == NULL) { 259 goto done; 260 } 261 262 /* Compose the command */ 263 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, 264 get_adapter_path(env, object), 265 DBUS_ADAPTER_IFACE, "StopDiscovery"); 266 if (msg == NULL) { 267 if (dbus_error_is_set(&err)) 268 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); 269 goto done; 270 } 271 272 /* Send the command. */ 273 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err); 274 if (dbus_error_is_set(&err)) { 275 if(strncmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized", 276 strlen(BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized")) == 0) { 277 // hcid sends this if there is no active discovery to cancel 278 LOGV("%s: There was no active discovery to cancel", __FUNCTION__); 279 dbus_error_free(&err); 280 } else { 281 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); 282 } 283 } 284 285 done: 286 if (msg) dbus_message_unref(msg); 287 if (reply) dbus_message_unref(reply); 288 #endif 289 } 290 291 static jbyteArray readAdapterOutOfBandDataNative(JNIEnv *env, jobject object) { 292 LOGV(__FUNCTION__); 293 #ifdef HAVE_BLUETOOTH 294 native_data_t *nat = get_native_data(env, object); 295 DBusError err; 296 jbyte *hash, *randomizer; 297 jbyteArray byteArray = NULL; 298 int hash_len, r_len; 299 if (nat) { 300 DBusMessage *reply = dbus_func_args(env, nat->conn, 301 get_adapter_path(env, object), 302 DBUS_ADAPTER_IFACE, "ReadLocalOutOfBandData", 303 DBUS_TYPE_INVALID); 304 if (!reply) return NULL; 305 306 dbus_error_init(&err); 307 if (dbus_message_get_args(reply, &err, 308 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, &hash_len, 309 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, &r_len, 310 DBUS_TYPE_INVALID)) { 311 if (hash_len == 16 && r_len == 16) { 312 byteArray = env->NewByteArray(32); 313 if (byteArray) { 314 env->SetByteArrayRegion(byteArray, 0, 16, hash); 315 env->SetByteArrayRegion(byteArray, 16, 16, randomizer); 316 } 317 } else { 318 LOGE("readAdapterOutOfBandDataNative: Hash len = %d, R len = %d", 319 hash_len, r_len); 320 } 321 } else { 322 LOG_AND_FREE_DBUS_ERROR(&err); 323 } 324 dbus_message_unref(reply); 325 return byteArray; 326 } 327 #endif 328 return NULL; 329 } 330 331 static jboolean createPairedDeviceNative(JNIEnv *env, jobject object, 332 jstring address, jint timeout_ms) { 333 LOGV(__FUNCTION__); 334 #ifdef HAVE_BLUETOOTH 335 native_data_t *nat = get_native_data(env, object); 336 jobject eventLoop = env->GetObjectField(object, field_mEventLoop); 337 struct event_loop_native_data_t *eventLoopNat = 338 get_EventLoop_native_data(env, eventLoop); 339 340 if (nat && eventLoopNat) { 341 const char *c_address = env->GetStringUTFChars(address, NULL); 342 LOGV("... address = %s", c_address); 343 char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char)); 344 const char *capabilities = "DisplayYesNo"; 345 const char *agent_path = "/android/bluetooth/remote_device_agent"; 346 347 strlcpy(context_address, c_address, BTADDR_SIZE); // for callback 348 bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms, 349 onCreatePairedDeviceResult, // callback 350 context_address, 351 eventLoopNat, 352 get_adapter_path(env, object), 353 DBUS_ADAPTER_IFACE, 354 "CreatePairedDevice", 355 DBUS_TYPE_STRING, &c_address, 356 DBUS_TYPE_OBJECT_PATH, &agent_path, 357 DBUS_TYPE_STRING, &capabilities, 358 DBUS_TYPE_INVALID); 359 env->ReleaseStringUTFChars(address, c_address); 360 return ret ? JNI_TRUE : JNI_FALSE; 361 362 } 363 #endif 364 return JNI_FALSE; 365 } 366 367 static jboolean createPairedDeviceOutOfBandNative(JNIEnv *env, jobject object, 368 jstring address, jint timeout_ms) { 369 LOGV(__FUNCTION__); 370 #ifdef HAVE_BLUETOOTH 371 native_data_t *nat = get_native_data(env, object); 372 jobject eventLoop = env->GetObjectField(object, field_mEventLoop); 373 struct event_loop_native_data_t *eventLoopNat = 374 get_EventLoop_native_data(env, eventLoop); 375 376 if (nat && eventLoopNat) { 377 const char *c_address = env->GetStringUTFChars(address, NULL); 378 LOGV("... address = %s", c_address); 379 char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char)); 380 const char *capabilities = "DisplayYesNo"; 381 const char *agent_path = "/android/bluetooth/remote_device_agent"; 382 383 strlcpy(context_address, c_address, BTADDR_SIZE); // for callback 384 bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms, 385 onCreatePairedDeviceResult, // callback 386 context_address, 387 eventLoopNat, 388 get_adapter_path(env, object), 389 DBUS_ADAPTER_IFACE, 390 "CreatePairedDeviceOutOfBand", 391 DBUS_TYPE_STRING, &c_address, 392 DBUS_TYPE_OBJECT_PATH, &agent_path, 393 DBUS_TYPE_STRING, &capabilities, 394 DBUS_TYPE_INVALID); 395 env->ReleaseStringUTFChars(address, c_address); 396 return ret ? JNI_TRUE : JNI_FALSE; 397 } 398 #endif 399 return JNI_FALSE; 400 } 401 402 static jint getDeviceServiceChannelNative(JNIEnv *env, jobject object, 403 jstring path, 404 jstring pattern, jint attr_id) { 405 #ifdef HAVE_BLUETOOTH 406 LOGV(__FUNCTION__); 407 native_data_t *nat = get_native_data(env, object); 408 jobject eventLoop = env->GetObjectField(object, field_mEventLoop); 409 struct event_loop_native_data_t *eventLoopNat = 410 get_EventLoop_native_data(env, eventLoop); 411 if (nat && eventLoopNat) { 412 const char *c_pattern = env->GetStringUTFChars(pattern, NULL); 413 const char *c_path = env->GetStringUTFChars(path, NULL); 414 LOGV("... pattern = %s", c_pattern); 415 LOGV("... attr_id = %#X", attr_id); 416 DBusMessage *reply = 417 dbus_func_args(env, nat->conn, c_path, 418 DBUS_DEVICE_IFACE, "GetServiceAttributeValue", 419 DBUS_TYPE_STRING, &c_pattern, 420 DBUS_TYPE_UINT16, &attr_id, 421 DBUS_TYPE_INVALID); 422 env->ReleaseStringUTFChars(pattern, c_pattern); 423 env->ReleaseStringUTFChars(path, c_path); 424 return reply ? dbus_returns_int32(env, reply) : -1; 425 } 426 #endif 427 return -1; 428 } 429 430 static jboolean cancelDeviceCreationNative(JNIEnv *env, jobject object, 431 jstring address) { 432 LOGV(__FUNCTION__); 433 jboolean result = JNI_FALSE; 434 #ifdef HAVE_BLUETOOTH 435 native_data_t *nat = get_native_data(env, object); 436 if (nat) { 437 const char *c_address = env->GetStringUTFChars(address, NULL); 438 DBusError err; 439 dbus_error_init(&err); 440 LOGV("... address = %s", c_address); 441 DBusMessage *reply = 442 dbus_func_args_timeout(env, nat->conn, -1, 443 get_adapter_path(env, object), 444 DBUS_ADAPTER_IFACE, "CancelDeviceCreation", 445 DBUS_TYPE_STRING, &c_address, 446 DBUS_TYPE_INVALID); 447 env->ReleaseStringUTFChars(address, c_address); 448 if (!reply) { 449 if (dbus_error_is_set(&err)) { 450 LOG_AND_FREE_DBUS_ERROR(&err); 451 } else 452 LOGE("DBus reply is NULL in function %s", __FUNCTION__); 453 return JNI_FALSE; 454 } else { 455 result = JNI_TRUE; 456 } 457 dbus_message_unref(reply); 458 } 459 #endif 460 return JNI_FALSE; 461 } 462 463 static jboolean removeDeviceNative(JNIEnv *env, jobject object, jstring object_path) { 464 LOGV(__FUNCTION__); 465 #ifdef HAVE_BLUETOOTH 466 native_data_t *nat = get_native_data(env, object); 467 if (nat) { 468 const char *c_object_path = env->GetStringUTFChars(object_path, NULL); 469 bool ret = dbus_func_args_async(env, nat->conn, -1, 470 NULL, 471 NULL, 472 NULL, 473 get_adapter_path(env, object), 474 DBUS_ADAPTER_IFACE, 475 "RemoveDevice", 476 DBUS_TYPE_OBJECT_PATH, &c_object_path, 477 DBUS_TYPE_INVALID); 478 env->ReleaseStringUTFChars(object_path, c_object_path); 479 return ret ? JNI_TRUE : JNI_FALSE; 480 } 481 #endif 482 return JNI_FALSE; 483 } 484 485 static jint enableNative(JNIEnv *env, jobject object) { 486 #ifdef HAVE_BLUETOOTH 487 LOGV(__FUNCTION__); 488 return bt_enable(); 489 #endif 490 return -1; 491 } 492 493 static jint disableNative(JNIEnv *env, jobject object) { 494 #ifdef HAVE_BLUETOOTH 495 LOGV(__FUNCTION__); 496 return bt_disable(); 497 #endif 498 return -1; 499 } 500 501 static jint isEnabledNative(JNIEnv *env, jobject object) { 502 #ifdef HAVE_BLUETOOTH 503 LOGV(__FUNCTION__); 504 return bt_is_enabled(); 505 #endif 506 return -1; 507 } 508 509 static jboolean setPairingConfirmationNative(JNIEnv *env, jobject object, 510 jstring address, bool confirm, 511 int nativeData) { 512 #ifdef HAVE_BLUETOOTH 513 LOGV(__FUNCTION__); 514 native_data_t *nat = get_native_data(env, object); 515 if (nat) { 516 DBusMessage *msg = (DBusMessage *)nativeData; 517 DBusMessage *reply; 518 if (confirm) { 519 reply = dbus_message_new_method_return(msg); 520 } else { 521 reply = dbus_message_new_error(msg, 522 "org.bluez.Error.Rejected", "User rejected confirmation"); 523 } 524 525 if (!reply) { 526 LOGE("%s: Cannot create message reply to RequestPasskeyConfirmation or" 527 "RequestPairingConsent to D-Bus\n", __FUNCTION__); 528 dbus_message_unref(msg); 529 return JNI_FALSE; 530 } 531 532 dbus_connection_send(nat->conn, reply, NULL); 533 dbus_message_unref(msg); 534 dbus_message_unref(reply); 535 return JNI_TRUE; 536 } 537 #endif 538 return JNI_FALSE; 539 } 540 541 static jboolean setPasskeyNative(JNIEnv *env, jobject object, jstring address, 542 int passkey, int nativeData) { 543 #ifdef HAVE_BLUETOOTH 544 LOGV(__FUNCTION__); 545 native_data_t *nat = get_native_data(env, object); 546 if (nat) { 547 DBusMessage *msg = (DBusMessage *)nativeData; 548 DBusMessage *reply = dbus_message_new_method_return(msg); 549 if (!reply) { 550 LOGE("%s: Cannot create message reply to return Passkey code to " 551 "D-Bus\n", __FUNCTION__); 552 dbus_message_unref(msg); 553 return JNI_FALSE; 554 } 555 556 dbus_message_append_args(reply, DBUS_TYPE_UINT32, (uint32_t *)&passkey, 557 DBUS_TYPE_INVALID); 558 559 dbus_connection_send(nat->conn, reply, NULL); 560 dbus_message_unref(msg); 561 dbus_message_unref(reply); 562 return JNI_TRUE; 563 } 564 #endif 565 return JNI_FALSE; 566 } 567 568 static jboolean setRemoteOutOfBandDataNative(JNIEnv *env, jobject object, jstring address, 569 jbyteArray hash, jbyteArray randomizer, int nativeData) { 570 #ifdef HAVE_BLUETOOTH 571 LOGV(__FUNCTION__); 572 native_data_t *nat = get_native_data(env, object); 573 if (nat) { 574 DBusMessage *msg = (DBusMessage *)nativeData; 575 DBusMessage *reply = dbus_message_new_method_return(msg); 576 jbyte *h_ptr = env->GetByteArrayElements(hash, NULL); 577 jbyte *r_ptr = env->GetByteArrayElements(randomizer, NULL); 578 if (!reply) { 579 LOGE("%s: Cannot create message reply to return remote OOB data to " 580 "D-Bus\n", __FUNCTION__); 581 dbus_message_unref(msg); 582 return JNI_FALSE; 583 } 584 585 dbus_message_append_args(reply, 586 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &h_ptr, 16, 587 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &r_ptr, 16, 588 DBUS_TYPE_INVALID); 589 590 env->ReleaseByteArrayElements(hash, h_ptr, 0); 591 env->ReleaseByteArrayElements(randomizer, r_ptr, 0); 592 593 dbus_connection_send(nat->conn, reply, NULL); 594 dbus_message_unref(msg); 595 dbus_message_unref(reply); 596 return JNI_TRUE; 597 } 598 #endif 599 return JNI_FALSE; 600 } 601 602 static jboolean setAuthorizationNative(JNIEnv *env, jobject object, jstring address, 603 jboolean val, int nativeData) { 604 #ifdef HAVE_BLUETOOTH 605 LOGV(__FUNCTION__); 606 native_data_t *nat = get_native_data(env, object); 607 if (nat) { 608 DBusMessage *msg = (DBusMessage *)nativeData; 609 DBusMessage *reply; 610 if (val) { 611 reply = dbus_message_new_method_return(msg); 612 } else { 613 reply = dbus_message_new_error(msg, 614 "org.bluez.Error.Rejected", "Authorization rejected"); 615 } 616 if (!reply) { 617 LOGE("%s: Cannot create message reply D-Bus\n", __FUNCTION__); 618 dbus_message_unref(msg); 619 return JNI_FALSE; 620 } 621 622 dbus_connection_send(nat->conn, reply, NULL); 623 dbus_message_unref(msg); 624 dbus_message_unref(reply); 625 return JNI_TRUE; 626 } 627 #endif 628 return JNI_FALSE; 629 } 630 631 static jboolean setPinNative(JNIEnv *env, jobject object, jstring address, 632 jstring pin, int nativeData) { 633 #ifdef HAVE_BLUETOOTH 634 LOGV(__FUNCTION__); 635 native_data_t *nat = get_native_data(env, object); 636 if (nat) { 637 DBusMessage *msg = (DBusMessage *)nativeData; 638 DBusMessage *reply = dbus_message_new_method_return(msg); 639 if (!reply) { 640 LOGE("%s: Cannot create message reply to return PIN code to " 641 "D-Bus\n", __FUNCTION__); 642 dbus_message_unref(msg); 643 return JNI_FALSE; 644 } 645 646 const char *c_pin = env->GetStringUTFChars(pin, NULL); 647 648 dbus_message_append_args(reply, DBUS_TYPE_STRING, &c_pin, 649 DBUS_TYPE_INVALID); 650 651 dbus_connection_send(nat->conn, reply, NULL); 652 dbus_message_unref(msg); 653 dbus_message_unref(reply); 654 env->ReleaseStringUTFChars(pin, c_pin); 655 return JNI_TRUE; 656 } 657 #endif 658 return JNI_FALSE; 659 } 660 661 static jboolean cancelPairingUserInputNative(JNIEnv *env, jobject object, 662 jstring address, int nativeData) { 663 #ifdef HAVE_BLUETOOTH 664 LOGV(__FUNCTION__); 665 native_data_t *nat = get_native_data(env, object); 666 if (nat) { 667 DBusMessage *msg = (DBusMessage *)nativeData; 668 DBusMessage *reply = dbus_message_new_error(msg, 669 "org.bluez.Error.Canceled", "Pairing User Input was canceled"); 670 if (!reply) { 671 LOGE("%s: Cannot create message reply to return cancelUserInput to" 672 "D-BUS\n", __FUNCTION__); 673 dbus_message_unref(msg); 674 return JNI_FALSE; 675 } 676 677 dbus_connection_send(nat->conn, reply, NULL); 678 dbus_message_unref(msg); 679 dbus_message_unref(reply); 680 return JNI_TRUE; 681 } 682 #endif 683 return JNI_FALSE; 684 } 685 686 static jobjectArray getDevicePropertiesNative(JNIEnv *env, jobject object, 687 jstring path) 688 { 689 #ifdef HAVE_BLUETOOTH 690 LOGV(__FUNCTION__); 691 native_data_t *nat = get_native_data(env, object); 692 if (nat) { 693 DBusMessage *msg, *reply; 694 DBusError err; 695 dbus_error_init(&err); 696 697 const char *c_path = env->GetStringUTFChars(path, NULL); 698 reply = dbus_func_args_timeout(env, 699 nat->conn, -1, c_path, 700 DBUS_DEVICE_IFACE, "GetProperties", 701 DBUS_TYPE_INVALID); 702 env->ReleaseStringUTFChars(path, c_path); 703 704 if (!reply) { 705 if (dbus_error_is_set(&err)) { 706 LOG_AND_FREE_DBUS_ERROR(&err); 707 } else 708 LOGE("DBus reply is NULL in function %s", __FUNCTION__); 709 return NULL; 710 } 711 env->PushLocalFrame(PROPERTIES_NREFS); 712 713 DBusMessageIter iter; 714 jobjectArray str_array = NULL; 715 if (dbus_message_iter_init(reply, &iter)) 716 str_array = parse_remote_device_properties(env, &iter); 717 dbus_message_unref(reply); 718 719 env->PopLocalFrame(NULL); 720 721 return str_array; 722 } 723 #endif 724 return NULL; 725 } 726 727 static jobjectArray getAdapterPropertiesNative(JNIEnv *env, jobject object) { 728 #ifdef HAVE_BLUETOOTH 729 LOGV(__FUNCTION__); 730 native_data_t *nat = get_native_data(env, object); 731 if (nat) { 732 DBusMessage *msg, *reply; 733 DBusError err; 734 dbus_error_init(&err); 735 736 reply = dbus_func_args_timeout(env, 737 nat->conn, -1, get_adapter_path(env, object), 738 DBUS_ADAPTER_IFACE, "GetProperties", 739 DBUS_TYPE_INVALID); 740 if (!reply) { 741 if (dbus_error_is_set(&err)) { 742 LOG_AND_FREE_DBUS_ERROR(&err); 743 } else 744 LOGE("DBus reply is NULL in function %s", __FUNCTION__); 745 return NULL; 746 } 747 env->PushLocalFrame(PROPERTIES_NREFS); 748 749 DBusMessageIter iter; 750 jobjectArray str_array = NULL; 751 if (dbus_message_iter_init(reply, &iter)) 752 str_array = parse_adapter_properties(env, &iter); 753 dbus_message_unref(reply); 754 755 env->PopLocalFrame(NULL); 756 return str_array; 757 } 758 #endif 759 return NULL; 760 } 761 762 static jboolean setAdapterPropertyNative(JNIEnv *env, jobject object, jstring key, 763 void *value, jint type) { 764 #ifdef HAVE_BLUETOOTH 765 LOGV(__FUNCTION__); 766 native_data_t *nat = get_native_data(env, object); 767 if (nat) { 768 DBusMessage *reply, *msg; 769 DBusMessageIter iter; 770 DBusError err; 771 const char *c_key = env->GetStringUTFChars(key, NULL); 772 dbus_error_init(&err); 773 774 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, 775 get_adapter_path(env, object), 776 DBUS_ADAPTER_IFACE, "SetProperty"); 777 if (!msg) { 778 LOGE("%s: Can't allocate new method call for GetProperties!", 779 __FUNCTION__); 780 env->ReleaseStringUTFChars(key, c_key); 781 return JNI_FALSE; 782 } 783 784 dbus_message_append_args(msg, DBUS_TYPE_STRING, &c_key, DBUS_TYPE_INVALID); 785 dbus_message_iter_init_append(msg, &iter); 786 append_variant(&iter, type, value); 787 788 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err); 789 dbus_message_unref(msg); 790 791 env->ReleaseStringUTFChars(key, c_key); 792 793 if (!reply) { 794 if (dbus_error_is_set(&err)) { 795 LOG_AND_FREE_DBUS_ERROR(&err); 796 } else 797 LOGE("DBus reply is NULL in function %s", __FUNCTION__); 798 return JNI_FALSE; 799 } 800 return JNI_TRUE; 801 } 802 #endif 803 return JNI_FALSE; 804 } 805 806 static jboolean setAdapterPropertyStringNative(JNIEnv *env, jobject object, jstring key, 807 jstring value) { 808 #ifdef HAVE_BLUETOOTH 809 const char *c_value = env->GetStringUTFChars(value, NULL); 810 jboolean ret = setAdapterPropertyNative(env, object, key, (void *)&c_value, DBUS_TYPE_STRING); 811 env->ReleaseStringUTFChars(value, (char *)c_value); 812 return ret; 813 #else 814 return JNI_FALSE; 815 #endif 816 } 817 818 static jboolean setAdapterPropertyIntegerNative(JNIEnv *env, jobject object, jstring key, 819 jint value) { 820 #ifdef HAVE_BLUETOOTH 821 return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_UINT32); 822 #else 823 return JNI_FALSE; 824 #endif 825 } 826 827 static jboolean setAdapterPropertyBooleanNative(JNIEnv *env, jobject object, jstring key, 828 jint value) { 829 #ifdef HAVE_BLUETOOTH 830 return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_BOOLEAN); 831 #else 832 return JNI_FALSE; 833 #endif 834 } 835 836 static jboolean setDevicePropertyNative(JNIEnv *env, jobject object, jstring path, 837 jstring key, void *value, jint type) { 838 #ifdef HAVE_BLUETOOTH 839 LOGV(__FUNCTION__); 840 native_data_t *nat = get_native_data(env, object); 841 if (nat) { 842 DBusMessage *reply, *msg; 843 DBusMessageIter iter; 844 DBusError err; 845 846 const char *c_key = env->GetStringUTFChars(key, NULL); 847 const char *c_path = env->GetStringUTFChars(path, NULL); 848 849 dbus_error_init(&err); 850 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, 851 c_path, DBUS_DEVICE_IFACE, "SetProperty"); 852 if (!msg) { 853 LOGE("%s: Can't allocate new method call for device SetProperty!", __FUNCTION__); 854 env->ReleaseStringUTFChars(key, c_key); 855 env->ReleaseStringUTFChars(path, c_path); 856 return JNI_FALSE; 857 } 858 859 dbus_message_append_args(msg, DBUS_TYPE_STRING, &c_key, DBUS_TYPE_INVALID); 860 dbus_message_iter_init_append(msg, &iter); 861 append_variant(&iter, type, value); 862 863 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err); 864 dbus_message_unref(msg); 865 866 env->ReleaseStringUTFChars(key, c_key); 867 env->ReleaseStringUTFChars(path, c_path); 868 if (!reply) { 869 if (dbus_error_is_set(&err)) { 870 LOG_AND_FREE_DBUS_ERROR(&err); 871 } else 872 LOGE("DBus reply is NULL in function %s", __FUNCTION__); 873 return JNI_FALSE; 874 } 875 return JNI_TRUE; 876 } 877 #endif 878 return JNI_FALSE; 879 } 880 881 static jboolean setDevicePropertyBooleanNative(JNIEnv *env, jobject object, 882 jstring path, jstring key, jint value) { 883 #ifdef HAVE_BLUETOOTH 884 return setDevicePropertyNative(env, object, path, key, 885 (void *)&value, DBUS_TYPE_BOOLEAN); 886 #else 887 return JNI_FALSE; 888 #endif 889 } 890 891 892 static jboolean createDeviceNative(JNIEnv *env, jobject object, 893 jstring address) { 894 LOGV(__FUNCTION__); 895 #ifdef HAVE_BLUETOOTH 896 native_data_t *nat = get_native_data(env, object); 897 jobject eventLoop = env->GetObjectField(object, field_mEventLoop); 898 struct event_loop_native_data_t *eventLoopNat = 899 get_EventLoop_native_data(env, eventLoop); 900 901 if (nat && eventLoopNat) { 902 const char *c_address = env->GetStringUTFChars(address, NULL); 903 LOGV("... address = %s", c_address); 904 char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char)); 905 strlcpy(context_address, c_address, BTADDR_SIZE); // for callback 906 907 bool ret = dbus_func_args_async(env, nat->conn, -1, 908 onCreateDeviceResult, 909 context_address, 910 eventLoopNat, 911 get_adapter_path(env, object), 912 DBUS_ADAPTER_IFACE, 913 "CreateDevice", 914 DBUS_TYPE_STRING, &c_address, 915 DBUS_TYPE_INVALID); 916 env->ReleaseStringUTFChars(address, c_address); 917 return ret ? JNI_TRUE : JNI_FALSE; 918 } 919 #endif 920 return JNI_FALSE; 921 } 922 923 static jboolean discoverServicesNative(JNIEnv *env, jobject object, 924 jstring path, jstring pattern) { 925 LOGV(__FUNCTION__); 926 #ifdef HAVE_BLUETOOTH 927 native_data_t *nat = get_native_data(env, object); 928 jobject eventLoop = env->GetObjectField(object, field_mEventLoop); 929 struct event_loop_native_data_t *eventLoopNat = 930 get_EventLoop_native_data(env, eventLoop); 931 932 if (nat && eventLoopNat) { 933 const char *c_path = env->GetStringUTFChars(path, NULL); 934 const char *c_pattern = env->GetStringUTFChars(pattern, NULL); 935 int len = env->GetStringLength(path) + 1; 936 char *context_path = (char *)calloc(len, sizeof(char)); 937 strlcpy(context_path, c_path, len); // for callback 938 939 LOGV("... Object Path = %s", c_path); 940 LOGV("... Pattern = %s, strlen = %d", c_pattern, strlen(c_pattern)); 941 942 bool ret = dbus_func_args_async(env, nat->conn, -1, 943 onDiscoverServicesResult, 944 context_path, 945 eventLoopNat, 946 c_path, 947 DBUS_DEVICE_IFACE, 948 "DiscoverServices", 949 DBUS_TYPE_STRING, &c_pattern, 950 DBUS_TYPE_INVALID); 951 env->ReleaseStringUTFChars(path, c_path); 952 env->ReleaseStringUTFChars(pattern, c_pattern); 953 return ret ? JNI_TRUE : JNI_FALSE; 954 } 955 #endif 956 return JNI_FALSE; 957 } 958 959 static jint addRfcommServiceRecordNative(JNIEnv *env, jobject object, 960 jstring name, jlong uuidMsb, jlong uuidLsb, jshort channel) { 961 LOGV(__FUNCTION__); 962 #ifdef HAVE_BLUETOOTH 963 native_data_t *nat = get_native_data(env, object); 964 if (nat) { 965 const char *c_name = env->GetStringUTFChars(name, NULL); 966 LOGV("... name = %s", c_name); 967 LOGV("... uuid1 = %llX", uuidMsb); 968 LOGV("... uuid2 = %llX", uuidLsb); 969 LOGV("... channel = %d", channel); 970 DBusMessage *reply = dbus_func_args(env, nat->conn, 971 get_adapter_path(env, object), 972 DBUS_ADAPTER_IFACE, "AddRfcommServiceRecord", 973 DBUS_TYPE_STRING, &c_name, 974 DBUS_TYPE_UINT64, &uuidMsb, 975 DBUS_TYPE_UINT64, &uuidLsb, 976 DBUS_TYPE_UINT16, &channel, 977 DBUS_TYPE_INVALID); 978 env->ReleaseStringUTFChars(name, c_name); 979 return reply ? dbus_returns_uint32(env, reply) : -1; 980 } 981 #endif 982 return -1; 983 } 984 985 static jboolean removeServiceRecordNative(JNIEnv *env, jobject object, jint handle) { 986 LOGV(__FUNCTION__); 987 #ifdef HAVE_BLUETOOTH 988 native_data_t *nat = get_native_data(env, object); 989 if (nat) { 990 LOGV("... handle = %X", handle); 991 DBusMessage *reply = dbus_func_args(env, nat->conn, 992 get_adapter_path(env, object), 993 DBUS_ADAPTER_IFACE, "RemoveServiceRecord", 994 DBUS_TYPE_UINT32, &handle, 995 DBUS_TYPE_INVALID); 996 return reply ? JNI_TRUE : JNI_FALSE; 997 } 998 #endif 999 return JNI_FALSE; 1000 } 1001 1002 static jboolean setLinkTimeoutNative(JNIEnv *env, jobject object, jstring object_path, 1003 jint num_slots) { 1004 LOGV(__FUNCTION__); 1005 #ifdef HAVE_BLUETOOTH 1006 native_data_t *nat = get_native_data(env, object); 1007 if (nat) { 1008 const char *c_object_path = env->GetStringUTFChars(object_path, NULL); 1009 DBusMessage *reply = dbus_func_args(env, nat->conn, 1010 get_adapter_path(env, object), 1011 DBUS_ADAPTER_IFACE, "SetLinkTimeout", 1012 DBUS_TYPE_OBJECT_PATH, &c_object_path, 1013 DBUS_TYPE_UINT32, &num_slots, 1014 DBUS_TYPE_INVALID); 1015 env->ReleaseStringUTFChars(object_path, c_object_path); 1016 return reply ? JNI_TRUE : JNI_FALSE; 1017 } 1018 #endif 1019 return JNI_FALSE; 1020 } 1021 1022 static JNINativeMethod sMethods[] = { 1023 /* name, signature, funcPtr */ 1024 {"classInitNative", "()V", (void*)classInitNative}, 1025 {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative}, 1026 {"setupNativeDataNative", "()Z", (void *)setupNativeDataNative}, 1027 {"tearDownNativeDataNative", "()Z", (void *)tearDownNativeDataNative}, 1028 {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative}, 1029 {"getAdapterPathNative", "()Ljava/lang/String;", (void*)getAdapterPathNative}, 1030 1031 {"isEnabledNative", "()I", (void *)isEnabledNative}, 1032 {"enableNative", "()I", (void *)enableNative}, 1033 {"disableNative", "()I", (void *)disableNative}, 1034 1035 {"getAdapterPropertiesNative", "()[Ljava/lang/Object;", (void *)getAdapterPropertiesNative}, 1036 {"getDevicePropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;", 1037 (void *)getDevicePropertiesNative}, 1038 {"setAdapterPropertyStringNative", "(Ljava/lang/String;Ljava/lang/String;)Z", 1039 (void *)setAdapterPropertyStringNative}, 1040 {"setAdapterPropertyBooleanNative", "(Ljava/lang/String;I)Z", 1041 (void *)setAdapterPropertyBooleanNative}, 1042 {"setAdapterPropertyIntegerNative", "(Ljava/lang/String;I)Z", 1043 (void *)setAdapterPropertyIntegerNative}, 1044 1045 {"startDiscoveryNative", "()Z", (void*)startDiscoveryNative}, 1046 {"stopDiscoveryNative", "()Z", (void *)stopDiscoveryNative}, 1047 1048 {"readAdapterOutOfBandDataNative", "()[B", (void *)readAdapterOutOfBandDataNative}, 1049 {"createPairedDeviceNative", "(Ljava/lang/String;I)Z", (void *)createPairedDeviceNative}, 1050 {"createPairedDeviceOutOfBandNative", "(Ljava/lang/String;I)Z", 1051 (void *)createPairedDeviceOutOfBandNative}, 1052 {"cancelDeviceCreationNative", "(Ljava/lang/String;)Z", (void *)cancelDeviceCreationNative}, 1053 {"removeDeviceNative", "(Ljava/lang/String;)Z", (void *)removeDeviceNative}, 1054 {"getDeviceServiceChannelNative", "(Ljava/lang/String;Ljava/lang/String;I)I", 1055 (void *)getDeviceServiceChannelNative}, 1056 1057 {"setPairingConfirmationNative", "(Ljava/lang/String;ZI)Z", 1058 (void *)setPairingConfirmationNative}, 1059 {"setPasskeyNative", "(Ljava/lang/String;II)Z", (void *)setPasskeyNative}, 1060 {"setRemoteOutOfBandDataNative", "(Ljava/lang/String;[B[BI)Z", (void *)setRemoteOutOfBandDataNative}, 1061 {"setAuthorizationNative", "(Ljava/lang/String;ZI)Z", (void *)setAuthorizationNative}, 1062 {"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative}, 1063 {"cancelPairingUserInputNative", "(Ljava/lang/String;I)Z", 1064 (void *)cancelPairingUserInputNative}, 1065 {"setDevicePropertyBooleanNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", 1066 (void *)setDevicePropertyBooleanNative}, 1067 {"createDeviceNative", "(Ljava/lang/String;)Z", (void *)createDeviceNative}, 1068 {"discoverServicesNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)discoverServicesNative}, 1069 {"addRfcommServiceRecordNative", "(Ljava/lang/String;JJS)I", (void *)addRfcommServiceRecordNative}, 1070 {"removeServiceRecordNative", "(I)Z", (void *)removeServiceRecordNative}, 1071 {"setLinkTimeoutNative", "(Ljava/lang/String;I)Z", (void *)setLinkTimeoutNative}, 1072 }; 1073 1074 int register_android_server_BluetoothService(JNIEnv *env) { 1075 return AndroidRuntime::registerNativeMethods(env, 1076 "android/server/BluetoothService", sMethods, NELEM(sMethods)); 1077 } 1078 1079 } /* namespace android */ 1080