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
55namespace 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
63static jfieldID field_mNativeData;
64static jfieldID field_mEventLoop;
65
66typedef struct {
67    JNIEnv *env;
68    DBusConnection *conn;
69    const char *adapter;  // dbus object name of the local adapter
70} native_data_t;
71
72extern event_loop_native_data_t *get_EventLoop_native_data(JNIEnv *,
73                                                           jobject);
74extern DBusHandlerResult agent_event_filter(DBusConnection *conn,
75                                            DBusMessage *msg,
76                                            void *data);
77void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *nat);
78void onDiscoverServicesResult(DBusMessage *msg, void *user, void *nat);
79void onCreateDeviceResult(DBusMessage *msg, void *user, void *nat);
80void onInputDeviceConnectionResult(DBusMessage *msg, void *user, void *nat);
81void onPanDeviceConnectionResult(DBusMessage *msg, void *user, void *nat);
82void 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 */
88static 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
99static 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*/
111static 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
136static 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.
150static 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
173static 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
187static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
188    LOGV("%s", __FUNCTION__);
189#ifdef HAVE_BLUETOOTH
190    native_data_t *nat =
191        (native_data_t *)env->GetIntField(object, field_mNativeData);
192    if (nat) {
193        free(nat);
194        nat = NULL;
195    }
196#endif
197}
198
199static 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
211static 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;
248done:
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
257static 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;
299done:
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
308static 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
348static 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
384static 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
419static 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
447static 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
480static 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
502static 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
510static 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
518static 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
526static 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
558static 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
585static 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
619static 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
648static 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
678static 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
703static 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
742static 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
776static 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
813static 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
825static 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
834static 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
843static 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
882static 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
892static 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
905static 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
936static 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
973static 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
997static 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
1021static 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
1044static 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
1070static 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
1087static 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
1107static 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
1134static 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
1162static 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
1197static 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
1229static 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
1258static 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
1297static 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
1360static 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
1421static 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
1452static 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
1488static 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
1519static 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
1553static 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
1601static 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
1622static 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
1674static 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
1761int register_android_server_BluetoothService(JNIEnv *env) {
1762    return AndroidRuntime::registerNativeMethods(env,
1763                "android/server/BluetoothService", sMethods, NELEM(sMethods));
1764}
1765
1766} /* namespace android */
1767