Home | History | Annotate | Download | only in jni
      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 DBUS_INPUT_IFACE BLUEZ_DBUS_BASE_IFC ".Input"
     20 #define DBUS_NETWORK_IFACE BLUEZ_DBUS_BASE_IFC ".Network"
     21 #define DBUS_NETWORKSERVER_IFACE BLUEZ_DBUS_BASE_IFC ".NetworkServer"
     22 #define DBUS_HEALTH_MANAGER_PATH "/org/bluez"
     23 #define DBUS_HEALTH_MANAGER_IFACE BLUEZ_DBUS_BASE_IFC ".HealthManager"
     24 #define DBUS_HEALTH_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".HealthDevice"
     25 #define DBUS_HEALTH_CHANNEL_IFACE BLUEZ_DBUS_BASE_IFC ".HealthChannel"
     26 
     27 #define LOG_TAG "BluetoothService.cpp"
     28 
     29 #include "android_bluetooth_common.h"
     30 #include "android_runtime/AndroidRuntime.h"
     31 #include "android_util_Binder.h"
     32 #include "JNIHelp.h"
     33 #include "jni.h"
     34 #include "utils/Log.h"
     35 #include "utils/misc.h"
     36 
     37 #include <ctype.h>
     38 #include <stdio.h>
     39 #include <string.h>
     40 #include <stdlib.h>
     41 #include <errno.h>
     42 #include <unistd.h>
     43 
     44 #include <sys/socket.h>
     45 #include <sys/ioctl.h>
     46 #include <fcntl.h>
     47 
     48 #ifdef HAVE_BLUETOOTH
     49 #include <dbus/dbus.h>
     50 #include <bluedroid/bluetooth.h>
     51 #endif
     52 
     53 #include <cutils/properties.h>
     54 
     55 namespace android {
     56 
     57 #define BLUETOOTH_CLASS_ERROR 0xFF000000
     58 #define PROPERTIES_NREFS 10
     59 
     60 #ifdef HAVE_BLUETOOTH
     61 // We initialize these variables when we load class
     62 // android.server.BluetoothService
     63 static jfieldID field_mNativeData;
     64 static jfieldID field_mEventLoop;
     65 
     66 typedef struct {
     67     JNIEnv *env;
     68     DBusConnection *conn;
     69     const char *adapter;  // dbus object name of the local adapter
     70 } native_data_t;
     71 
     72 extern event_loop_native_data_t *get_EventLoop_native_data(JNIEnv *,
     73                                                            jobject);
     74 extern DBusHandlerResult agent_event_filter(DBusConnection *conn,
     75                                             DBusMessage *msg,
     76                                             void *data);
     77 void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *nat);
     78 void onDiscoverServicesResult(DBusMessage *msg, void *user, void *nat);
     79 void onCreateDeviceResult(DBusMessage *msg, void *user, void *nat);
     80 void onInputDeviceConnectionResult(DBusMessage *msg, void *user, void *nat);
     81 void onPanDeviceConnectionResult(DBusMessage *msg, void *user, void *nat);
     82 void onHealthDeviceConnectionResult(DBusMessage *msg, void *user, void *nat);
     83 
     84 
     85 /** Get native data stored in the opaque (Java code maintained) pointer mNativeData
     86  *  Perform quick sanity check, if there are any problems return NULL
     87  */
     88 static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
     89     native_data_t *nat =
     90             (native_data_t *)(env->GetIntField(object, field_mNativeData));
     91     if (nat == NULL || nat->conn == NULL) {
     92         LOGE("Uninitialized native data\n");
     93         return NULL;
     94     }
     95     return nat;
     96 }
     97 #endif
     98 
     99 static void classInitNative(JNIEnv* env, jclass clazz) {
    100     LOGV("%s", __FUNCTION__);
    101 #ifdef HAVE_BLUETOOTH
    102     field_mNativeData = get_field(env, clazz, "mNativeData", "I");
    103     field_mEventLoop = get_field(env, clazz, "mEventLoop",
    104             "Landroid/server/BluetoothEventLoop;");
    105 #endif
    106 }
    107 
    108 /* Returns true on success (even if adapter is present but disabled).
    109  * Return false if dbus is down, or another serious error (out of memory)
    110 */
    111 static bool initializeNativeDataNative(JNIEnv* env, jobject object) {
    112     LOGV("%s", __FUNCTION__);
    113 #ifdef HAVE_BLUETOOTH
    114     native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
    115     if (NULL == nat) {
    116         LOGE("%s: out of memory!", __FUNCTION__);
    117         return false;
    118     }
    119     nat->env = env;
    120 
    121     env->SetIntField(object, field_mNativeData, (jint)nat);
    122     DBusError err;
    123     dbus_error_init(&err);
    124     dbus_threads_init_default();
    125     nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
    126     if (dbus_error_is_set(&err)) {
    127         LOGE("Could not get onto the system bus: %s", err.message);
    128         dbus_error_free(&err);
    129         return false;
    130     }
    131     dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
    132 #endif  /*HAVE_BLUETOOTH*/
    133     return true;
    134 }
    135 
    136 static const char *get_adapter_path(JNIEnv* env, jobject object) {
    137 #ifdef HAVE_BLUETOOTH
    138     event_loop_native_data_t *event_nat =
    139         get_EventLoop_native_data(env, env->GetObjectField(object,
    140                                                            field_mEventLoop));
    141     if (event_nat == NULL)
    142         return NULL;
    143     return event_nat->adapter;
    144 #else
    145     return NULL;
    146 #endif
    147 }
    148 
    149 // This function is called when the adapter is enabled.
    150 static jboolean setupNativeDataNative(JNIEnv* env, jobject object) {
    151     LOGV("%s", __FUNCTION__);
    152 #ifdef HAVE_BLUETOOTH
    153     native_data_t *nat =
    154         (native_data_t *)env->GetIntField(object, field_mNativeData);
    155     event_loop_native_data_t *event_nat =
    156         get_EventLoop_native_data(env, env->GetObjectField(object,
    157                                                            field_mEventLoop));
    158     // Register agent for remote devices.
    159     const char *device_agent_path = "/android/bluetooth/remote_device_agent";
    160     static const DBusObjectPathVTable agent_vtable = {
    161                  NULL, agent_event_filter, NULL, NULL, NULL, NULL };
    162 
    163     if (!dbus_connection_register_object_path(nat->conn, device_agent_path,
    164                                               &agent_vtable, event_nat)) {
    165         LOGE("%s: Can't register object path %s for remote device agent!",
    166                                __FUNCTION__, device_agent_path);
    167         return JNI_FALSE;
    168     }
    169 #endif /*HAVE_BLUETOOTH*/
    170     return JNI_TRUE;
    171 }
    172 
    173 static jboolean tearDownNativeDataNative(JNIEnv *env, jobject object) {
    174     LOGV("%s", __FUNCTION__);
    175 #ifdef HAVE_BLUETOOTH
    176     native_data_t *nat =
    177                (native_data_t *)env->GetIntField(object, field_mNativeData);
    178     if (nat != NULL) {
    179         const char *device_agent_path =
    180             "/android/bluetooth/remote_device_agent";
    181         dbus_connection_unregister_object_path (nat->conn, device_agent_path);
    182     }
    183 #endif /*HAVE_BLUETOOTH*/
    184     return JNI_TRUE;
    185 }
    186 
    187 static 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     if (nat) {
    193         free(nat);
    194         nat = NULL;
    195     }
    196 #endif
    197 }
    198 
    199 static jstring getAdapterPathNative(JNIEnv *env, jobject object) {
    200     LOGV("%s", __FUNCTION__);
    201 #ifdef HAVE_BLUETOOTH
    202     native_data_t *nat = get_native_data(env, object);
    203     if (nat) {
    204         return (env->NewStringUTF(get_adapter_path(env, object)));
    205     }
    206 #endif
    207     return NULL;
    208 }
    209 
    210 
    211 static jboolean startDiscoveryNative(JNIEnv *env, jobject object) {
    212     LOGV("%s", __FUNCTION__);
    213 #ifdef HAVE_BLUETOOTH
    214     DBusMessage *msg = NULL;
    215     DBusMessage *reply = NULL;
    216     DBusError err;
    217     const char *name;
    218     jboolean ret = JNI_FALSE;
    219 
    220     native_data_t *nat = get_native_data(env, object);
    221     if (nat == NULL) {
    222         goto done;
    223     }
    224 
    225     dbus_error_init(&err);
    226 
    227     /* Compose the command */
    228     msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
    229                                        get_adapter_path(env, object),
    230                                        DBUS_ADAPTER_IFACE, "StartDiscovery");
    231 
    232     if (msg == NULL) {
    233         if (dbus_error_is_set(&err)) {
    234             LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    235         }
    236         goto done;
    237     }
    238 
    239     /* Send the command. */
    240     reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
    241     if (dbus_error_is_set(&err)) {
    242          LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    243          ret = JNI_FALSE;
    244          goto done;
    245     }
    246 
    247     ret = JNI_TRUE;
    248 done:
    249     if (reply) dbus_message_unref(reply);
    250     if (msg) dbus_message_unref(msg);
    251     return ret;
    252 #else
    253     return JNI_FALSE;
    254 #endif
    255 }
    256 
    257 static jboolean stopDiscoveryNative(JNIEnv *env, jobject object) {
    258     LOGV("%s", __FUNCTION__);
    259 #ifdef HAVE_BLUETOOTH
    260     DBusMessage *msg = NULL;
    261     DBusMessage *reply = NULL;
    262     DBusError err;
    263     const char *name;
    264     native_data_t *nat;
    265     jboolean ret = JNI_FALSE;
    266 
    267     dbus_error_init(&err);
    268 
    269     nat = get_native_data(env, object);
    270     if (nat == NULL) {
    271         goto done;
    272     }
    273 
    274     /* Compose the command */
    275     msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
    276                                        get_adapter_path(env, object),
    277                                        DBUS_ADAPTER_IFACE, "StopDiscovery");
    278     if (msg == NULL) {
    279         if (dbus_error_is_set(&err))
    280             LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    281         goto done;
    282     }
    283 
    284     /* Send the command. */
    285     reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
    286     if (dbus_error_is_set(&err)) {
    287         if(strncmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized",
    288                    strlen(BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized")) == 0) {
    289             // hcid sends this if there is no active discovery to cancel
    290             LOGV("%s: There was no active discovery to cancel", __FUNCTION__);
    291             dbus_error_free(&err);
    292         } else {
    293             LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    294         }
    295         goto done;
    296     }
    297 
    298     ret = JNI_TRUE;
    299 done:
    300     if (msg) dbus_message_unref(msg);
    301     if (reply) dbus_message_unref(reply);
    302     return ret;
    303 #else
    304     return JNI_FALSE;
    305 #endif
    306 }
    307 
    308 static jbyteArray readAdapterOutOfBandDataNative(JNIEnv *env, jobject object) {
    309     LOGV("%s", __FUNCTION__);
    310 #ifdef HAVE_BLUETOOTH
    311     native_data_t *nat = get_native_data(env, object);
    312     DBusError err;
    313     jbyte *hash, *randomizer;
    314     jbyteArray byteArray = NULL;
    315     int hash_len, r_len;
    316     if (nat) {
    317        DBusMessage *reply = dbus_func_args(env, nat->conn,
    318                            get_adapter_path(env, object),
    319                            DBUS_ADAPTER_IFACE, "ReadLocalOutOfBandData",
    320                            DBUS_TYPE_INVALID);
    321        if (!reply) return NULL;
    322 
    323        dbus_error_init(&err);
    324        if (dbus_message_get_args(reply, &err,
    325                                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, &hash_len,
    326                                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, &r_len,
    327                                 DBUS_TYPE_INVALID)) {
    328           if (hash_len == 16 && r_len == 16) {
    329                byteArray = env->NewByteArray(32);
    330                if (byteArray) {
    331                    env->SetByteArrayRegion(byteArray, 0, 16, hash);
    332                    env->SetByteArrayRegion(byteArray, 16, 16, randomizer);
    333                }
    334            } else {
    335                LOGE("readAdapterOutOfBandDataNative: Hash len = %d, R len = %d",
    336                                                                   hash_len, r_len);
    337            }
    338        } else {
    339           LOG_AND_FREE_DBUS_ERROR(&err);
    340        }
    341        dbus_message_unref(reply);
    342        return byteArray;
    343     }
    344 #endif
    345     return NULL;
    346 }
    347 
    348 static jboolean createPairedDeviceNative(JNIEnv *env, jobject object,
    349                                          jstring address, jint timeout_ms) {
    350     LOGV("%s", __FUNCTION__);
    351 #ifdef HAVE_BLUETOOTH
    352     native_data_t *nat = get_native_data(env, object);
    353     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
    354     struct event_loop_native_data_t *eventLoopNat =
    355             get_EventLoop_native_data(env, eventLoop);
    356 
    357     if (nat && eventLoopNat) {
    358         const char *c_address = env->GetStringUTFChars(address, NULL);
    359         LOGV("... address = %s", c_address);
    360         char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
    361         const char *capabilities = "DisplayYesNo";
    362         const char *agent_path = "/android/bluetooth/remote_device_agent";
    363 
    364         strlcpy(context_address, c_address, BTADDR_SIZE);  // for callback
    365         bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms,
    366                                         onCreatePairedDeviceResult, // callback
    367                                         context_address,
    368                                         eventLoopNat,
    369                                         get_adapter_path(env, object),
    370                                         DBUS_ADAPTER_IFACE,
    371                                         "CreatePairedDevice",
    372                                         DBUS_TYPE_STRING, &c_address,
    373                                         DBUS_TYPE_OBJECT_PATH, &agent_path,
    374                                         DBUS_TYPE_STRING, &capabilities,
    375                                         DBUS_TYPE_INVALID);
    376         env->ReleaseStringUTFChars(address, c_address);
    377         return ret ? JNI_TRUE : JNI_FALSE;
    378 
    379     }
    380 #endif
    381     return JNI_FALSE;
    382 }
    383 
    384 static jboolean createPairedDeviceOutOfBandNative(JNIEnv *env, jobject object,
    385                                                 jstring address, jint timeout_ms) {
    386     LOGV("%s", __FUNCTION__);
    387 #ifdef HAVE_BLUETOOTH
    388     native_data_t *nat = get_native_data(env, object);
    389     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
    390     struct event_loop_native_data_t *eventLoopNat =
    391             get_EventLoop_native_data(env, eventLoop);
    392 
    393     if (nat && eventLoopNat) {
    394         const char *c_address = env->GetStringUTFChars(address, NULL);
    395         LOGV("... address = %s", c_address);
    396         char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
    397         const char *capabilities = "DisplayYesNo";
    398         const char *agent_path = "/android/bluetooth/remote_device_agent";
    399 
    400         strlcpy(context_address, c_address, BTADDR_SIZE);  // for callback
    401         bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms,
    402                                         onCreatePairedDeviceResult, // callback
    403                                         context_address,
    404                                         eventLoopNat,
    405                                         get_adapter_path(env, object),
    406                                         DBUS_ADAPTER_IFACE,
    407                                         "CreatePairedDeviceOutOfBand",
    408                                         DBUS_TYPE_STRING, &c_address,
    409                                         DBUS_TYPE_OBJECT_PATH, &agent_path,
    410                                         DBUS_TYPE_STRING, &capabilities,
    411                                         DBUS_TYPE_INVALID);
    412         env->ReleaseStringUTFChars(address, c_address);
    413         return ret ? JNI_TRUE : JNI_FALSE;
    414     }
    415 #endif
    416     return JNI_FALSE;
    417 }
    418 
    419 static jint getDeviceServiceChannelNative(JNIEnv *env, jobject object,
    420                                           jstring path,
    421                                           jstring pattern, jint attr_id) {
    422 #ifdef HAVE_BLUETOOTH
    423     LOGV("%s", __FUNCTION__);
    424     native_data_t *nat = get_native_data(env, object);
    425     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
    426     struct event_loop_native_data_t *eventLoopNat =
    427             get_EventLoop_native_data(env, eventLoop);
    428     if (nat && eventLoopNat) {
    429         const char *c_pattern = env->GetStringUTFChars(pattern, NULL);
    430         const char *c_path = env->GetStringUTFChars(path, NULL);
    431         LOGV("... pattern = %s", c_pattern);
    432         LOGV("... attr_id = %#X", attr_id);
    433         DBusMessage *reply =
    434             dbus_func_args(env, nat->conn, c_path,
    435                            DBUS_DEVICE_IFACE, "GetServiceAttributeValue",
    436                            DBUS_TYPE_STRING, &c_pattern,
    437                            DBUS_TYPE_UINT16, &attr_id,
    438                            DBUS_TYPE_INVALID);
    439         env->ReleaseStringUTFChars(pattern, c_pattern);
    440         env->ReleaseStringUTFChars(path, c_path);
    441         return reply ? dbus_returns_int32(env, reply) : -1;
    442     }
    443 #endif
    444     return -1;
    445 }
    446 
    447 static jboolean cancelDeviceCreationNative(JNIEnv *env, jobject object,
    448                                            jstring address) {
    449     LOGV("%s", __FUNCTION__);
    450     jboolean result = JNI_FALSE;
    451 #ifdef HAVE_BLUETOOTH
    452     native_data_t *nat = get_native_data(env, object);
    453     if (nat) {
    454         const char *c_address = env->GetStringUTFChars(address, NULL);
    455         DBusError err;
    456         dbus_error_init(&err);
    457         LOGV("... address = %s", c_address);
    458         DBusMessage *reply =
    459             dbus_func_args_timeout(env, nat->conn, -1,
    460                                    get_adapter_path(env, object),
    461                                    DBUS_ADAPTER_IFACE, "CancelDeviceCreation",
    462                                    DBUS_TYPE_STRING, &c_address,
    463                                    DBUS_TYPE_INVALID);
    464         env->ReleaseStringUTFChars(address, c_address);
    465         if (!reply) {
    466             if (dbus_error_is_set(&err)) {
    467                 LOG_AND_FREE_DBUS_ERROR(&err);
    468             } else
    469                 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
    470             return JNI_FALSE;
    471         } else {
    472             result = JNI_TRUE;
    473         }
    474         dbus_message_unref(reply);
    475     }
    476 #endif
    477     return JNI_FALSE;
    478 }
    479 
    480 static jboolean removeDeviceNative(JNIEnv *env, jobject object, jstring object_path) {
    481     LOGV("%s", __FUNCTION__);
    482 #ifdef HAVE_BLUETOOTH
    483     native_data_t *nat = get_native_data(env, object);
    484     if (nat) {
    485         const char *c_object_path = env->GetStringUTFChars(object_path, NULL);
    486         bool ret = dbus_func_args_async(env, nat->conn, -1,
    487                                         NULL,
    488                                         NULL,
    489                                         NULL,
    490                                         get_adapter_path(env, object),
    491                                         DBUS_ADAPTER_IFACE,
    492                                         "RemoveDevice",
    493                                         DBUS_TYPE_OBJECT_PATH, &c_object_path,
    494                                         DBUS_TYPE_INVALID);
    495         env->ReleaseStringUTFChars(object_path, c_object_path);
    496         return ret ? JNI_TRUE : JNI_FALSE;
    497     }
    498 #endif
    499     return JNI_FALSE;
    500 }
    501 
    502 static jint enableNative(JNIEnv *env, jobject object) {
    503 #ifdef HAVE_BLUETOOTH
    504     LOGV("%s", __FUNCTION__);
    505     return bt_enable();
    506 #endif
    507     return -1;
    508 }
    509 
    510 static jint disableNative(JNIEnv *env, jobject object) {
    511 #ifdef HAVE_BLUETOOTH
    512     LOGV("%s", __FUNCTION__);
    513     return bt_disable();
    514 #endif
    515     return -1;
    516 }
    517 
    518 static jint isEnabledNative(JNIEnv *env, jobject object) {
    519 #ifdef HAVE_BLUETOOTH
    520     LOGV("%s", __FUNCTION__);
    521     return bt_is_enabled();
    522 #endif
    523     return -1;
    524 }
    525 
    526 static jboolean setPairingConfirmationNative(JNIEnv *env, jobject object,
    527                                              jstring address, bool confirm,
    528                                              int nativeData) {
    529 #ifdef HAVE_BLUETOOTH
    530     LOGV("%s", __FUNCTION__);
    531     native_data_t *nat = get_native_data(env, object);
    532     if (nat) {
    533         DBusMessage *msg = (DBusMessage *)nativeData;
    534         DBusMessage *reply;
    535         if (confirm) {
    536             reply = dbus_message_new_method_return(msg);
    537         } else {
    538             reply = dbus_message_new_error(msg,
    539                 "org.bluez.Error.Rejected", "User rejected confirmation");
    540         }
    541 
    542         if (!reply) {
    543             LOGE("%s: Cannot create message reply to RequestPasskeyConfirmation or"
    544                   "RequestPairingConsent to D-Bus\n", __FUNCTION__);
    545             dbus_message_unref(msg);
    546             return JNI_FALSE;
    547         }
    548 
    549         dbus_connection_send(nat->conn, reply, NULL);
    550         dbus_message_unref(msg);
    551         dbus_message_unref(reply);
    552         return JNI_TRUE;
    553     }
    554 #endif
    555     return JNI_FALSE;
    556 }
    557 
    558 static jboolean setPasskeyNative(JNIEnv *env, jobject object, jstring address,
    559                          int passkey, int nativeData) {
    560 #ifdef HAVE_BLUETOOTH
    561     LOGV("%s", __FUNCTION__);
    562     native_data_t *nat = get_native_data(env, object);
    563     if (nat) {
    564         DBusMessage *msg = (DBusMessage *)nativeData;
    565         DBusMessage *reply = dbus_message_new_method_return(msg);
    566         if (!reply) {
    567             LOGE("%s: Cannot create message reply to return Passkey code to "
    568                  "D-Bus\n", __FUNCTION__);
    569             dbus_message_unref(msg);
    570             return JNI_FALSE;
    571         }
    572 
    573         dbus_message_append_args(reply, DBUS_TYPE_UINT32, (uint32_t *)&passkey,
    574                                  DBUS_TYPE_INVALID);
    575 
    576         dbus_connection_send(nat->conn, reply, NULL);
    577         dbus_message_unref(msg);
    578         dbus_message_unref(reply);
    579         return JNI_TRUE;
    580     }
    581 #endif
    582     return JNI_FALSE;
    583 }
    584 
    585 static jboolean setRemoteOutOfBandDataNative(JNIEnv *env, jobject object, jstring address,
    586                          jbyteArray hash, jbyteArray randomizer, int nativeData) {
    587 #ifdef HAVE_BLUETOOTH
    588     LOGV("%s", __FUNCTION__);
    589     native_data_t *nat = get_native_data(env, object);
    590     if (nat) {
    591         DBusMessage *msg = (DBusMessage *)nativeData;
    592         DBusMessage *reply = dbus_message_new_method_return(msg);
    593         jbyte *h_ptr = env->GetByteArrayElements(hash, NULL);
    594         jbyte *r_ptr = env->GetByteArrayElements(randomizer, NULL);
    595         if (!reply) {
    596             LOGE("%s: Cannot create message reply to return remote OOB data to "
    597                  "D-Bus\n", __FUNCTION__);
    598             dbus_message_unref(msg);
    599             return JNI_FALSE;
    600         }
    601 
    602         dbus_message_append_args(reply,
    603                                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &h_ptr, 16,
    604                                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &r_ptr, 16,
    605                                 DBUS_TYPE_INVALID);
    606 
    607         env->ReleaseByteArrayElements(hash, h_ptr, 0);
    608         env->ReleaseByteArrayElements(randomizer, r_ptr, 0);
    609 
    610         dbus_connection_send(nat->conn, reply, NULL);
    611         dbus_message_unref(msg);
    612         dbus_message_unref(reply);
    613         return JNI_TRUE;
    614     }
    615 #endif
    616     return JNI_FALSE;
    617 }
    618 
    619 static jboolean setAuthorizationNative(JNIEnv *env, jobject object, jstring address,
    620                          jboolean val, int nativeData) {
    621 #ifdef HAVE_BLUETOOTH
    622   LOGV("%s", __FUNCTION__);
    623     native_data_t *nat = get_native_data(env, object);
    624     if (nat) {
    625         DBusMessage *msg = (DBusMessage *)nativeData;
    626         DBusMessage *reply;
    627         if (val) {
    628             reply = dbus_message_new_method_return(msg);
    629         } else {
    630             reply = dbus_message_new_error(msg,
    631                     "org.bluez.Error.Rejected", "Authorization rejected");
    632         }
    633         if (!reply) {
    634             LOGE("%s: Cannot create message reply D-Bus\n", __FUNCTION__);
    635             dbus_message_unref(msg);
    636             return JNI_FALSE;
    637         }
    638 
    639         dbus_connection_send(nat->conn, reply, NULL);
    640         dbus_message_unref(msg);
    641         dbus_message_unref(reply);
    642         return JNI_TRUE;
    643     }
    644 #endif
    645     return JNI_FALSE;
    646 }
    647 
    648 static jboolean setPinNative(JNIEnv *env, jobject object, jstring address,
    649                          jstring pin, int nativeData) {
    650 #ifdef HAVE_BLUETOOTH
    651     LOGV("%s", __FUNCTION__);
    652     native_data_t *nat = get_native_data(env, object);
    653     if (nat) {
    654         DBusMessage *msg = (DBusMessage *)nativeData;
    655         DBusMessage *reply = dbus_message_new_method_return(msg);
    656         if (!reply) {
    657             LOGE("%s: Cannot create message reply to return PIN code to "
    658                  "D-Bus\n", __FUNCTION__);
    659             dbus_message_unref(msg);
    660             return JNI_FALSE;
    661         }
    662 
    663         const char *c_pin = env->GetStringUTFChars(pin, NULL);
    664 
    665         dbus_message_append_args(reply, DBUS_TYPE_STRING, &c_pin,
    666                                  DBUS_TYPE_INVALID);
    667 
    668         dbus_connection_send(nat->conn, reply, NULL);
    669         dbus_message_unref(msg);
    670         dbus_message_unref(reply);
    671         env->ReleaseStringUTFChars(pin, c_pin);
    672         return JNI_TRUE;
    673     }
    674 #endif
    675     return JNI_FALSE;
    676 }
    677 
    678 static jboolean cancelPairingUserInputNative(JNIEnv *env, jobject object,
    679                                             jstring address, int nativeData) {
    680 #ifdef HAVE_BLUETOOTH
    681     LOGV("%s", __FUNCTION__);
    682     native_data_t *nat = get_native_data(env, object);
    683     if (nat) {
    684         DBusMessage *msg = (DBusMessage *)nativeData;
    685         DBusMessage *reply = dbus_message_new_error(msg,
    686                 "org.bluez.Error.Canceled", "Pairing User Input was canceled");
    687         if (!reply) {
    688             LOGE("%s: Cannot create message reply to return cancelUserInput to"
    689                  "D-BUS\n", __FUNCTION__);
    690             dbus_message_unref(msg);
    691             return JNI_FALSE;
    692         }
    693 
    694         dbus_connection_send(nat->conn, reply, NULL);
    695         dbus_message_unref(msg);
    696         dbus_message_unref(reply);
    697         return JNI_TRUE;
    698     }
    699 #endif
    700     return JNI_FALSE;
    701 }
    702 
    703 static jobjectArray getDevicePropertiesNative(JNIEnv *env, jobject object,
    704                                                     jstring path)
    705 {
    706 #ifdef HAVE_BLUETOOTH
    707     LOGV("%s", __FUNCTION__);
    708     native_data_t *nat = get_native_data(env, object);
    709     if (nat) {
    710         DBusMessage *msg, *reply;
    711         DBusError err;
    712         dbus_error_init(&err);
    713 
    714         const char *c_path = env->GetStringUTFChars(path, NULL);
    715         reply = dbus_func_args_timeout(env,
    716                                    nat->conn, -1, c_path,
    717                                    DBUS_DEVICE_IFACE, "GetProperties",
    718                                    DBUS_TYPE_INVALID);
    719         env->ReleaseStringUTFChars(path, c_path);
    720 
    721         if (!reply) {
    722             if (dbus_error_is_set(&err)) {
    723                 LOG_AND_FREE_DBUS_ERROR(&err);
    724             } else
    725                 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
    726             return NULL;
    727         }
    728         env->PushLocalFrame(PROPERTIES_NREFS);
    729 
    730         DBusMessageIter iter;
    731         jobjectArray str_array = NULL;
    732         if (dbus_message_iter_init(reply, &iter))
    733            str_array =  parse_remote_device_properties(env, &iter);
    734         dbus_message_unref(reply);
    735 
    736         return (jobjectArray) env->PopLocalFrame(str_array);
    737     }
    738 #endif
    739     return NULL;
    740 }
    741 
    742 static jobjectArray getAdapterPropertiesNative(JNIEnv *env, jobject object) {
    743 #ifdef HAVE_BLUETOOTH
    744     LOGV("%s", __FUNCTION__);
    745     native_data_t *nat = get_native_data(env, object);
    746     if (nat) {
    747         DBusMessage *msg, *reply;
    748         DBusError err;
    749         dbus_error_init(&err);
    750 
    751         reply = dbus_func_args_timeout(env,
    752                                    nat->conn, -1, get_adapter_path(env, object),
    753                                    DBUS_ADAPTER_IFACE, "GetProperties",
    754                                    DBUS_TYPE_INVALID);
    755         if (!reply) {
    756             if (dbus_error_is_set(&err)) {
    757                 LOG_AND_FREE_DBUS_ERROR(&err);
    758             } else
    759                 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
    760             return NULL;
    761         }
    762         env->PushLocalFrame(PROPERTIES_NREFS);
    763 
    764         DBusMessageIter iter;
    765         jobjectArray str_array = NULL;
    766         if (dbus_message_iter_init(reply, &iter))
    767             str_array = parse_adapter_properties(env, &iter);
    768         dbus_message_unref(reply);
    769 
    770         return (jobjectArray) env->PopLocalFrame(str_array);
    771     }
    772 #endif
    773     return NULL;
    774 }
    775 
    776 static jboolean setAdapterPropertyNative(JNIEnv *env, jobject object, jstring key,
    777                                          void *value, jint type) {
    778 #ifdef HAVE_BLUETOOTH
    779     LOGV("%s", __FUNCTION__);
    780     native_data_t *nat = get_native_data(env, object);
    781     if (nat) {
    782         DBusMessage *msg;
    783         DBusMessageIter iter;
    784         dbus_bool_t reply = JNI_FALSE;
    785         const char *c_key = env->GetStringUTFChars(key, NULL);
    786 
    787         msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
    788                                            get_adapter_path(env, object),
    789                                            DBUS_ADAPTER_IFACE, "SetProperty");
    790         if (!msg) {
    791             LOGE("%s: Can't allocate new method call for GetProperties!",
    792                   __FUNCTION__);
    793             env->ReleaseStringUTFChars(key, c_key);
    794             return JNI_FALSE;
    795         }
    796 
    797         dbus_message_append_args(msg, DBUS_TYPE_STRING, &c_key, DBUS_TYPE_INVALID);
    798         dbus_message_iter_init_append(msg, &iter);
    799         append_variant(&iter, type, value);
    800 
    801         // Asynchronous call - the callbacks come via propertyChange
    802         reply = dbus_connection_send_with_reply(nat->conn, msg, NULL, -1);
    803         dbus_message_unref(msg);
    804 
    805         env->ReleaseStringUTFChars(key, c_key);
    806         return reply ? JNI_TRUE : JNI_FALSE;
    807 
    808     }
    809 #endif
    810     return JNI_FALSE;
    811 }
    812 
    813 static jboolean setAdapterPropertyStringNative(JNIEnv *env, jobject object, jstring key,
    814                                                jstring value) {
    815 #ifdef HAVE_BLUETOOTH
    816     const char *c_value = env->GetStringUTFChars(value, NULL);
    817     jboolean ret =  setAdapterPropertyNative(env, object, key, (void *)&c_value, DBUS_TYPE_STRING);
    818     env->ReleaseStringUTFChars(value, (char *)c_value);
    819     return ret;
    820 #else
    821     return JNI_FALSE;
    822 #endif
    823 }
    824 
    825 static jboolean setAdapterPropertyIntegerNative(JNIEnv *env, jobject object, jstring key,
    826                                                jint value) {
    827 #ifdef HAVE_BLUETOOTH
    828     return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_UINT32);
    829 #else
    830     return JNI_FALSE;
    831 #endif
    832 }
    833 
    834 static jboolean setAdapterPropertyBooleanNative(JNIEnv *env, jobject object, jstring key,
    835                                                jint value) {
    836 #ifdef HAVE_BLUETOOTH
    837     return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_BOOLEAN);
    838 #else
    839     return JNI_FALSE;
    840 #endif
    841 }
    842 
    843 static jboolean setDevicePropertyNative(JNIEnv *env, jobject object, jstring path,
    844                                                jstring key, void *value, jint type) {
    845 #ifdef HAVE_BLUETOOTH
    846     LOGV("%s", __FUNCTION__);
    847     native_data_t *nat = get_native_data(env, object);
    848     if (nat) {
    849         DBusMessage *msg;
    850         DBusMessageIter iter;
    851         dbus_bool_t reply = JNI_FALSE;
    852 
    853         const char *c_key = env->GetStringUTFChars(key, NULL);
    854         const char *c_path = env->GetStringUTFChars(path, NULL);
    855 
    856         msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
    857                                           c_path, DBUS_DEVICE_IFACE, "SetProperty");
    858         if (!msg) {
    859             LOGE("%s: Can't allocate new method call for device SetProperty!", __FUNCTION__);
    860             env->ReleaseStringUTFChars(key, c_key);
    861             env->ReleaseStringUTFChars(path, c_path);
    862             return JNI_FALSE;
    863         }
    864 
    865         dbus_message_append_args(msg, DBUS_TYPE_STRING, &c_key, DBUS_TYPE_INVALID);
    866         dbus_message_iter_init_append(msg, &iter);
    867         append_variant(&iter, type, value);
    868 
    869         // Asynchronous call - the callbacks come via Device propertyChange
    870         reply = dbus_connection_send_with_reply(nat->conn, msg, NULL, -1);
    871         dbus_message_unref(msg);
    872 
    873         env->ReleaseStringUTFChars(path, c_path);
    874         env->ReleaseStringUTFChars(key, c_key);
    875 
    876         return reply ? JNI_TRUE : JNI_FALSE;
    877     }
    878 #endif
    879     return JNI_FALSE;
    880 }
    881 
    882 static jboolean setDevicePropertyBooleanNative(JNIEnv *env, jobject object,
    883                                                      jstring path, jstring key, jint value) {
    884 #ifdef HAVE_BLUETOOTH
    885     return setDevicePropertyNative(env, object, path, key,
    886                                         (void *)&value, DBUS_TYPE_BOOLEAN);
    887 #else
    888     return JNI_FALSE;
    889 #endif
    890 }
    891 
    892 static jboolean setDevicePropertyStringNative(JNIEnv *env, jobject object,
    893                                               jstring path, jstring key, jstring value) {
    894 #ifdef HAVE_BLUETOOTH
    895     const char *c_value = env->GetStringUTFChars(value, NULL);
    896     jboolean ret = setDevicePropertyNative(env, object, path, key,
    897                                            (void *)&c_value, DBUS_TYPE_STRING);
    898     env->ReleaseStringUTFChars(value, (char *)c_value);
    899     return ret;
    900 #else
    901     return JNI_FALSE;
    902 #endif
    903 }
    904 
    905 static jboolean createDeviceNative(JNIEnv *env, jobject object,
    906                                                 jstring address) {
    907     LOGV("%s", __FUNCTION__);
    908 #ifdef HAVE_BLUETOOTH
    909     native_data_t *nat = get_native_data(env, object);
    910     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
    911     struct event_loop_native_data_t *eventLoopNat =
    912             get_EventLoop_native_data(env, eventLoop);
    913 
    914     if (nat && eventLoopNat) {
    915         const char *c_address = env->GetStringUTFChars(address, NULL);
    916         LOGV("... address = %s", c_address);
    917         char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
    918         strlcpy(context_address, c_address, BTADDR_SIZE);  // for callback
    919 
    920         bool ret = dbus_func_args_async(env, nat->conn, -1,
    921                                         onCreateDeviceResult,
    922                                         context_address,
    923                                         eventLoopNat,
    924                                         get_adapter_path(env, object),
    925                                         DBUS_ADAPTER_IFACE,
    926                                         "CreateDevice",
    927                                         DBUS_TYPE_STRING, &c_address,
    928                                         DBUS_TYPE_INVALID);
    929         env->ReleaseStringUTFChars(address, c_address);
    930         return ret ? JNI_TRUE : JNI_FALSE;
    931     }
    932 #endif
    933     return JNI_FALSE;
    934 }
    935 
    936 static jboolean discoverServicesNative(JNIEnv *env, jobject object,
    937                                                jstring path, jstring pattern) {
    938     LOGV("%s", __FUNCTION__);
    939 #ifdef HAVE_BLUETOOTH
    940     native_data_t *nat = get_native_data(env, object);
    941     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
    942     struct event_loop_native_data_t *eventLoopNat =
    943             get_EventLoop_native_data(env, eventLoop);
    944 
    945     if (nat && eventLoopNat) {
    946         const char *c_path = env->GetStringUTFChars(path, NULL);
    947         const char *c_pattern = env->GetStringUTFChars(pattern, NULL);
    948         int len = env->GetStringLength(path) + 1;
    949         char *context_path = (char *)calloc(len, sizeof(char));
    950         strlcpy(context_path, c_path, len);  // for callback
    951 
    952         LOGV("... Object Path = %s", c_path);
    953         LOGV("... Pattern = %s, strlen = %d", c_pattern, strlen(c_pattern));
    954 
    955         bool ret = dbus_func_args_async(env, nat->conn, -1,
    956                                         onDiscoverServicesResult,
    957                                         context_path,
    958                                         eventLoopNat,
    959                                         c_path,
    960                                         DBUS_DEVICE_IFACE,
    961                                         "DiscoverServices",
    962                                         DBUS_TYPE_STRING, &c_pattern,
    963                                         DBUS_TYPE_INVALID);
    964         env->ReleaseStringUTFChars(path, c_path);
    965         env->ReleaseStringUTFChars(pattern, c_pattern);
    966         return ret ? JNI_TRUE : JNI_FALSE;
    967     }
    968 #endif
    969     return JNI_FALSE;
    970 }
    971 
    972 #ifdef HAVE_BLUETOOTH
    973 static jintArray extract_handles(JNIEnv *env, DBusMessage *reply) {
    974     jint *handles;
    975     jintArray handleArray = NULL;
    976     int len;
    977 
    978     DBusError err;
    979     dbus_error_init(&err);
    980 
    981     if (dbus_message_get_args(reply, &err,
    982                               DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &handles, &len,
    983                               DBUS_TYPE_INVALID)) {
    984         handleArray = env->NewIntArray(len);
    985         if (handleArray) {
    986             env->SetIntArrayRegion(handleArray, 0, len, handles);
    987         } else {
    988             LOGE("Null array in extract_handles");
    989         }
    990     } else {
    991         LOG_AND_FREE_DBUS_ERROR(&err);
    992     }
    993     return handleArray;
    994 }
    995 #endif
    996 
    997 static jintArray addReservedServiceRecordsNative(JNIEnv *env, jobject object,
    998                                                 jintArray uuids) {
    999     LOGV("%s", __FUNCTION__);
   1000 #ifdef HAVE_BLUETOOTH
   1001     DBusMessage *reply = NULL;
   1002 
   1003     native_data_t *nat = get_native_data(env, object);
   1004 
   1005     jint* svc_classes = env->GetIntArrayElements(uuids, NULL);
   1006     if (!svc_classes) return NULL;
   1007 
   1008     int len = env->GetArrayLength(uuids);
   1009     reply = dbus_func_args(env, nat->conn,
   1010                             get_adapter_path(env, object),
   1011                             DBUS_ADAPTER_IFACE, "AddReservedServiceRecords",
   1012                             DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
   1013                             &svc_classes, len, DBUS_TYPE_INVALID);
   1014     env->ReleaseIntArrayElements(uuids, svc_classes, 0);
   1015     return reply ? extract_handles(env, reply) : NULL;
   1016 
   1017 #endif
   1018     return NULL;
   1019 }
   1020 
   1021 static jboolean removeReservedServiceRecordsNative(JNIEnv *env, jobject object,
   1022                                                    jintArray handles) {
   1023     LOGV("%s", __FUNCTION__);
   1024 #ifdef HAVE_BLUETOOTH
   1025     native_data_t *nat = get_native_data(env, object);
   1026     jint *values = env->GetIntArrayElements(handles, NULL);
   1027     DBusMessage *msg = NULL;
   1028     DBusMessage *reply = NULL;
   1029     if (values == NULL) return JNI_FALSE;
   1030 
   1031     jsize len = env->GetArrayLength(handles);
   1032 
   1033     reply = dbus_func_args(env, nat->conn,
   1034                             get_adapter_path(env, object),
   1035                             DBUS_ADAPTER_IFACE, "RemoveReservedServiceRecords",
   1036                             DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
   1037                             &values, len, DBUS_TYPE_INVALID);
   1038     env->ReleaseIntArrayElements(handles, values, NULL);
   1039     return reply ? JNI_TRUE : JNI_FALSE;
   1040 #endif
   1041     return JNI_FALSE;
   1042 }
   1043 
   1044 static jint addRfcommServiceRecordNative(JNIEnv *env, jobject object,
   1045         jstring name, jlong uuidMsb, jlong uuidLsb, jshort channel) {
   1046     LOGV("%s", __FUNCTION__);
   1047 #ifdef HAVE_BLUETOOTH
   1048     native_data_t *nat = get_native_data(env, object);
   1049     if (nat) {
   1050         const char *c_name = env->GetStringUTFChars(name, NULL);
   1051         LOGV("... name = %s", c_name);
   1052         LOGV("... uuid1 = %llX", uuidMsb);
   1053         LOGV("... uuid2 = %llX", uuidLsb);
   1054         LOGV("... channel = %d", channel);
   1055         DBusMessage *reply = dbus_func_args(env, nat->conn,
   1056                            get_adapter_path(env, object),
   1057                            DBUS_ADAPTER_IFACE, "AddRfcommServiceRecord",
   1058                            DBUS_TYPE_STRING, &c_name,
   1059                            DBUS_TYPE_UINT64, &uuidMsb,
   1060                            DBUS_TYPE_UINT64, &uuidLsb,
   1061                            DBUS_TYPE_UINT16, &channel,
   1062                            DBUS_TYPE_INVALID);
   1063         env->ReleaseStringUTFChars(name, c_name);
   1064         return reply ? dbus_returns_uint32(env, reply) : -1;
   1065     }
   1066 #endif
   1067     return -1;
   1068 }
   1069 
   1070 static jboolean removeServiceRecordNative(JNIEnv *env, jobject object, jint handle) {
   1071     LOGV("%s", __FUNCTION__);
   1072 #ifdef HAVE_BLUETOOTH
   1073     native_data_t *nat = get_native_data(env, object);
   1074     if (nat) {
   1075         LOGV("... handle = %X", handle);
   1076         DBusMessage *reply = dbus_func_args(env, nat->conn,
   1077                            get_adapter_path(env, object),
   1078                            DBUS_ADAPTER_IFACE, "RemoveServiceRecord",
   1079                            DBUS_TYPE_UINT32, &handle,
   1080                            DBUS_TYPE_INVALID);
   1081         return reply ? JNI_TRUE : JNI_FALSE;
   1082     }
   1083 #endif
   1084     return JNI_FALSE;
   1085 }
   1086 
   1087 static jboolean setLinkTimeoutNative(JNIEnv *env, jobject object, jstring object_path,
   1088                                      jint num_slots) {
   1089     LOGV("%s", __FUNCTION__);
   1090 #ifdef HAVE_BLUETOOTH
   1091     native_data_t *nat = get_native_data(env, object);
   1092     if (nat) {
   1093         const char *c_object_path = env->GetStringUTFChars(object_path, NULL);
   1094         DBusMessage *reply = dbus_func_args(env, nat->conn,
   1095                            get_adapter_path(env, object),
   1096                            DBUS_ADAPTER_IFACE, "SetLinkTimeout",
   1097                            DBUS_TYPE_OBJECT_PATH, &c_object_path,
   1098                            DBUS_TYPE_UINT32, &num_slots,
   1099                            DBUS_TYPE_INVALID);
   1100         env->ReleaseStringUTFChars(object_path, c_object_path);
   1101         return reply ? JNI_TRUE : JNI_FALSE;
   1102     }
   1103 #endif
   1104     return JNI_FALSE;
   1105 }
   1106 
   1107 static jboolean connectInputDeviceNative(JNIEnv *env, jobject object, jstring path) {
   1108     LOGV("%s", __FUNCTION__);
   1109 #ifdef HAVE_BLUETOOTH
   1110     native_data_t *nat = get_native_data(env, object);
   1111     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
   1112     struct event_loop_native_data_t *eventLoopNat =
   1113             get_EventLoop_native_data(env, eventLoop);
   1114 
   1115     if (nat && eventLoopNat) {
   1116         const char *c_path = env->GetStringUTFChars(path, NULL);
   1117 
   1118         int len = env->GetStringLength(path) + 1;
   1119         char *context_path = (char *)calloc(len, sizeof(char));
   1120         strlcpy(context_path, c_path, len);  // for callback
   1121 
   1122         bool ret = dbus_func_args_async(env, nat->conn, -1, onInputDeviceConnectionResult,
   1123                                         context_path, eventLoopNat, c_path, DBUS_INPUT_IFACE,
   1124                                         "Connect",
   1125                                         DBUS_TYPE_INVALID);
   1126 
   1127         env->ReleaseStringUTFChars(path, c_path);
   1128         return ret ? JNI_TRUE : JNI_FALSE;
   1129     }
   1130 #endif
   1131     return JNI_FALSE;
   1132 }
   1133 
   1134 static jboolean disconnectInputDeviceNative(JNIEnv *env, jobject object,
   1135                                      jstring path) {
   1136     LOGV("%s", __FUNCTION__);
   1137 #ifdef HAVE_BLUETOOTH
   1138     native_data_t *nat = get_native_data(env, object);
   1139     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
   1140     struct event_loop_native_data_t *eventLoopNat =
   1141             get_EventLoop_native_data(env, eventLoop);
   1142 
   1143     if (nat && eventLoopNat) {
   1144         const char *c_path = env->GetStringUTFChars(path, NULL);
   1145 
   1146         int len = env->GetStringLength(path) + 1;
   1147         char *context_path = (char *)calloc(len, sizeof(char));
   1148         strlcpy(context_path, c_path, len);  // for callback
   1149 
   1150         bool ret = dbus_func_args_async(env, nat->conn, -1, onInputDeviceConnectionResult,
   1151                                         context_path, eventLoopNat, c_path, DBUS_INPUT_IFACE,
   1152                                         "Disconnect",
   1153                                         DBUS_TYPE_INVALID);
   1154 
   1155         env->ReleaseStringUTFChars(path, c_path);
   1156         return ret ? JNI_TRUE : JNI_FALSE;
   1157     }
   1158 #endif
   1159     return JNI_FALSE;
   1160 }
   1161 
   1162 static jboolean setBluetoothTetheringNative(JNIEnv *env, jobject object, jboolean value,
   1163                                             jstring src_role, jstring bridge) {
   1164     LOGV("%s", __FUNCTION__);
   1165 #ifdef HAVE_BLUETOOTH
   1166     native_data_t *nat = get_native_data(env, object);
   1167     if (nat) {
   1168         DBusMessage *reply;
   1169         const char *c_role = env->GetStringUTFChars(src_role, NULL);
   1170         const char *c_bridge = env->GetStringUTFChars(bridge, NULL);
   1171         if (value) {
   1172             LOGE("setBluetoothTetheringNative true");
   1173             reply = dbus_func_args(env, nat->conn,
   1174                                   get_adapter_path(env, object),
   1175                                   DBUS_NETWORKSERVER_IFACE,
   1176                                   "Register",
   1177                                   DBUS_TYPE_STRING, &c_role,
   1178                                   DBUS_TYPE_STRING, &c_bridge,
   1179                                   DBUS_TYPE_INVALID);
   1180         } else {
   1181             LOGE("setBluetoothTetheringNative false");
   1182             reply = dbus_func_args(env, nat->conn,
   1183                                   get_adapter_path(env, object),
   1184                                   DBUS_NETWORKSERVER_IFACE,
   1185                                   "Unregister",
   1186                                   DBUS_TYPE_STRING, &c_role,
   1187                                   DBUS_TYPE_INVALID);
   1188         }
   1189         env->ReleaseStringUTFChars(src_role, c_role);
   1190         env->ReleaseStringUTFChars(bridge, c_bridge);
   1191         return reply ? JNI_TRUE : JNI_FALSE;
   1192     }
   1193 #endif
   1194     return JNI_FALSE;
   1195 }
   1196 
   1197 static jboolean connectPanDeviceNative(JNIEnv *env, jobject object, jstring path,
   1198                                        jstring dstRole) {
   1199     LOGV("%s", __FUNCTION__);
   1200 #ifdef HAVE_BLUETOOTH
   1201     LOGE("connectPanDeviceNative");
   1202     native_data_t *nat = get_native_data(env, object);
   1203     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
   1204     struct event_loop_native_data_t *eventLoopNat =
   1205             get_EventLoop_native_data(env, eventLoop);
   1206 
   1207     if (nat && eventLoopNat) {
   1208         const char *c_path = env->GetStringUTFChars(path, NULL);
   1209         const char *dst = env->GetStringUTFChars(dstRole, NULL);
   1210 
   1211         int len = env->GetStringLength(path) + 1;
   1212         char *context_path = (char *)calloc(len, sizeof(char));
   1213         strlcpy(context_path, c_path, len);  // for callback
   1214 
   1215         bool ret = dbus_func_args_async(env, nat->conn, -1,onPanDeviceConnectionResult,
   1216                                     context_path, eventLoopNat, c_path,
   1217                                     DBUS_NETWORK_IFACE, "Connect",
   1218                                     DBUS_TYPE_STRING, &dst,
   1219                                     DBUS_TYPE_INVALID);
   1220 
   1221         env->ReleaseStringUTFChars(path, c_path);
   1222         env->ReleaseStringUTFChars(dstRole, dst);
   1223         return ret ? JNI_TRUE : JNI_FALSE;
   1224     }
   1225 #endif
   1226     return JNI_FALSE;
   1227 }
   1228 
   1229 static jboolean disconnectPanDeviceNative(JNIEnv *env, jobject object,
   1230                                      jstring path) {
   1231     LOGV("%s", __FUNCTION__);
   1232 #ifdef HAVE_BLUETOOTH
   1233     LOGE("disconnectPanDeviceNative");
   1234     native_data_t *nat = get_native_data(env, object);
   1235     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
   1236     struct event_loop_native_data_t *eventLoopNat =
   1237             get_EventLoop_native_data(env, eventLoop);
   1238 
   1239     if (nat && eventLoopNat) {
   1240         const char *c_path = env->GetStringUTFChars(path, NULL);
   1241 
   1242         int len = env->GetStringLength(path) + 1;
   1243         char *context_path = (char *)calloc(len, sizeof(char));
   1244         strlcpy(context_path, c_path, len);  // for callback
   1245 
   1246         bool ret = dbus_func_args_async(env, nat->conn, -1,onPanDeviceConnectionResult,
   1247                                         context_path, eventLoopNat, c_path,
   1248                                         DBUS_NETWORK_IFACE, "Disconnect",
   1249                                         DBUS_TYPE_INVALID);
   1250 
   1251         env->ReleaseStringUTFChars(path, c_path);
   1252         return ret ? JNI_TRUE : JNI_FALSE;
   1253     }
   1254 #endif
   1255     return JNI_FALSE;
   1256 }
   1257 
   1258 static jboolean disconnectPanServerDeviceNative(JNIEnv *env, jobject object,
   1259                                                 jstring path, jstring address,
   1260                                                 jstring iface) {
   1261     LOGV("%s", __FUNCTION__);
   1262 #ifdef HAVE_BLUETOOTH
   1263     LOGE("disconnectPanServerDeviceNative");
   1264     native_data_t *nat = get_native_data(env, object);
   1265     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
   1266     struct event_loop_native_data_t *eventLoopNat =
   1267             get_EventLoop_native_data(env, eventLoop);
   1268 
   1269     if (nat && eventLoopNat) {
   1270         const char *c_address = env->GetStringUTFChars(address, NULL);
   1271         const char *c_path = env->GetStringUTFChars(path, NULL);
   1272         const char *c_iface = env->GetStringUTFChars(iface, NULL);
   1273 
   1274         int len = env->GetStringLength(path) + 1;
   1275         char *context_path = (char *)calloc(len, sizeof(char));
   1276         strlcpy(context_path, c_path, len);  // for callback
   1277 
   1278         bool ret = dbus_func_args_async(env, nat->conn, -1,
   1279                                         onPanDeviceConnectionResult,
   1280                                         context_path, eventLoopNat,
   1281                                         get_adapter_path(env, object),
   1282                                         DBUS_NETWORKSERVER_IFACE,
   1283                                         "DisconnectDevice",
   1284                                         DBUS_TYPE_STRING, &c_address,
   1285                                         DBUS_TYPE_STRING, &c_iface,
   1286                                         DBUS_TYPE_INVALID);
   1287 
   1288         env->ReleaseStringUTFChars(address, c_address);
   1289         env->ReleaseStringUTFChars(iface, c_iface);
   1290         env->ReleaseStringUTFChars(path, c_path);
   1291         return ret ? JNI_TRUE : JNI_FALSE;
   1292     }
   1293 #endif
   1294     return JNI_FALSE;
   1295 }
   1296 
   1297 static jstring registerHealthApplicationNative(JNIEnv *env, jobject object,
   1298                                            jint dataType, jstring role,
   1299                                            jstring name, jstring channelType) {
   1300     LOGV("%s", __FUNCTION__);
   1301     jstring path = NULL;
   1302 #ifdef HAVE_BLUETOOTH
   1303     native_data_t *nat = get_native_data(env, object);
   1304     if (nat) {
   1305         const char *c_role = env->GetStringUTFChars(role, NULL);
   1306         const char *c_name = env->GetStringUTFChars(name, NULL);
   1307         const char *c_channel_type = env->GetStringUTFChars(channelType, NULL);
   1308         char *c_path;
   1309         DBusMessage *msg, *reply;
   1310         DBusError err;
   1311         dbus_error_init(&err);
   1312 
   1313         msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
   1314                                             DBUS_HEALTH_MANAGER_PATH,
   1315                                             DBUS_HEALTH_MANAGER_IFACE,
   1316                                             "CreateApplication");
   1317 
   1318         if (msg == NULL) {
   1319             LOGE("Could not allocate D-Bus message object!");
   1320             return NULL;
   1321         }
   1322 
   1323         /* append arguments */
   1324         append_dict_args(msg,
   1325                          "DataType", DBUS_TYPE_UINT16, &dataType,
   1326                          "Role", DBUS_TYPE_STRING, &c_role,
   1327                          "Description", DBUS_TYPE_STRING, &c_name,
   1328                          "ChannelType", DBUS_TYPE_STRING, &c_channel_type,
   1329                          DBUS_TYPE_INVALID);
   1330 
   1331 
   1332         /* Make the call. */
   1333         reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
   1334 
   1335         env->ReleaseStringUTFChars(role, c_role);
   1336         env->ReleaseStringUTFChars(name, c_name);
   1337         env->ReleaseStringUTFChars(channelType, c_channel_type);
   1338 
   1339         if (!reply) {
   1340             if (dbus_error_is_set(&err)) {
   1341                 LOG_AND_FREE_DBUS_ERROR(&err);
   1342             }
   1343         } else {
   1344             if (!dbus_message_get_args(reply, &err,
   1345                                       DBUS_TYPE_OBJECT_PATH, &c_path,
   1346                                       DBUS_TYPE_INVALID)) {
   1347                 if (dbus_error_is_set(&err)) {
   1348                     LOG_AND_FREE_DBUS_ERROR(&err);
   1349                 }
   1350             } else {
   1351                path = env->NewStringUTF(c_path);
   1352             }
   1353             dbus_message_unref(reply);
   1354         }
   1355     }
   1356 #endif
   1357     return path;
   1358 }
   1359 
   1360 static jstring registerSinkHealthApplicationNative(JNIEnv *env, jobject object,
   1361                                            jint dataType, jstring role,
   1362                                            jstring name) {
   1363     LOGV("%s", __FUNCTION__);
   1364     jstring path = NULL;
   1365 #ifdef HAVE_BLUETOOTH
   1366     native_data_t *nat = get_native_data(env, object);
   1367     if (nat) {
   1368         const char *c_role = env->GetStringUTFChars(role, NULL);
   1369         const char *c_name = env->GetStringUTFChars(name, NULL);
   1370         char *c_path;
   1371 
   1372         DBusMessage *msg, *reply;
   1373         DBusError err;
   1374         dbus_error_init(&err);
   1375 
   1376         msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
   1377                                             DBUS_HEALTH_MANAGER_PATH,
   1378                                             DBUS_HEALTH_MANAGER_IFACE,
   1379                                             "CreateApplication");
   1380 
   1381         if (msg == NULL) {
   1382             LOGE("Could not allocate D-Bus message object!");
   1383             return NULL;
   1384         }
   1385 
   1386         /* append arguments */
   1387         append_dict_args(msg,
   1388                          "DataType", DBUS_TYPE_UINT16, &dataType,
   1389                          "Role", DBUS_TYPE_STRING, &c_role,
   1390                          "Description", DBUS_TYPE_STRING, &c_name,
   1391                          DBUS_TYPE_INVALID);
   1392 
   1393 
   1394         /* Make the call. */
   1395         reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
   1396 
   1397         env->ReleaseStringUTFChars(role, c_role);
   1398         env->ReleaseStringUTFChars(name, c_name);
   1399 
   1400         if (!reply) {
   1401             if (dbus_error_is_set(&err)) {
   1402                 LOG_AND_FREE_DBUS_ERROR(&err);
   1403             }
   1404         } else {
   1405             if (!dbus_message_get_args(reply, &err,
   1406                                       DBUS_TYPE_OBJECT_PATH, &c_path,
   1407                                       DBUS_TYPE_INVALID)) {
   1408                 if (dbus_error_is_set(&err)) {
   1409                     LOG_AND_FREE_DBUS_ERROR(&err);
   1410                 }
   1411             } else {
   1412                 path = env->NewStringUTF(c_path);
   1413             }
   1414             dbus_message_unref(reply);
   1415         }
   1416     }
   1417 #endif
   1418     return path;
   1419 }
   1420 
   1421 static jboolean unregisterHealthApplicationNative(JNIEnv *env, jobject object,
   1422                                                     jstring path) {
   1423     LOGV("%s", __FUNCTION__);
   1424     jboolean result = JNI_FALSE;
   1425 #ifdef HAVE_BLUETOOTH
   1426     native_data_t *nat = get_native_data(env, object);
   1427     if (nat) {
   1428         const char *c_path = env->GetStringUTFChars(path, NULL);
   1429         DBusError err;
   1430         dbus_error_init(&err);
   1431         DBusMessage *reply =
   1432             dbus_func_args_timeout(env, nat->conn, -1,
   1433                                    DBUS_HEALTH_MANAGER_PATH,
   1434                                    DBUS_HEALTH_MANAGER_IFACE, "DestroyApplication",
   1435                                    DBUS_TYPE_OBJECT_PATH, &c_path,
   1436                                    DBUS_TYPE_INVALID);
   1437 
   1438         env->ReleaseStringUTFChars(path, c_path);
   1439 
   1440         if (!reply) {
   1441             if (dbus_error_is_set(&err)) {
   1442                 LOG_AND_FREE_DBUS_ERROR(&err);
   1443             }
   1444         } else {
   1445             result = JNI_TRUE;
   1446         }
   1447     }
   1448 #endif
   1449     return result;
   1450 }
   1451 
   1452 static jboolean createChannelNative(JNIEnv *env, jobject object,
   1453                                        jstring devicePath, jstring appPath, jstring config,
   1454                                        jint code) {
   1455     LOGV("%s", __FUNCTION__);
   1456 #ifdef HAVE_BLUETOOTH
   1457     native_data_t *nat = get_native_data(env, object);
   1458     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
   1459     struct event_loop_native_data_t *eventLoopNat =
   1460             get_EventLoop_native_data(env, eventLoop);
   1461 
   1462     if (nat && eventLoopNat) {
   1463         const char *c_device_path = env->GetStringUTFChars(devicePath, NULL);
   1464         const char *c_app_path = env->GetStringUTFChars(appPath, NULL);
   1465         const char *c_config = env->GetStringUTFChars(config, NULL);
   1466         int *data = (int *) malloc(sizeof(int));
   1467         if (data == NULL) return JNI_FALSE;
   1468 
   1469         *data = code;
   1470         bool ret = dbus_func_args_async(env, nat->conn, -1, onHealthDeviceConnectionResult,
   1471                                         data, eventLoopNat, c_device_path,
   1472                                         DBUS_HEALTH_DEVICE_IFACE, "CreateChannel",
   1473                                         DBUS_TYPE_OBJECT_PATH, &c_app_path,
   1474                                         DBUS_TYPE_STRING, &c_config,
   1475                                         DBUS_TYPE_INVALID);
   1476 
   1477 
   1478         env->ReleaseStringUTFChars(devicePath, c_device_path);
   1479         env->ReleaseStringUTFChars(appPath, c_app_path);
   1480         env->ReleaseStringUTFChars(config, c_config);
   1481 
   1482         return ret ? JNI_TRUE : JNI_FALSE;
   1483     }
   1484 #endif
   1485     return JNI_FALSE;
   1486 }
   1487 
   1488 static jboolean destroyChannelNative(JNIEnv *env, jobject object, jstring devicePath,
   1489                                      jstring channelPath, jint code) {
   1490     LOGE("%s", __FUNCTION__);
   1491 #ifdef HAVE_BLUETOOTH
   1492     native_data_t *nat = get_native_data(env, object);
   1493     jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
   1494     struct event_loop_native_data_t *eventLoopNat =
   1495             get_EventLoop_native_data(env, eventLoop);
   1496 
   1497     if (nat && eventLoopNat) {
   1498         const char *c_device_path = env->GetStringUTFChars(devicePath, NULL);
   1499         const char *c_channel_path = env->GetStringUTFChars(channelPath, NULL);
   1500         int *data = (int *) malloc(sizeof(int));
   1501         if (data == NULL) return JNI_FALSE;
   1502 
   1503         *data = code;
   1504         bool ret = dbus_func_args_async(env, nat->conn, -1, onHealthDeviceConnectionResult,
   1505                                         data, eventLoopNat, c_device_path,
   1506                                         DBUS_HEALTH_DEVICE_IFACE, "DestroyChannel",
   1507                                         DBUS_TYPE_OBJECT_PATH, &c_channel_path,
   1508                                         DBUS_TYPE_INVALID);
   1509 
   1510         env->ReleaseStringUTFChars(devicePath, c_device_path);
   1511         env->ReleaseStringUTFChars(channelPath, c_channel_path);
   1512 
   1513         return ret ? JNI_TRUE : JNI_FALSE;
   1514     }
   1515 #endif
   1516     return JNI_FALSE;
   1517 }
   1518 
   1519 static jstring getMainChannelNative(JNIEnv *env, jobject object, jstring devicePath) {
   1520     LOGE("%s", __FUNCTION__);
   1521 #ifdef HAVE_BLUETOOTH
   1522     native_data_t *nat = get_native_data(env, object);
   1523     if (nat) {
   1524         const char *c_device_path = env->GetStringUTFChars(devicePath, NULL);
   1525         DBusError err;
   1526         dbus_error_init(&err);
   1527 
   1528         DBusMessage *reply = dbus_func_args(env, nat->conn,
   1529                            c_device_path,
   1530                            DBUS_HEALTH_DEVICE_IFACE, "GetProperties",
   1531                            DBUS_TYPE_INVALID);
   1532         env->ReleaseStringUTFChars(devicePath, c_device_path);
   1533 
   1534         if (!reply) {
   1535             if (dbus_error_is_set(&err)) {
   1536                 LOG_AND_FREE_DBUS_ERROR(&err);
   1537             }
   1538         } else {
   1539             DBusMessageIter iter;
   1540             jobjectArray str_array = NULL;
   1541             if (dbus_message_iter_init(reply, &iter))
   1542                 str_array = parse_health_device_properties(env, &iter);
   1543             dbus_message_unref(reply);
   1544             jstring path = (jstring) env->GetObjectArrayElement(str_array, 1);
   1545 
   1546             return path;
   1547         }
   1548     }
   1549 #endif
   1550     return NULL;
   1551 }
   1552 
   1553 static jstring getChannelApplicationNative(JNIEnv *env, jobject object, jstring channelPath) {
   1554     LOGE("%s", __FUNCTION__);
   1555 #ifdef HAVE_BLUETOOTH
   1556     native_data_t *nat = get_native_data(env, object);
   1557     if (nat) {
   1558         const char *c_channel_path = env->GetStringUTFChars(channelPath, NULL);
   1559         DBusError err;
   1560         dbus_error_init(&err);
   1561 
   1562         DBusMessage *reply = dbus_func_args(env, nat->conn,
   1563                                             c_channel_path,
   1564                                             DBUS_HEALTH_CHANNEL_IFACE, "GetProperties",
   1565                                             DBUS_TYPE_INVALID);
   1566         env->ReleaseStringUTFChars(channelPath, c_channel_path);
   1567 
   1568         if (!reply) {
   1569             if (dbus_error_is_set(&err)) {
   1570                 LOG_AND_FREE_DBUS_ERROR(&err);
   1571             }
   1572         } else {
   1573             DBusMessageIter iter;
   1574             jobjectArray str_array = NULL;
   1575             if (dbus_message_iter_init(reply, &iter))
   1576                 str_array = parse_health_channel_properties(env, &iter);
   1577             dbus_message_unref(reply);
   1578 
   1579             jint len = env->GetArrayLength(str_array);
   1580 
   1581             jstring name, path;
   1582             const char *c_name;
   1583 
   1584             for (int i = 0; i < len; i+=2) {
   1585                 name = (jstring) env->GetObjectArrayElement(str_array, i);
   1586                 c_name = env->GetStringUTFChars(name, NULL);
   1587 
   1588                 if (!strcmp(c_name, "Application")) {
   1589                     path = (jstring) env->GetObjectArrayElement(str_array, i+1);
   1590                     env->ReleaseStringUTFChars(name, c_name);
   1591                     return path;
   1592                 }
   1593                 env->ReleaseStringUTFChars(name, c_name);
   1594             }
   1595         }
   1596     }
   1597 #endif
   1598     return NULL;
   1599 }
   1600 
   1601 static jboolean releaseChannelFdNative(JNIEnv *env, jobject object, jstring channelPath) {
   1602     LOGV("%s", __FUNCTION__);
   1603 #ifdef HAVE_BLUETOOTH
   1604     native_data_t *nat = get_native_data(env, object);
   1605     if (nat) {
   1606         const char *c_channel_path = env->GetStringUTFChars(channelPath, NULL);
   1607         DBusError err;
   1608         dbus_error_init(&err);
   1609 
   1610         DBusMessage *reply = dbus_func_args(env, nat->conn,
   1611                                             c_channel_path,
   1612                                             DBUS_HEALTH_CHANNEL_IFACE, "Release",
   1613                                             DBUS_TYPE_INVALID);
   1614         env->ReleaseStringUTFChars(channelPath, c_channel_path);
   1615 
   1616         return reply ? JNI_TRUE : JNI_FALSE;
   1617     }
   1618 #endif
   1619     return JNI_FALSE;
   1620 }
   1621 
   1622 static jobject getChannelFdNative(JNIEnv *env, jobject object, jstring channelPath) {
   1623     LOGV("%s", __FUNCTION__);
   1624 #ifdef HAVE_BLUETOOTH
   1625     native_data_t *nat = get_native_data(env, object);
   1626     if (nat) {
   1627         const char *c_channel_path = env->GetStringUTFChars(channelPath, NULL);
   1628         int32_t fd;
   1629         DBusError err;
   1630         dbus_error_init(&err);
   1631 
   1632         DBusMessage *reply = dbus_func_args(env, nat->conn,
   1633                                             c_channel_path,
   1634                                             DBUS_HEALTH_CHANNEL_IFACE, "Acquire",
   1635                                             DBUS_TYPE_INVALID);
   1636         env->ReleaseStringUTFChars(channelPath, c_channel_path);
   1637 
   1638         if (!reply) {
   1639             if (dbus_error_is_set(&err)) {
   1640                 LOG_AND_FREE_DBUS_ERROR(&err);
   1641             }
   1642             return NULL;
   1643         }
   1644 
   1645         fd = dbus_returns_unixfd(env, reply);
   1646         if (fd == -1) return NULL;
   1647 
   1648         // Create FileDescriptor object
   1649         jobject fileDesc = jniCreateFileDescriptor(env, fd);
   1650         if (fileDesc == NULL) {
   1651             // FileDescriptor constructor has thrown an exception
   1652             releaseChannelFdNative(env, object, channelPath);
   1653             close(fd);
   1654             return NULL;
   1655         }
   1656 
   1657         // Wrap it in a ParcelFileDescriptor
   1658         jobject parcelFileDesc = newParcelFileDescriptor(env, fileDesc);
   1659         if (parcelFileDesc == NULL) {
   1660             // ParcelFileDescriptor constructor has thrown an exception
   1661             releaseChannelFdNative(env, object, channelPath);
   1662             close(fd);
   1663             return NULL;
   1664         }
   1665 
   1666         return parcelFileDesc;
   1667     }
   1668 #endif
   1669     return NULL;
   1670 }
   1671 
   1672 
   1673 
   1674 static JNINativeMethod sMethods[] = {
   1675      /* name, signature, funcPtr */
   1676     {"classInitNative", "()V", (void*)classInitNative},
   1677     {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
   1678     {"setupNativeDataNative", "()Z", (void *)setupNativeDataNative},
   1679     {"tearDownNativeDataNative", "()Z", (void *)tearDownNativeDataNative},
   1680     {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
   1681     {"getAdapterPathNative", "()Ljava/lang/String;", (void*)getAdapterPathNative},
   1682 
   1683     {"isEnabledNative", "()I", (void *)isEnabledNative},
   1684     {"enableNative", "()I", (void *)enableNative},
   1685     {"disableNative", "()I", (void *)disableNative},
   1686 
   1687     {"getAdapterPropertiesNative", "()[Ljava/lang/Object;", (void *)getAdapterPropertiesNative},
   1688     {"getDevicePropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
   1689       (void *)getDevicePropertiesNative},
   1690     {"setAdapterPropertyStringNative", "(Ljava/lang/String;Ljava/lang/String;)Z",
   1691       (void *)setAdapterPropertyStringNative},
   1692     {"setAdapterPropertyBooleanNative", "(Ljava/lang/String;I)Z",
   1693       (void *)setAdapterPropertyBooleanNative},
   1694     {"setAdapterPropertyIntegerNative", "(Ljava/lang/String;I)Z",
   1695       (void *)setAdapterPropertyIntegerNative},
   1696 
   1697     {"startDiscoveryNative", "()Z", (void*)startDiscoveryNative},
   1698     {"stopDiscoveryNative", "()Z", (void *)stopDiscoveryNative},
   1699 
   1700     {"readAdapterOutOfBandDataNative", "()[B", (void *)readAdapterOutOfBandDataNative},
   1701     {"createPairedDeviceNative", "(Ljava/lang/String;I)Z", (void *)createPairedDeviceNative},
   1702     {"createPairedDeviceOutOfBandNative", "(Ljava/lang/String;I)Z",
   1703                                     (void *)createPairedDeviceOutOfBandNative},
   1704     {"cancelDeviceCreationNative", "(Ljava/lang/String;)Z", (void *)cancelDeviceCreationNative},
   1705     {"removeDeviceNative", "(Ljava/lang/String;)Z", (void *)removeDeviceNative},
   1706     {"getDeviceServiceChannelNative", "(Ljava/lang/String;Ljava/lang/String;I)I",
   1707       (void *)getDeviceServiceChannelNative},
   1708 
   1709     {"setPairingConfirmationNative", "(Ljava/lang/String;ZI)Z",
   1710             (void *)setPairingConfirmationNative},
   1711     {"setPasskeyNative", "(Ljava/lang/String;II)Z", (void *)setPasskeyNative},
   1712     {"setRemoteOutOfBandDataNative", "(Ljava/lang/String;[B[BI)Z", (void *)setRemoteOutOfBandDataNative},
   1713     {"setAuthorizationNative", "(Ljava/lang/String;ZI)Z", (void *)setAuthorizationNative},
   1714     {"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative},
   1715     {"cancelPairingUserInputNative", "(Ljava/lang/String;I)Z",
   1716             (void *)cancelPairingUserInputNative},
   1717     {"setDevicePropertyBooleanNative", "(Ljava/lang/String;Ljava/lang/String;I)Z",
   1718             (void *)setDevicePropertyBooleanNative},
   1719     {"setDevicePropertyStringNative", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
   1720             (void *)setDevicePropertyStringNative},
   1721     {"createDeviceNative", "(Ljava/lang/String;)Z", (void *)createDeviceNative},
   1722     {"discoverServicesNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)discoverServicesNative},
   1723     {"addRfcommServiceRecordNative", "(Ljava/lang/String;JJS)I", (void *)addRfcommServiceRecordNative},
   1724     {"removeServiceRecordNative", "(I)Z", (void *)removeServiceRecordNative},
   1725     {"addReservedServiceRecordsNative", "([I)[I", (void *) addReservedServiceRecordsNative},
   1726     {"removeReservedServiceRecordsNative", "([I)Z", (void *) removeReservedServiceRecordsNative},
   1727     {"setLinkTimeoutNative", "(Ljava/lang/String;I)Z", (void *)setLinkTimeoutNative},
   1728     // HID functions
   1729     {"connectInputDeviceNative", "(Ljava/lang/String;)Z", (void *)connectInputDeviceNative},
   1730     {"disconnectInputDeviceNative", "(Ljava/lang/String;)Z", (void *)disconnectInputDeviceNative},
   1731 
   1732     {"setBluetoothTetheringNative", "(ZLjava/lang/String;Ljava/lang/String;)Z",
   1733               (void *)setBluetoothTetheringNative},
   1734     {"connectPanDeviceNative", "(Ljava/lang/String;Ljava/lang/String;)Z",
   1735               (void *)connectPanDeviceNative},
   1736     {"disconnectPanDeviceNative", "(Ljava/lang/String;)Z", (void *)disconnectPanDeviceNative},
   1737     {"disconnectPanServerDeviceNative", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
   1738               (void *)disconnectPanServerDeviceNative},
   1739     // Health function
   1740     {"registerHealthApplicationNative",
   1741               "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
   1742               (void *)registerHealthApplicationNative},
   1743     {"registerHealthApplicationNative",
   1744             "(ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
   1745             (void *)registerSinkHealthApplicationNative},
   1746 
   1747     {"unregisterHealthApplicationNative", "(Ljava/lang/String;)Z",
   1748               (void *)unregisterHealthApplicationNative},
   1749     {"createChannelNative", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Z",
   1750               (void *)createChannelNative},
   1751     {"destroyChannelNative", "(Ljava/lang/String;Ljava/lang/String;I)Z",
   1752               (void *)destroyChannelNative},
   1753     {"getMainChannelNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getMainChannelNative},
   1754     {"getChannelApplicationNative", "(Ljava/lang/String;)Ljava/lang/String;",
   1755               (void *)getChannelApplicationNative},
   1756     {"getChannelFdNative", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;", (void *)getChannelFdNative},
   1757     {"releaseChannelFdNative", "(Ljava/lang/String;)Z", (void *)releaseChannelFdNative},
   1758 };
   1759 
   1760 
   1761 int register_android_server_BluetoothService(JNIEnv *env) {
   1762     return AndroidRuntime::registerNativeMethods(env,
   1763                 "android/server/BluetoothService", sMethods, NELEM(sMethods));
   1764 }
   1765 
   1766 } /* namespace android */
   1767