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_CLASS_NAME BLUEZ_DBUS_BASE_IFC ".Adapter" 18#define LOG_TAG "BluetoothDeviceService.cpp" 19 20#include "android_bluetooth_common.h" 21#include "android_runtime/AndroidRuntime.h" 22#include "JNIHelp.h" 23#include "jni.h" 24#include "utils/Log.h" 25#include "utils/misc.h" 26 27#include <ctype.h> 28#include <stdio.h> 29#include <string.h> 30#include <stdlib.h> 31#include <errno.h> 32#include <unistd.h> 33 34#include <sys/socket.h> 35#include <sys/ioctl.h> 36#include <fcntl.h> 37 38#ifdef HAVE_BLUETOOTH 39#include <dbus/dbus.h> 40#include <bluedroid/bluetooth.h> 41#endif 42 43#include <cutils/properties.h> 44 45namespace android { 46 47#define BLUETOOTH_CLASS_ERROR 0xFF000000 48 49#ifdef HAVE_BLUETOOTH 50// We initialize these variables when we load class 51// android.server.BluetoothDeviceService 52static jfieldID field_mNativeData; 53static jfieldID field_mEventLoop; 54 55typedef struct { 56 JNIEnv *env; 57 DBusConnection *conn; 58 const char *adapter; // dbus object name of the local adapter 59} native_data_t; 60 61extern event_loop_native_data_t *get_EventLoop_native_data(JNIEnv *, 62 jobject); 63void onCreateBondingResult(DBusMessage *msg, void *user, void *nat); 64void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user, void *nat); 65 66/** Get native data stored in the opaque (Java code maintained) pointer mNativeData 67 * Perform quick sanity check, if there are any problems return NULL 68 */ 69static inline native_data_t * get_native_data(JNIEnv *env, jobject object) { 70 native_data_t *nat = 71 (native_data_t *)(env->GetIntField(object, field_mNativeData)); 72 if (nat == NULL || nat->conn == NULL) { 73 LOGE("Uninitialized native data\n"); 74 return NULL; 75 } 76 return nat; 77} 78#endif 79 80static void classInitNative(JNIEnv* env, jclass clazz) { 81 LOGV(__FUNCTION__); 82#ifdef HAVE_BLUETOOTH 83 field_mNativeData = get_field(env, clazz, "mNativeData", "I"); 84 field_mEventLoop = get_field(env, clazz, "mEventLoop", 85 "Landroid/server/BluetoothEventLoop;"); 86#endif 87} 88 89/* Returns true on success (even if adapter is present but disabled). 90 * Return false if dbus is down, or another serious error (out of memory) 91*/ 92static bool initializeNativeDataNative(JNIEnv* env, jobject object) { 93 LOGV(__FUNCTION__); 94#ifdef HAVE_BLUETOOTH 95 native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t)); 96 if (NULL == nat) { 97 LOGE("%s: out of memory!", __FUNCTION__); 98 return false; 99 } 100 nat->env = env; 101 102 env->SetIntField(object, field_mNativeData, (jint)nat); 103 DBusError err; 104 dbus_error_init(&err); 105 dbus_threads_init_default(); 106 nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); 107 if (dbus_error_is_set(&err)) { 108 LOGE("Could not get onto the system bus: %s", err.message); 109 dbus_error_free(&err); 110 return false; 111 } 112 dbus_connection_set_exit_on_disconnect(nat->conn, FALSE); 113 114 nat->adapter = BLUEZ_ADAPTER_OBJECT_NAME; 115#endif /*HAVE_BLUETOOTH*/ 116 return true; 117} 118 119static void cleanupNativeDataNative(JNIEnv* env, jobject object) { 120 LOGV(__FUNCTION__); 121#ifdef HAVE_BLUETOOTH 122 native_data_t *nat = 123 (native_data_t *)env->GetIntField(object, field_mNativeData); 124 if (nat) { 125 free(nat); 126 nat = NULL; 127 } 128#endif 129} 130 131static jstring getNameNative(JNIEnv *env, jobject object){ 132 LOGV(__FUNCTION__); 133#ifdef HAVE_BLUETOOTH 134 native_data_t *nat = get_native_data(env, object); 135 if (nat) { 136 DBusMessage *reply = dbus_func_args(env, nat->conn, nat->adapter, 137 DBUS_CLASS_NAME, "GetName", 138 DBUS_TYPE_INVALID); 139 return reply ? dbus_returns_string(env, reply) : NULL; 140 } 141#endif 142 return NULL; 143} 144 145static jstring getAdapterPathNative(JNIEnv *env, jobject object) { 146 LOGV(__FUNCTION__); 147#ifdef HAVE_BLUETOOTH 148 native_data_t *nat = get_native_data(env, object); 149 if (nat) { 150 return (env->NewStringUTF(nat->adapter)); 151 } 152#endif 153 return NULL; 154} 155 156 157static jboolean startDiscoveryNative(JNIEnv *env, jobject object) { 158 LOGV(__FUNCTION__); 159#ifdef HAVE_BLUETOOTH 160 DBusMessage *msg = NULL; 161 DBusMessage *reply = NULL; 162 DBusError err; 163 const char *name; 164 jboolean ret = JNI_FALSE; 165 166 native_data_t *nat = get_native_data(env, object); 167 if (nat == NULL) { 168 goto done; 169 } 170 171 dbus_error_init(&err); 172 173 /* Compose the command */ 174 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter, 175 DBUS_CLASS_NAME, "DiscoverDevices"); 176 177 if (msg == NULL) { 178 LOGE("%s: Could not allocate D-Bus message object!", __FUNCTION__); 179 goto done; 180 } 181 182 /* Send the command. */ 183 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err); 184 if (dbus_error_is_set(&err)) { 185 /* We treat the in-progress error code as success. */ 186 if(strcmp(err.message, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") == 0) { 187 LOGW("%s: D-Bus error: %s, treating as startDiscoveryNative success\n", 188 __FUNCTION__, err.message); 189 ret = JNI_TRUE; 190 goto done; 191 } else { 192 LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message); 193 ret = JNI_FALSE; 194 goto done; 195 } 196 } 197 198 ret = JNI_TRUE; 199done: 200 if (reply) dbus_message_unref(reply); 201 if (msg) dbus_message_unref(msg); 202 return ret; 203#else 204 return JNI_FALSE; 205#endif 206} 207 208static void cancelDiscoveryNative(JNIEnv *env, jobject object) { 209 LOGV(__FUNCTION__); 210#ifdef HAVE_BLUETOOTH 211 DBusMessage *msg = NULL; 212 DBusMessage *reply = NULL; 213 DBusError err; 214 const char *name; 215 jstring ret; 216 native_data_t *nat; 217 218 dbus_error_init(&err); 219 220 nat = get_native_data(env, object); 221 if (nat == NULL) { 222 goto done; 223 } 224 225 /* Compose the command */ 226 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter, 227 DBUS_CLASS_NAME, "CancelDiscovery"); 228 229 if (msg == NULL) { 230 LOGE("%s: Could not allocate D-Bus message object!", __FUNCTION__); 231 goto done; 232 } 233 234 /* Send the command. */ 235 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err); 236 if (dbus_error_is_set(&err)) { 237 if(strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized") == 0) { 238 // hcid sends this if there is no active discovery to cancel 239 LOGV("%s: There was no active discovery to cancel", __FUNCTION__); 240 dbus_error_free(&err); 241 } else { 242 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg); 243 } 244 } 245 246done: 247 if (msg) dbus_message_unref(msg); 248 if (reply) dbus_message_unref(reply); 249#endif 250} 251 252static jboolean startPeriodicDiscoveryNative(JNIEnv *env, jobject object) { 253 LOGV(__FUNCTION__); 254#ifdef HAVE_BLUETOOTH 255 DBusMessage *msg = NULL; 256 DBusMessage *reply = NULL; 257 DBusError err; 258 jboolean ret = JNI_FALSE; 259 260 native_data_t *nat = get_native_data(env, object); 261 if (nat == NULL) { 262 goto done; 263 } 264 265 dbus_error_init(&err); 266 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter, 267 DBUS_CLASS_NAME, "StartPeriodicDiscovery"); 268 if (msg == NULL) { 269 LOGE("%s: Could not allocate DBUS message object\n", __FUNCTION__); 270 goto done; 271 } 272 273 /* Send the command. */ 274 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err); 275 if (dbus_error_is_set(&err)) { 276 /* We treat the in-progress error code as success. */ 277 if(strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") == 0) { 278 LOGW("%s: D-Bus error: %s (%s), treating as " 279 "startPeriodicDiscoveryNative success\n", 280 __FUNCTION__, err.name, err.message); 281 } else { 282 LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message); 283 ret = JNI_FALSE; 284 goto done; 285 } 286 } 287 288 ret = JNI_TRUE; 289done: 290 if (reply) dbus_message_unref(reply); 291 if (msg) dbus_message_unref(msg); 292 return ret; 293#else 294 return JNI_FALSE; 295#endif 296} 297 298static jboolean stopPeriodicDiscoveryNative(JNIEnv *env, jobject object) { 299 LOGV(__FUNCTION__); 300#ifdef HAVE_BLUETOOTH 301 DBusMessage *msg = NULL; 302 DBusMessage *reply = NULL; 303 DBusError err; 304 const char *name; 305 jboolean ret = JNI_FALSE; 306 307 native_data_t *nat = get_native_data(env, object); 308 if (nat == NULL) { 309 goto done; 310 } 311 312 dbus_error_init(&err); 313 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, nat->adapter, 314 DBUS_CLASS_NAME, "StopPeriodicDiscovery"); 315 if (msg == NULL) { 316 LOGE("%s: Could not allocate DBUS message object\n", __FUNCTION__); 317 goto done; 318 } 319 320 /* Send the command. */ 321 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err); 322 if (dbus_error_is_set(&err)) { 323 /* We treat the in-progress error code as success. */ 324 if(strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") == 0) { 325 LOGW("%s: D-Bus error: %s (%s), treating as " 326 "stopPeriodicDiscoveryNative success\n", 327 __FUNCTION__, err.name, err.message); 328 } else { 329 LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message); 330 ret = JNI_FALSE; 331 goto done; 332 } 333 } 334 335 ret = JNI_TRUE; 336done: 337 if (reply) dbus_message_unref(reply); 338 if (msg) dbus_message_unref(msg); 339 return ret; 340#else 341 return JNI_FALSE; 342#endif 343} 344 345static jboolean isPeriodicDiscoveryNative(JNIEnv *env, jobject object) { 346#ifdef HAVE_BLUETOOTH 347 LOGV(__FUNCTION__); 348 native_data_t *nat = get_native_data(env, object); 349 if (nat) { 350 DBusMessage *reply = 351 dbus_func_args(env, nat->conn, nat->adapter, 352 DBUS_CLASS_NAME, "IsPeriodicDiscovery", 353 DBUS_TYPE_INVALID); 354 return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE; 355 } 356#endif 357 return JNI_FALSE; 358} 359 360static jboolean setDiscoverableTimeoutNative(JNIEnv *env, jobject object, jint timeout_s) { 361#ifdef HAVE_BLUETOOTH 362 LOGV(__FUNCTION__); 363 364 if (timeout_s < 0) { 365 return JNI_FALSE; 366 } 367 368 native_data_t *nat = get_native_data(env, object); 369 if (nat) { 370 DBusMessage *reply = 371 dbus_func_args(env, nat->conn, nat->adapter, 372 DBUS_CLASS_NAME, "SetDiscoverableTimeout", 373 DBUS_TYPE_UINT32, &timeout_s, 374 DBUS_TYPE_INVALID); 375 if (reply != NULL) { 376 dbus_message_unref(reply); 377 return JNI_TRUE; 378 } 379 } 380#endif 381 return JNI_FALSE; 382} 383 384static jint getDiscoverableTimeoutNative(JNIEnv *env, jobject object) { 385#ifdef HAVE_BLUETOOTH 386 LOGV(__FUNCTION__); 387 native_data_t *nat = get_native_data(env, object); 388 if (nat) { 389 DBusMessage *reply = 390 dbus_func_args(env, nat->conn, nat->adapter, 391 DBUS_CLASS_NAME, "GetDiscoverableTimeout", 392 DBUS_TYPE_INVALID); 393 return reply ? dbus_returns_uint32(env, reply) : -1; 394 } 395#endif 396 return -1; 397} 398 399static jboolean isConnectedNative(JNIEnv *env, jobject object, jstring address) { 400#ifdef HAVE_BLUETOOTH 401 LOGV(__FUNCTION__); 402 native_data_t *nat = get_native_data(env, object); 403 if (nat) { 404 const char *c_address = env->GetStringUTFChars(address, NULL); 405 DBusMessage *reply = 406 dbus_func_args(env, nat->conn, nat->adapter, 407 DBUS_CLASS_NAME, "IsConnected", 408 DBUS_TYPE_STRING, &c_address, 409 DBUS_TYPE_INVALID); 410 env->ReleaseStringUTFChars(address, c_address); 411 return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE; 412 } 413#endif 414 return JNI_FALSE; 415} 416 417static void disconnectRemoteDeviceNative(JNIEnv *env, jobject object, jstring address) { 418#ifdef HAVE_BLUETOOTH 419 LOGV(__FUNCTION__); 420 native_data_t *nat = get_native_data(env, object); 421 if (nat) { 422 const char *c_address = env->GetStringUTFChars(address, NULL); 423 // Set a timeout of 5 seconds. Specifying the default timeout is 424 // not long enough, as a remote-device disconnect results in 425 // signal RemoteDisconnectRequested being sent, followed by a 426 // delay of 2 seconds, after which the actual disconnect takes 427 // place. 428 DBusMessage *reply = 429 dbus_func_args_timeout(env, nat->conn, 60000, nat->adapter, 430 DBUS_CLASS_NAME, "DisconnectRemoteDevice", 431 DBUS_TYPE_STRING, &c_address, 432 DBUS_TYPE_INVALID); 433 env->ReleaseStringUTFChars(address, c_address); 434 if (reply) dbus_message_unref(reply); 435 } 436#endif 437} 438 439static jstring getModeNative(JNIEnv *env, jobject object) { 440#ifdef HAVE_BLUETOOTH 441 LOGV(__FUNCTION__); 442 native_data_t *nat = get_native_data(env, object); 443 if (nat) { 444 DBusMessage *reply = 445 dbus_func_args(env, nat->conn, nat->adapter, 446 DBUS_CLASS_NAME, "GetMode", 447 DBUS_TYPE_INVALID); 448 return reply ? dbus_returns_string(env, reply) : NULL; 449 } 450#endif 451 return NULL; 452} 453 454static jboolean setModeNative(JNIEnv *env, jobject object, jstring mode) { 455#ifdef HAVE_BLUETOOTH 456 LOGV(__FUNCTION__); 457 native_data_t *nat = get_native_data(env, object); 458 if (nat) { 459 const char *c_mode = env->GetStringUTFChars(mode, NULL); 460 DBusMessage *reply = 461 dbus_func_args(env, nat->conn, nat->adapter, 462 DBUS_CLASS_NAME, "SetMode", 463 DBUS_TYPE_STRING, &c_mode, 464 DBUS_TYPE_INVALID); 465 env->ReleaseStringUTFChars(mode, c_mode); 466 if (reply) { 467 dbus_message_unref(reply); 468 return JNI_TRUE; 469 } 470 return JNI_FALSE; 471 } 472#endif 473 return JNI_FALSE; 474} 475 476static jboolean createBondingNative(JNIEnv *env, jobject object, 477 jstring address, jint timeout_ms) { 478 LOGV(__FUNCTION__); 479#ifdef HAVE_BLUETOOTH 480 native_data_t *nat = get_native_data(env, object); 481 jobject eventLoop = env->GetObjectField(object, field_mEventLoop); 482 struct event_loop_native_data_t *eventLoopNat = 483 get_EventLoop_native_data(env, eventLoop); 484 485 if (nat && eventLoopNat) { 486 const char *c_address = env->GetStringUTFChars(address, NULL); 487 LOGV("... address = %s", c_address); 488 char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char)); 489 strlcpy(context_address, c_address, BTADDR_SIZE); // for callback 490 bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms, 491 onCreateBondingResult, // callback 492 context_address, 493 eventLoopNat, 494 nat->adapter, 495 DBUS_CLASS_NAME, "CreateBonding", 496 DBUS_TYPE_STRING, &c_address, 497 DBUS_TYPE_INVALID); 498 env->ReleaseStringUTFChars(address, c_address); 499 return ret ? JNI_TRUE : JNI_FALSE; 500 501 } 502#endif 503 return JNI_FALSE; 504} 505 506static jboolean cancelBondingProcessNative(JNIEnv *env, jobject object, 507 jstring address) { 508 LOGV(__FUNCTION__); 509#ifdef HAVE_BLUETOOTH 510 native_data_t *nat = get_native_data(env, object); 511 if (nat) { 512 const char *c_address = env->GetStringUTFChars(address, NULL); 513 LOGV("... address = %s", c_address); 514 DBusMessage *reply = 515 dbus_func_args_timeout(env, nat->conn, -1, nat->adapter, 516 DBUS_CLASS_NAME, "CancelBondingProcess", 517 DBUS_TYPE_STRING, &c_address, 518 DBUS_TYPE_INVALID); 519 env->ReleaseStringUTFChars(address, c_address); 520 if (reply) { 521 dbus_message_unref(reply); 522 } 523 return JNI_TRUE; 524 } 525#endif 526 return JNI_FALSE; 527} 528 529static jboolean removeBondingNative(JNIEnv *env, jobject object, jstring address) { 530 LOGV(__FUNCTION__); 531 jboolean result = JNI_FALSE; 532#ifdef HAVE_BLUETOOTH 533 native_data_t *nat = get_native_data(env, object); 534 if (nat) { 535 const char *c_address = env->GetStringUTFChars(address, NULL); 536 LOGV("... address = %s", c_address); 537 DBusError err; 538 dbus_error_init(&err); 539 DBusMessage *reply = 540 dbus_func_args_error(env, nat->conn, &err, nat->adapter, 541 DBUS_CLASS_NAME, "RemoveBonding", 542 DBUS_TYPE_STRING, &c_address, 543 DBUS_TYPE_INVALID); 544 if (dbus_error_is_set(&err)) { 545 if (dbus_error_has_name(&err, 546 BLUEZ_DBUS_BASE_IFC ".Error.DoesNotExist")) { 547 LOGW("%s: Warning: %s (%s)", __FUNCTION__, err.message, 548 c_address); 549 result = JNI_TRUE; 550 } else { 551 LOGE("%s: D-Bus error %s (%s)", __FUNCTION__, err.name, 552 err.message); 553 } 554 } else { 555 result = JNI_TRUE; 556 } 557 558 env->ReleaseStringUTFChars(address, c_address); 559 dbus_error_free(&err); 560 if (reply) dbus_message_unref(reply); 561 } 562#endif 563 return result; 564} 565 566static jobjectArray listBondingsNative(JNIEnv *env, jobject object) { 567#ifdef HAVE_BLUETOOTH 568 LOGV(__FUNCTION__); 569 native_data_t *nat = get_native_data(env, object); 570 if (nat) { 571 DBusMessage *reply = 572 dbus_func_args(env, nat->conn, nat->adapter, 573 DBUS_CLASS_NAME, "ListBondings", 574 DBUS_TYPE_INVALID); 575 // return String[] 576 return reply ? dbus_returns_array_of_strings(env, reply) : NULL; 577 } 578#endif 579 return NULL; 580} 581 582static jobjectArray listConnectionsNative(JNIEnv *env, jobject object) { 583#ifdef HAVE_BLUETOOTH 584 LOGV(__FUNCTION__); 585 native_data_t *nat = get_native_data(env, object); 586 if (nat) { 587 DBusMessage *reply = 588 dbus_func_args(env, nat->conn, nat->adapter, 589 DBUS_CLASS_NAME, "ListConnections", 590 DBUS_TYPE_INVALID); 591 // return String[] 592 return reply ? dbus_returns_array_of_strings(env, reply) : NULL; 593 } 594#endif 595 return NULL; 596} 597 598static jobjectArray listRemoteDevicesNative(JNIEnv *env, jobject object) { 599#ifdef HAVE_BLUETOOTH 600 LOGV(__FUNCTION__); 601 native_data_t *nat = get_native_data(env, object); 602 if (nat) { 603 DBusMessage *reply = 604 dbus_func_args(env, nat->conn, nat->adapter, 605 DBUS_CLASS_NAME, "ListRemoteDevices", 606 DBUS_TYPE_INVALID); 607 return reply ? dbus_returns_array_of_strings(env, reply) : NULL; 608 } 609#endif 610 return NULL; 611} 612 613static jstring common_Get(JNIEnv *env, jobject object, const char *func) { 614 LOGV("%s:%s", __FUNCTION__, func); 615#ifdef HAVE_BLUETOOTH 616 native_data_t *nat = get_native_data(env, object); 617 if (nat) { 618 DBusError err; 619 dbus_error_init(&err); 620 DBusMessage *reply = 621 dbus_func_args_error(env, nat->conn, &err, nat->adapter, 622 DBUS_CLASS_NAME, func, 623 DBUS_TYPE_INVALID); 624 if (reply) { 625 return dbus_returns_string(env, reply); 626 } else { 627 LOG_AND_FREE_DBUS_ERROR(&err); 628 return NULL; 629 } 630 } 631#endif 632 return NULL; 633} 634 635static jstring getAddressNative(JNIEnv *env, jobject obj) { 636 return common_Get(env, obj, "GetAddress"); 637} 638 639static jstring getVersionNative(JNIEnv *env, jobject obj) { 640 return common_Get(env, obj, "GetVersion"); 641} 642 643static jstring getRevisionNative(JNIEnv *env, jobject obj) { 644 return common_Get(env, obj, "GetRevision"); 645} 646 647static jstring getManufacturerNative(JNIEnv *env, jobject obj) { 648 return common_Get(env, obj, "GetManufacturer"); 649} 650 651static jstring getCompanyNative(JNIEnv *env, jobject obj) { 652 return common_Get(env, obj, "GetCompany"); 653} 654 655static jboolean setNameNative(JNIEnv *env, jobject obj, jstring name) { 656#ifdef HAVE_BLUETOOTH 657 LOGV(__FUNCTION__); 658 native_data_t *nat = get_native_data(env, obj); 659 if (nat) { 660 const char *c_name = env->GetStringUTFChars(name, NULL); 661 DBusMessage *reply = dbus_func_args(env, nat->conn, nat->adapter, 662 DBUS_CLASS_NAME, "SetName", 663 DBUS_TYPE_STRING, &c_name, 664 DBUS_TYPE_INVALID); 665 env->ReleaseStringUTFChars(name, c_name); 666 if (reply) { 667 dbus_message_unref(reply); 668 return JNI_TRUE; 669 } 670 } 671#endif 672 return JNI_FALSE; 673} 674 675static jstring common_getRemote(JNIEnv *env, jobject object, const char *func, 676 jstring address) { 677 LOGV("%s:%s", __FUNCTION__, func); 678#ifdef HAVE_BLUETOOTH 679 native_data_t *nat = get_native_data(env, object); 680 if (nat) { 681 const char *c_address = env->GetStringUTFChars(address, NULL); 682 DBusError err; 683 dbus_error_init(&err); 684 685 LOGV("... address = %s", c_address); 686 687 DBusMessage *reply = 688 dbus_func_args_error(env, nat->conn, &err, nat->adapter, 689 DBUS_CLASS_NAME, func, 690 DBUS_TYPE_STRING, &c_address, 691 DBUS_TYPE_INVALID); 692 env->ReleaseStringUTFChars(address, c_address); 693 if (reply) { 694 return dbus_returns_string(env, reply); 695 } else if (!strcmp(func, "GetRemoteName") && 696 dbus_error_has_name(&err, "org.bluez.Error.RequestDeferred")) { 697 // This error occurs if we request name during device discovery, 698 // its fine 699 LOGV("... %s: %s", func, err.message); 700 dbus_error_free(&err); 701 return NULL; 702 } else { 703 LOG_AND_FREE_DBUS_ERROR(&err); 704 return NULL; 705 } 706 } 707#endif 708 return NULL; 709} 710 711static jstring getRemoteVersionNative(JNIEnv *env, jobject obj, jstring address) { 712 return common_getRemote(env, obj, "GetRemoteVersion", address); 713} 714 715static jstring getRemoteRevisionNative(JNIEnv *env, jobject obj, jstring address) { 716 return common_getRemote(env, obj, "GetRemoteRevision", address); 717} 718 719static jstring getRemoteManufacturerNative(JNIEnv *env, jobject obj, jstring address) { 720 return common_getRemote(env, obj, "GetRemoteManufacturer", address); 721} 722 723static jstring getRemoteCompanyNative(JNIEnv *env, jobject obj, jstring address) { 724 return common_getRemote(env, obj, "GetRemoteCompany", address); 725} 726 727static jstring getRemoteNameNative(JNIEnv *env, jobject obj, jstring address) { 728 return common_getRemote(env, obj, "GetRemoteName", address); 729} 730 731static jstring lastSeenNative(JNIEnv *env, jobject obj, jstring address) { 732 return common_getRemote(env, obj, "LastSeen", address); 733} 734 735static jstring lastUsedNative(JNIEnv *env, jobject obj, jstring address) { 736 return common_getRemote(env, obj, "LastUsed", address); 737} 738 739static jint getRemoteClassNative(JNIEnv *env, jobject object, jstring address) { 740 jint result = BLUETOOTH_CLASS_ERROR; 741#ifdef HAVE_BLUETOOTH 742 LOGV(__FUNCTION__); 743 native_data_t *nat = get_native_data(env, object); 744 if (nat) { 745 const char *c_address = env->GetStringUTFChars(address, NULL); 746 747 LOGV("... address = %s", c_address); 748 749 DBusMessage *reply = 750 dbus_func_args(env, nat->conn, nat->adapter, 751 DBUS_CLASS_NAME, "GetRemoteClass", 752 DBUS_TYPE_STRING, &c_address, 753 DBUS_TYPE_INVALID); 754 env->ReleaseStringUTFChars(address, c_address); 755 if (reply) 756 { 757 DBusError err; 758 dbus_error_init(&err); 759 if (!dbus_message_get_args(reply, &err, 760 DBUS_TYPE_UINT32, &result, 761 DBUS_TYPE_INVALID)) { 762 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply); 763 } 764 dbus_message_unref(reply); 765 } 766 } 767#endif 768 return result; 769} 770 771static jbyteArray getRemoteFeaturesNative(JNIEnv *env, jobject object, 772 jstring address) { 773#ifdef HAVE_BLUETOOTH 774 LOGV(__FUNCTION__); 775 native_data_t *nat = get_native_data(env, object); 776 if (nat) { 777 const char *c_address = env->GetStringUTFChars(address, NULL); 778 779 LOGV("... address = %s", c_address); 780 781 DBusMessage *reply = 782 dbus_func_args(env, nat->conn, nat->adapter, 783 DBUS_CLASS_NAME, "GetRemoteFeatures", 784 DBUS_TYPE_STRING, &c_address, 785 DBUS_TYPE_INVALID); 786 env->ReleaseStringUTFChars(address, c_address); 787 /* array of DBUS_TYPE_BYTE_AS_STRING */ 788 return reply ? dbus_returns_array_of_bytes(env, reply) : NULL; 789 } 790#endif 791 return NULL; 792} 793 794static jintArray getRemoteServiceHandlesNative(JNIEnv *env, jobject object, 795 jstring address, jstring match) { 796#ifdef HAVE_BLUETOOTH 797 LOGV(__FUNCTION__); 798 native_data_t *nat = get_native_data(env, object); 799 if (nat) { 800 jintArray intArray = NULL; 801 const char *c_address = env->GetStringUTFChars(address, NULL); 802 const char *c_match = env->GetStringUTFChars(match, NULL); 803 804 LOGV("... address = %s match = %s", c_address, c_match); 805 806 DBusMessage *reply = 807 dbus_func_args(env, nat->conn, nat->adapter, 808 DBUS_CLASS_NAME, "GetRemoteServiceHandles", 809 DBUS_TYPE_STRING, &c_address, 810 DBUS_TYPE_STRING, &c_match, 811 DBUS_TYPE_INVALID); 812 env->ReleaseStringUTFChars(address, c_address); 813 env->ReleaseStringUTFChars(match, c_match); 814 if (reply) 815 { 816 DBusError err; 817 jint *list; 818 int i, len; 819 820 dbus_error_init(&err); 821 if (dbus_message_get_args (reply, &err, 822 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, 823 &list, &len, 824 DBUS_TYPE_INVALID)) { 825 if (len) { 826 intArray = env->NewIntArray(len); 827 if (intArray) 828 env->SetIntArrayRegion(intArray, 0, len, list); 829 } 830 } else { 831 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply); 832 } 833 834 dbus_message_unref(reply); 835 } 836 return intArray; 837 } 838#endif 839 return NULL; 840} 841 842static jbyteArray getRemoteServiceRecordNative(JNIEnv *env, jobject object, 843 jstring address, jint handle) { 844#ifdef HAVE_BLUETOOTH 845 LOGV(__FUNCTION__); 846 native_data_t *nat = get_native_data(env, object); 847 if (nat) { 848 const char *c_address = env->GetStringUTFChars(address, NULL); 849 850 LOGV("... address = %s", c_address); 851 852 DBusMessage *reply = 853 dbus_func_args(env, nat->conn, nat->adapter, 854 DBUS_CLASS_NAME, "GetRemoteServiceRecord", 855 DBUS_TYPE_STRING, &c_address, 856 DBUS_TYPE_UINT32, &handle, 857 DBUS_TYPE_INVALID); 858 env->ReleaseStringUTFChars(address, c_address); 859 return reply ? dbus_returns_array_of_bytes(env, reply) : NULL; 860 } 861#endif 862 return NULL; 863} 864 865static jboolean getRemoteServiceChannelNative(JNIEnv *env, jobject object, 866 jstring address, jshort uuid16) { 867#ifdef HAVE_BLUETOOTH 868 LOGV(__FUNCTION__); 869 native_data_t *nat = get_native_data(env, object); 870 jobject eventLoop = env->GetObjectField(object, field_mEventLoop); 871 struct event_loop_native_data_t *eventLoopNat = 872 get_EventLoop_native_data(env, eventLoop); 873 if (nat && eventLoopNat) { 874 const char *c_address = env->GetStringUTFChars(address, NULL); 875 char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char)); 876 strlcpy(context_address, c_address, BTADDR_SIZE); 877 878 LOGV("... address = %s", c_address); 879 LOGV("... uuid16 = %#X", uuid16); 880 881 bool ret = dbus_func_args_async(env, nat->conn, 20000, // ms 882 onGetRemoteServiceChannelResult, context_address, 883 eventLoopNat, 884 nat->adapter, 885 DBUS_CLASS_NAME, "GetRemoteServiceChannel", 886 DBUS_TYPE_STRING, &c_address, 887 DBUS_TYPE_UINT16, &uuid16, 888 DBUS_TYPE_INVALID); 889 env->ReleaseStringUTFChars(address, c_address); 890 return ret ? JNI_TRUE : JNI_FALSE; 891 } 892#endif 893 return JNI_FALSE; 894} 895 896static jint enableNative(JNIEnv *env, jobject object) { 897#ifdef HAVE_BLUETOOTH 898 LOGV(__FUNCTION__); 899 return bt_enable(); 900#endif 901 return -1; 902} 903 904static jint disableNative(JNIEnv *env, jobject object) { 905#ifdef HAVE_BLUETOOTH 906 LOGV(__FUNCTION__); 907 return bt_disable(); 908#endif 909 return -1; 910} 911 912static jint isEnabledNative(JNIEnv *env, jobject object) { 913#ifdef HAVE_BLUETOOTH 914 LOGV(__FUNCTION__); 915 return bt_is_enabled(); 916#endif 917 return -1; 918} 919 920static jboolean setPinNative(JNIEnv *env, jobject object, jstring address, 921 jstring pin, int nativeData) { 922#ifdef HAVE_BLUETOOTH 923 LOGV(__FUNCTION__); 924 native_data_t *nat = get_native_data(env, object); 925 if (nat) { 926 DBusMessage *msg = (DBusMessage *)nativeData; 927 DBusMessage *reply = dbus_message_new_method_return(msg); 928 if (!reply) { 929 LOGE("%s: Cannot create message reply to return PIN code to " 930 "D-Bus\n", __FUNCTION__); 931 dbus_message_unref(msg); 932 return JNI_FALSE; 933 } 934 935 const char *c_pin = env->GetStringUTFChars(pin, NULL); 936 937 dbus_message_append_args(reply, DBUS_TYPE_STRING, &c_pin, 938 DBUS_TYPE_INVALID); 939 940 dbus_connection_send(nat->conn, reply, NULL); 941 dbus_message_unref(msg); 942 dbus_message_unref(reply); 943 env->ReleaseStringUTFChars(pin, c_pin); 944 return JNI_TRUE; 945 } 946#endif 947 return JNI_FALSE; 948} 949 950static jboolean cancelPinNative(JNIEnv *env, jobject object, jstring address, 951 int nativeData) { 952#ifdef HAVE_BLUETOOTH 953 LOGV(__FUNCTION__); 954 native_data_t *nat = get_native_data(env, object); 955 if (nat) { 956 DBusMessage *msg = (DBusMessage *)nativeData; 957 DBusMessage *reply = dbus_message_new_error(msg, 958 "org.bluez.Error.Canceled", "PIN Entry was canceled"); 959 if (!reply) { 960 LOGE("%s: Cannot create message reply to return PIN cancel to " 961 "D-BUS\n", __FUNCTION__); 962 dbus_message_unref(msg); 963 return JNI_FALSE; 964 } 965 966 dbus_connection_send(nat->conn, reply, NULL); 967 dbus_message_unref(msg); 968 dbus_message_unref(reply); 969 return JNI_TRUE; 970 } 971#endif 972 return JNI_FALSE; 973} 974 975static JNINativeMethod sMethods[] = { 976 /* name, signature, funcPtr */ 977 {"classInitNative", "()V", (void*)classInitNative}, 978 {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative}, 979 {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative}, 980 {"getAdapterPathNative", "()Ljava/lang/String;", (void*)getAdapterPathNative}, 981 982 {"isEnabledNative", "()I", (void *)isEnabledNative}, 983 {"enableNative", "()I", (void *)enableNative}, 984 {"disableNative", "()I", (void *)disableNative}, 985 986 {"getAddressNative", "()Ljava/lang/String;", (void *)getAddressNative}, 987 {"getNameNative", "()Ljava/lang/String;", (void*)getNameNative}, 988 {"setNameNative", "(Ljava/lang/String;)Z", (void *)setNameNative}, 989 {"getVersionNative", "()Ljava/lang/String;", (void *)getVersionNative}, 990 {"getRevisionNative", "()Ljava/lang/String;", (void *)getRevisionNative}, 991 {"getManufacturerNative", "()Ljava/lang/String;", (void *)getManufacturerNative}, 992 {"getCompanyNative", "()Ljava/lang/String;", (void *)getCompanyNative}, 993 994 {"getModeNative", "()Ljava/lang/String;", (void *)getModeNative}, 995 {"setModeNative", "(Ljava/lang/String;)Z", (void *)setModeNative}, 996 997 {"getDiscoverableTimeoutNative", "()I", (void *)getDiscoverableTimeoutNative}, 998 {"setDiscoverableTimeoutNative", "(I)Z", (void *)setDiscoverableTimeoutNative}, 999 1000 {"startDiscoveryNative", "(Z)Z", (void*)startDiscoveryNative}, 1001 {"cancelDiscoveryNative", "()Z", (void *)cancelDiscoveryNative}, 1002 {"startPeriodicDiscoveryNative", "()Z", (void *)startPeriodicDiscoveryNative}, 1003 {"stopPeriodicDiscoveryNative", "()Z", (void *)stopPeriodicDiscoveryNative}, 1004 {"isPeriodicDiscoveryNative", "()Z", (void *)isPeriodicDiscoveryNative}, 1005 {"listRemoteDevicesNative", "()[Ljava/lang/String;", (void *)listRemoteDevicesNative}, 1006 1007 {"listConnectionsNative", "()[Ljava/lang/String;", (void *)listConnectionsNative}, 1008 {"isConnectedNative", "(Ljava/lang/String;)Z", (void *)isConnectedNative}, 1009 {"disconnectRemoteDeviceNative", "(Ljava/lang/String;)Z", (void *)disconnectRemoteDeviceNative}, 1010 1011 {"createBondingNative", "(Ljava/lang/String;I)Z", (void *)createBondingNative}, 1012 {"cancelBondingProcessNative", "(Ljava/lang/String;)Z", (void *)cancelBondingProcessNative}, 1013 {"listBondingsNative", "()[Ljava/lang/String;", (void *)listBondingsNative}, 1014 {"removeBondingNative", "(Ljava/lang/String;)Z", (void *)removeBondingNative}, 1015 1016 {"getRemoteNameNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteNameNative}, 1017 {"getRemoteVersionNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteVersionNative}, 1018 {"getRemoteRevisionNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteRevisionNative}, 1019 {"getRemoteClassNative", "(Ljava/lang/String;)I", (void *)getRemoteClassNative}, 1020 {"getRemoteManufacturerNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteManufacturerNative}, 1021 {"getRemoteCompanyNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteCompanyNative}, 1022 {"getRemoteServiceChannelNative", "(Ljava/lang/String;S)Z", (void *)getRemoteServiceChannelNative}, 1023 {"getRemoteFeaturesNative", "(Ljava/lang/String;)[B", (void *)getRemoteFeaturesNative}, 1024 {"lastSeenNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)lastSeenNative}, 1025 {"lastUsedNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)lastUsedNative}, 1026 {"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative}, 1027 {"cancelPinNative", "(Ljava/lang/String;I)Z", (void *)cancelPinNative}, 1028}; 1029 1030int register_android_server_BluetoothDeviceService(JNIEnv *env) { 1031 return AndroidRuntime::registerNativeMethods(env, 1032 "android/server/BluetoothDeviceService", sMethods, NELEM(sMethods)); 1033} 1034 1035} /* namespace android */ 1036