Home | History | Annotate | Download | only in jni
      1 /*
      2 ** Copyright 2008, The Android Open Source Project
      3 **
      4 ** Licensed under the Apache License, Version 2.0 (the "License");
      5 ** you may not use this file except in compliance with the License.
      6 ** You may obtain a copy of the License at
      7 **
      8 **     http://www.apache.org/licenses/LICENSE-2.0
      9 **
     10 ** Unless required by applicable law or agreed to in writing, software
     11 ** distributed under the License is distributed on an "AS IS" BASIS,
     12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 ** See the License for the specific language governing permissions and
     14 ** limitations under the License.
     15 */
     16 
     17 #define LOG_TAG "BluetoothEventLoop.cpp"
     18 
     19 #include "android_bluetooth_common.h"
     20 #include "android_runtime/AndroidRuntime.h"
     21 #include "cutils/sockets.h"
     22 #include "JNIHelp.h"
     23 #include "jni.h"
     24 #include "utils/Log.h"
     25 #include "utils/misc.h"
     26 
     27 #include <stdio.h>
     28 #include <string.h>
     29 #include <stdlib.h>
     30 #include <errno.h>
     31 #include <unistd.h>
     32 
     33 #ifdef HAVE_BLUETOOTH
     34 #include <dbus/dbus.h>
     35 #endif
     36 
     37 namespace android {
     38 
     39 #define CREATE_DEVICE_ALREADY_EXISTS 1
     40 #define CREATE_DEVICE_SUCCESS 0
     41 #define CREATE_DEVICE_FAILED -1
     42 
     43 #ifdef HAVE_BLUETOOTH
     44 static jfieldID field_mNativeData;
     45 
     46 static jmethodID method_onPropertyChanged;
     47 static jmethodID method_onDevicePropertyChanged;
     48 static jmethodID method_onDeviceFound;
     49 static jmethodID method_onDeviceDisappeared;
     50 static jmethodID method_onDeviceCreated;
     51 static jmethodID method_onDeviceRemoved;
     52 static jmethodID method_onDeviceDisconnectRequested;
     53 
     54 static jmethodID method_onCreatePairedDeviceResult;
     55 static jmethodID method_onCreateDeviceResult;
     56 static jmethodID method_onDiscoverServicesResult;
     57 static jmethodID method_onGetDeviceServiceChannelResult;
     58 
     59 static jmethodID method_onRequestPinCode;
     60 static jmethodID method_onRequestPasskey;
     61 static jmethodID method_onRequestPasskeyConfirmation;
     62 static jmethodID method_onRequestPairingConsent;
     63 static jmethodID method_onDisplayPasskey;
     64 static jmethodID method_onRequestOobData;
     65 static jmethodID method_onAgentOutOfBandDataAvailable;
     66 static jmethodID method_onAgentAuthorize;
     67 static jmethodID method_onAgentCancel;
     68 
     69 typedef event_loop_native_data_t native_data_t;
     70 
     71 #define EVENT_LOOP_REFS 10
     72 
     73 static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
     74     return (native_data_t *)(env->GetIntField(object,
     75                                                  field_mNativeData));
     76 }
     77 
     78 native_data_t *get_EventLoop_native_data(JNIEnv *env, jobject object) {
     79     return get_native_data(env, object);
     80 }
     81 
     82 #endif
     83 static void classInitNative(JNIEnv* env, jclass clazz) {
     84     LOGV(__FUNCTION__);
     85 
     86 #ifdef HAVE_BLUETOOTH
     87     method_onPropertyChanged = env->GetMethodID(clazz, "onPropertyChanged",
     88                                                 "([Ljava/lang/String;)V");
     89     method_onDevicePropertyChanged = env->GetMethodID(clazz,
     90                                                       "onDevicePropertyChanged",
     91                                                       "(Ljava/lang/String;[Ljava/lang/String;)V");
     92     method_onDeviceFound = env->GetMethodID(clazz, "onDeviceFound",
     93                                             "(Ljava/lang/String;[Ljava/lang/String;)V");
     94     method_onDeviceDisappeared = env->GetMethodID(clazz, "onDeviceDisappeared",
     95                                                   "(Ljava/lang/String;)V");
     96     method_onDeviceCreated = env->GetMethodID(clazz, "onDeviceCreated", "(Ljava/lang/String;)V");
     97     method_onDeviceRemoved = env->GetMethodID(clazz, "onDeviceRemoved", "(Ljava/lang/String;)V");
     98     method_onDeviceDisconnectRequested = env->GetMethodID(clazz, "onDeviceDisconnectRequested",
     99                                                         "(Ljava/lang/String;)V");
    100 
    101     method_onCreatePairedDeviceResult = env->GetMethodID(clazz, "onCreatePairedDeviceResult",
    102                                                          "(Ljava/lang/String;I)V");
    103     method_onCreateDeviceResult = env->GetMethodID(clazz, "onCreateDeviceResult",
    104                                                          "(Ljava/lang/String;I)V");
    105     method_onDiscoverServicesResult = env->GetMethodID(clazz, "onDiscoverServicesResult",
    106                                                          "(Ljava/lang/String;Z)V");
    107 
    108     method_onAgentAuthorize = env->GetMethodID(clazz, "onAgentAuthorize",
    109                                                "(Ljava/lang/String;Ljava/lang/String;I)V");
    110     method_onAgentOutOfBandDataAvailable = env->GetMethodID(clazz, "onAgentOutOfBandDataAvailable",
    111                                                "(Ljava/lang/String;)Z");
    112     method_onAgentCancel = env->GetMethodID(clazz, "onAgentCancel", "()V");
    113     method_onRequestPinCode = env->GetMethodID(clazz, "onRequestPinCode",
    114                                                "(Ljava/lang/String;I)V");
    115     method_onRequestPasskey = env->GetMethodID(clazz, "onRequestPasskey",
    116                                                "(Ljava/lang/String;I)V");
    117     method_onRequestPasskeyConfirmation = env->GetMethodID(clazz, "onRequestPasskeyConfirmation",
    118                                                "(Ljava/lang/String;II)V");
    119     method_onRequestPairingConsent = env->GetMethodID(clazz, "onRequestPairingConsent",
    120                                                "(Ljava/lang/String;I)V");
    121     method_onDisplayPasskey = env->GetMethodID(clazz, "onDisplayPasskey",
    122                                                "(Ljava/lang/String;II)V");
    123     method_onRequestOobData = env->GetMethodID(clazz, "onRequestOobData",
    124                                                "(Ljava/lang/String;I)V");
    125 
    126     field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I");
    127 #endif
    128 }
    129 
    130 static void initializeNativeDataNative(JNIEnv* env, jobject object) {
    131     LOGV(__FUNCTION__);
    132 #ifdef HAVE_BLUETOOTH
    133     native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
    134     if (NULL == nat) {
    135         LOGE("%s: out of memory!", __FUNCTION__);
    136         return;
    137     }
    138     memset(nat, 0, sizeof(native_data_t));
    139 
    140     pthread_mutex_init(&(nat->thread_mutex), NULL);
    141 
    142     env->SetIntField(object, field_mNativeData, (jint)nat);
    143 
    144     {
    145         DBusError err;
    146         dbus_error_init(&err);
    147         dbus_threads_init_default();
    148         nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
    149         if (dbus_error_is_set(&err)) {
    150             LOGE("%s: Could not get onto the system bus!", __FUNCTION__);
    151             dbus_error_free(&err);
    152         }
    153         dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
    154     }
    155 #endif
    156 }
    157 
    158 static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
    159     LOGV(__FUNCTION__);
    160 #ifdef HAVE_BLUETOOTH
    161     native_data_t *nat =
    162             (native_data_t *)env->GetIntField(object, field_mNativeData);
    163 
    164     pthread_mutex_destroy(&(nat->thread_mutex));
    165 
    166     if (nat) {
    167         free(nat);
    168     }
    169 #endif
    170 }
    171 
    172 #ifdef HAVE_BLUETOOTH
    173 static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
    174                                       void *data);
    175 DBusHandlerResult agent_event_filter(DBusConnection *conn,
    176                                      DBusMessage *msg,
    177                                      void *data);
    178 static int register_agent(native_data_t *nat,
    179                           const char *agent_path, const char *capabilities);
    180 
    181 static const DBusObjectPathVTable agent_vtable = {
    182     NULL, agent_event_filter, NULL, NULL, NULL, NULL
    183 };
    184 
    185 static unsigned int unix_events_to_dbus_flags(short events) {
    186     return (events & DBUS_WATCH_READABLE ? POLLIN : 0) |
    187            (events & DBUS_WATCH_WRITABLE ? POLLOUT : 0) |
    188            (events & DBUS_WATCH_ERROR ? POLLERR : 0) |
    189            (events & DBUS_WATCH_HANGUP ? POLLHUP : 0);
    190 }
    191 
    192 static short dbus_flags_to_unix_events(unsigned int flags) {
    193     return (flags & POLLIN ? DBUS_WATCH_READABLE : 0) |
    194            (flags & POLLOUT ? DBUS_WATCH_WRITABLE : 0) |
    195            (flags & POLLERR ? DBUS_WATCH_ERROR : 0) |
    196            (flags & POLLHUP ? DBUS_WATCH_HANGUP : 0);
    197 }
    198 
    199 static jboolean setUpEventLoop(native_data_t *nat) {
    200     LOGV(__FUNCTION__);
    201 
    202     if (nat != NULL && nat->conn != NULL) {
    203         dbus_threads_init_default();
    204         DBusError err;
    205         dbus_error_init(&err);
    206 
    207         // Add a filter for all incoming messages
    208         if (!dbus_connection_add_filter(nat->conn, event_filter, nat, NULL)){
    209             return JNI_FALSE;
    210         }
    211 
    212         // Set which messages will be processed by this dbus connection
    213         dbus_bus_add_match(nat->conn,
    214                 "type='signal',interface='org.freedesktop.DBus'",
    215                 &err);
    216         if (dbus_error_is_set(&err)) {
    217             LOG_AND_FREE_DBUS_ERROR(&err);
    218             return JNI_FALSE;
    219         }
    220         dbus_bus_add_match(nat->conn,
    221                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'",
    222                 &err);
    223         if (dbus_error_is_set(&err)) {
    224             LOG_AND_FREE_DBUS_ERROR(&err);
    225             return JNI_FALSE;
    226         }
    227         dbus_bus_add_match(nat->conn,
    228                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Device'",
    229                 &err);
    230         if (dbus_error_is_set(&err)) {
    231             LOG_AND_FREE_DBUS_ERROR(&err);
    232             return JNI_FALSE;
    233         }
    234         dbus_bus_add_match(nat->conn,
    235                 "type='signal',interface='org.bluez.AudioSink'",
    236                 &err);
    237         if (dbus_error_is_set(&err)) {
    238             LOG_AND_FREE_DBUS_ERROR(&err);
    239             return JNI_FALSE;
    240         }
    241 
    242         const char *agent_path = "/android/bluetooth/agent";
    243         const char *capabilities = "DisplayYesNo";
    244         if (register_agent(nat, agent_path, capabilities) < 0) {
    245             dbus_connection_unregister_object_path (nat->conn, agent_path);
    246             return JNI_FALSE;
    247         }
    248         return JNI_TRUE;
    249     }
    250     return JNI_FALSE;
    251 }
    252 
    253 
    254 const char * get_adapter_path(DBusConnection *conn) {
    255     DBusMessage *msg = NULL, *reply = NULL;
    256     DBusError err;
    257     const char *device_path = NULL;
    258     int attempt = 0;
    259 
    260     for (attempt = 0; attempt < 1000 && reply == NULL; attempt ++) {
    261         msg = dbus_message_new_method_call("org.bluez", "/",
    262               "org.bluez.Manager", "DefaultAdapter");
    263         if (!msg) {
    264             LOGE("%s: Can't allocate new method call for get_adapter_path!",
    265                   __FUNCTION__);
    266             return NULL;
    267         }
    268         dbus_message_append_args(msg, DBUS_TYPE_INVALID);
    269         dbus_error_init(&err);
    270         reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
    271 
    272         if (!reply) {
    273             if (dbus_error_is_set(&err)) {
    274                 if (dbus_error_has_name(&err,
    275                     "org.freedesktop.DBus.Error.ServiceUnknown")) {
    276                     // bluetoothd is still down, retry
    277                     LOG_AND_FREE_DBUS_ERROR(&err);
    278                     usleep(10000);  // 10 ms
    279                     continue;
    280                 } else {
    281                     // Some other error we weren't expecting
    282                     LOG_AND_FREE_DBUS_ERROR(&err);
    283                 }
    284             }
    285             goto failed;
    286         }
    287     }
    288     if (attempt == 1000) {
    289         LOGE("Time out while trying to get Adapter path, is bluetoothd up ?");
    290         goto failed;
    291     }
    292 
    293     if (!dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH,
    294                                &device_path, DBUS_TYPE_INVALID)
    295                                || !device_path){
    296         if (dbus_error_is_set(&err)) {
    297             LOG_AND_FREE_DBUS_ERROR(&err);
    298         }
    299         goto failed;
    300     }
    301     dbus_message_unref(msg);
    302     return device_path;
    303 
    304 failed:
    305     dbus_message_unref(msg);
    306     return NULL;
    307 }
    308 
    309 static int register_agent(native_data_t *nat,
    310                           const char * agent_path, const char * capabilities)
    311 {
    312     DBusMessage *msg, *reply;
    313     DBusError err;
    314     bool oob = TRUE;
    315 
    316     if (!dbus_connection_register_object_path(nat->conn, agent_path,
    317             &agent_vtable, nat)) {
    318         LOGE("%s: Can't register object path %s for agent!",
    319               __FUNCTION__, agent_path);
    320         return -1;
    321     }
    322 
    323     nat->adapter = get_adapter_path(nat->conn);
    324     if (nat->adapter == NULL) {
    325         return -1;
    326     }
    327     msg = dbus_message_new_method_call("org.bluez", nat->adapter,
    328           "org.bluez.Adapter", "RegisterAgent");
    329     if (!msg) {
    330         LOGE("%s: Can't allocate new method call for agent!",
    331               __FUNCTION__);
    332         return -1;
    333     }
    334     dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
    335                              DBUS_TYPE_STRING, &capabilities,
    336                              DBUS_TYPE_BOOLEAN, &oob,
    337                              DBUS_TYPE_INVALID);
    338 
    339     dbus_error_init(&err);
    340     reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
    341     dbus_message_unref(msg);
    342 
    343     if (!reply) {
    344         LOGE("%s: Can't register agent!", __FUNCTION__);
    345         if (dbus_error_is_set(&err)) {
    346             LOG_AND_FREE_DBUS_ERROR(&err);
    347         }
    348         return -1;
    349     }
    350 
    351     dbus_message_unref(reply);
    352     dbus_connection_flush(nat->conn);
    353 
    354     return 0;
    355 }
    356 
    357 static void tearDownEventLoop(native_data_t *nat) {
    358     LOGV(__FUNCTION__);
    359     if (nat != NULL && nat->conn != NULL) {
    360 
    361         DBusMessage *msg, *reply;
    362         DBusError err;
    363         dbus_error_init(&err);
    364         const char * agent_path = "/android/bluetooth/agent";
    365 
    366         msg = dbus_message_new_method_call("org.bluez",
    367                                            nat->adapter,
    368                                            "org.bluez.Adapter",
    369                                            "UnregisterAgent");
    370         if (msg != NULL) {
    371             dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
    372                                      DBUS_TYPE_INVALID);
    373             reply = dbus_connection_send_with_reply_and_block(nat->conn,
    374                                                               msg, -1, &err);
    375 
    376             if (!reply) {
    377                 if (dbus_error_is_set(&err)) {
    378                     LOG_AND_FREE_DBUS_ERROR(&err);
    379                     dbus_error_free(&err);
    380                 }
    381             } else {
    382                 dbus_message_unref(reply);
    383             }
    384             dbus_message_unref(msg);
    385         } else {
    386              LOGE("%s: Can't create new method call!", __FUNCTION__);
    387         }
    388 
    389         dbus_connection_flush(nat->conn);
    390         dbus_connection_unregister_object_path(nat->conn, agent_path);
    391 
    392         dbus_bus_remove_match(nat->conn,
    393                 "type='signal',interface='org.bluez.AudioSink'",
    394                 &err);
    395         if (dbus_error_is_set(&err)) {
    396             LOG_AND_FREE_DBUS_ERROR(&err);
    397         }
    398         dbus_bus_remove_match(nat->conn,
    399                 "type='signal',interface='org.bluez.Device'",
    400                 &err);
    401         if (dbus_error_is_set(&err)) {
    402             LOG_AND_FREE_DBUS_ERROR(&err);
    403         }
    404         dbus_bus_remove_match(nat->conn,
    405                 "type='signal',interface='org.bluez.audio.Manager'",
    406                 &err);
    407         if (dbus_error_is_set(&err)) {
    408             LOG_AND_FREE_DBUS_ERROR(&err);
    409         }
    410         dbus_bus_remove_match(nat->conn,
    411                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'",
    412                 &err);
    413         if (dbus_error_is_set(&err)) {
    414             LOG_AND_FREE_DBUS_ERROR(&err);
    415         }
    416         dbus_bus_remove_match(nat->conn,
    417                 "type='signal',interface='org.freedesktop.DBus'",
    418                 &err);
    419         if (dbus_error_is_set(&err)) {
    420             LOG_AND_FREE_DBUS_ERROR(&err);
    421         }
    422 
    423         dbus_connection_remove_filter(nat->conn, event_filter, nat);
    424     }
    425 }
    426 
    427 
    428 #define EVENT_LOOP_EXIT 1
    429 #define EVENT_LOOP_ADD  2
    430 #define EVENT_LOOP_REMOVE 3
    431 
    432 dbus_bool_t dbusAddWatch(DBusWatch *watch, void *data) {
    433     native_data_t *nat = (native_data_t *)data;
    434 
    435     if (dbus_watch_get_enabled(watch)) {
    436         // note that we can't just send the watch and inspect it later
    437         // because we may get a removeWatch call before this data is reacted
    438         // to by our eventloop and remove this watch..  reading the add first
    439         // and then inspecting the recently deceased watch would be bad.
    440         char control = EVENT_LOOP_ADD;
    441         write(nat->controlFdW, &control, sizeof(char));
    442 
    443         int fd = dbus_watch_get_fd(watch);
    444         write(nat->controlFdW, &fd, sizeof(int));
    445 
    446         unsigned int flags = dbus_watch_get_flags(watch);
    447         write(nat->controlFdW, &flags, sizeof(unsigned int));
    448 
    449         write(nat->controlFdW, &watch, sizeof(DBusWatch*));
    450     }
    451     return true;
    452 }
    453 
    454 void dbusRemoveWatch(DBusWatch *watch, void *data) {
    455     native_data_t *nat = (native_data_t *)data;
    456 
    457     char control = EVENT_LOOP_REMOVE;
    458     write(nat->controlFdW, &control, sizeof(char));
    459 
    460     int fd = dbus_watch_get_fd(watch);
    461     write(nat->controlFdW, &fd, sizeof(int));
    462 
    463     unsigned int flags = dbus_watch_get_flags(watch);
    464     write(nat->controlFdW, &flags, sizeof(unsigned int));
    465 }
    466 
    467 void dbusToggleWatch(DBusWatch *watch, void *data) {
    468     if (dbus_watch_get_enabled(watch)) {
    469         dbusAddWatch(watch, data);
    470     } else {
    471         dbusRemoveWatch(watch, data);
    472     }
    473 }
    474 
    475 static void handleWatchAdd(native_data_t *nat) {
    476     DBusWatch *watch;
    477     int newFD;
    478     unsigned int flags;
    479 
    480     read(nat->controlFdR, &newFD, sizeof(int));
    481     read(nat->controlFdR, &flags, sizeof(unsigned int));
    482     read(nat->controlFdR, &watch, sizeof(DBusWatch *));
    483     short events = dbus_flags_to_unix_events(flags);
    484 
    485     for (int y = 0; y<nat->pollMemberCount; y++) {
    486         if ((nat->pollData[y].fd == newFD) &&
    487                 (nat->pollData[y].events == events)) {
    488             LOGV("DBusWatch duplicate add");
    489             return;
    490         }
    491     }
    492     if (nat->pollMemberCount == nat->pollDataSize) {
    493         LOGV("Bluetooth EventLoop poll struct growing");
    494         struct pollfd *temp = (struct pollfd *)malloc(
    495                 sizeof(struct pollfd) * (nat->pollMemberCount+1));
    496         if (!temp) {
    497             return;
    498         }
    499         memcpy(temp, nat->pollData, sizeof(struct pollfd) *
    500                 nat->pollMemberCount);
    501         free(nat->pollData);
    502         nat->pollData = temp;
    503         DBusWatch **temp2 = (DBusWatch **)malloc(sizeof(DBusWatch *) *
    504                 (nat->pollMemberCount+1));
    505         if (!temp2) {
    506             return;
    507         }
    508         memcpy(temp2, nat->watchData, sizeof(DBusWatch *) *
    509                 nat->pollMemberCount);
    510         free(nat->watchData);
    511         nat->watchData = temp2;
    512         nat->pollDataSize++;
    513     }
    514     nat->pollData[nat->pollMemberCount].fd = newFD;
    515     nat->pollData[nat->pollMemberCount].revents = 0;
    516     nat->pollData[nat->pollMemberCount].events = events;
    517     nat->watchData[nat->pollMemberCount] = watch;
    518     nat->pollMemberCount++;
    519 }
    520 
    521 static void handleWatchRemove(native_data_t *nat) {
    522     int removeFD;
    523     unsigned int flags;
    524 
    525     read(nat->controlFdR, &removeFD, sizeof(int));
    526     read(nat->controlFdR, &flags, sizeof(unsigned int));
    527     short events = dbus_flags_to_unix_events(flags);
    528 
    529     for (int y = 0; y < nat->pollMemberCount; y++) {
    530         if ((nat->pollData[y].fd == removeFD) &&
    531                 (nat->pollData[y].events == events)) {
    532             int newCount = --nat->pollMemberCount;
    533             // copy the last live member over this one
    534             nat->pollData[y].fd = nat->pollData[newCount].fd;
    535             nat->pollData[y].events = nat->pollData[newCount].events;
    536             nat->pollData[y].revents = nat->pollData[newCount].revents;
    537             nat->watchData[y] = nat->watchData[newCount];
    538             return;
    539         }
    540     }
    541     LOGW("WatchRemove given with unknown watch");
    542 }
    543 
    544 static void *eventLoopMain(void *ptr) {
    545     native_data_t *nat = (native_data_t *)ptr;
    546     JNIEnv *env;
    547 
    548     JavaVMAttachArgs args;
    549     char name[] = "BT EventLoop";
    550     args.version = nat->envVer;
    551     args.name = name;
    552     args.group = NULL;
    553 
    554     nat->vm->AttachCurrentThread(&env, &args);
    555 
    556     dbus_connection_set_watch_functions(nat->conn, dbusAddWatch,
    557             dbusRemoveWatch, dbusToggleWatch, ptr, NULL);
    558 
    559     nat->running = true;
    560 
    561     while (1) {
    562         for (int i = 0; i < nat->pollMemberCount; i++) {
    563             if (!nat->pollData[i].revents) {
    564                 continue;
    565             }
    566             if (nat->pollData[i].fd == nat->controlFdR) {
    567                 char data;
    568                 while (recv(nat->controlFdR, &data, sizeof(char), MSG_DONTWAIT)
    569                         != -1) {
    570                     switch (data) {
    571                     case EVENT_LOOP_EXIT:
    572                     {
    573                         dbus_connection_set_watch_functions(nat->conn,
    574                                 NULL, NULL, NULL, NULL, NULL);
    575                         tearDownEventLoop(nat);
    576                         nat->vm->DetachCurrentThread();
    577 
    578                         int fd = nat->controlFdR;
    579                         nat->controlFdR = 0;
    580                         close(fd);
    581                         return NULL;
    582                     }
    583                     case EVENT_LOOP_ADD:
    584                     {
    585                         handleWatchAdd(nat);
    586                         break;
    587                     }
    588                     case EVENT_LOOP_REMOVE:
    589                     {
    590                         handleWatchRemove(nat);
    591                         break;
    592                     }
    593                     }
    594                 }
    595             } else {
    596                 short events = nat->pollData[i].revents;
    597                 unsigned int flags = unix_events_to_dbus_flags(events);
    598                 dbus_watch_handle(nat->watchData[i], flags);
    599                 nat->pollData[i].revents = 0;
    600                 // can only do one - it may have caused a 'remove'
    601                 break;
    602             }
    603         }
    604         while (dbus_connection_dispatch(nat->conn) ==
    605                 DBUS_DISPATCH_DATA_REMAINS) {
    606         }
    607 
    608         poll(nat->pollData, nat->pollMemberCount, -1);
    609     }
    610 }
    611 #endif // HAVE_BLUETOOTH
    612 
    613 static jboolean startEventLoopNative(JNIEnv *env, jobject object) {
    614     jboolean result = JNI_FALSE;
    615 #ifdef HAVE_BLUETOOTH
    616     event_loop_native_data_t *nat = get_native_data(env, object);
    617 
    618     pthread_mutex_lock(&(nat->thread_mutex));
    619 
    620     nat->running = false;
    621 
    622     if (nat->pollData) {
    623         LOGW("trying to start EventLoop a second time!");
    624         pthread_mutex_unlock( &(nat->thread_mutex) );
    625         return JNI_FALSE;
    626     }
    627 
    628     nat->pollData = (struct pollfd *)malloc(sizeof(struct pollfd) *
    629             DEFAULT_INITIAL_POLLFD_COUNT);
    630     if (!nat->pollData) {
    631         LOGE("out of memory error starting EventLoop!");
    632         goto done;
    633     }
    634 
    635     nat->watchData = (DBusWatch **)malloc(sizeof(DBusWatch *) *
    636             DEFAULT_INITIAL_POLLFD_COUNT);
    637     if (!nat->watchData) {
    638         LOGE("out of memory error starting EventLoop!");
    639         goto done;
    640     }
    641 
    642     memset(nat->pollData, 0, sizeof(struct pollfd) *
    643             DEFAULT_INITIAL_POLLFD_COUNT);
    644     memset(nat->watchData, 0, sizeof(DBusWatch *) *
    645             DEFAULT_INITIAL_POLLFD_COUNT);
    646     nat->pollDataSize = DEFAULT_INITIAL_POLLFD_COUNT;
    647     nat->pollMemberCount = 1;
    648 
    649     if (socketpair(AF_LOCAL, SOCK_STREAM, 0, &(nat->controlFdR))) {
    650         LOGE("Error getting BT control socket");
    651         goto done;
    652     }
    653     nat->pollData[0].fd = nat->controlFdR;
    654     nat->pollData[0].events = POLLIN;
    655 
    656     env->GetJavaVM( &(nat->vm) );
    657     nat->envVer = env->GetVersion();
    658 
    659     nat->me = env->NewGlobalRef(object);
    660 
    661     if (setUpEventLoop(nat) != JNI_TRUE) {
    662         LOGE("failure setting up Event Loop!");
    663         goto done;
    664     }
    665 
    666     pthread_create(&(nat->thread), NULL, eventLoopMain, nat);
    667     result = JNI_TRUE;
    668 
    669 done:
    670     if (JNI_FALSE == result) {
    671         if (nat->controlFdW) {
    672             close(nat->controlFdW);
    673             nat->controlFdW = 0;
    674         }
    675         if (nat->controlFdR) {
    676             close(nat->controlFdR);
    677             nat->controlFdR = 0;
    678         }
    679         if (nat->me) env->DeleteGlobalRef(nat->me);
    680         nat->me = NULL;
    681         if (nat->pollData) free(nat->pollData);
    682         nat->pollData = NULL;
    683         if (nat->watchData) free(nat->watchData);
    684         nat->watchData = NULL;
    685         nat->pollDataSize = 0;
    686         nat->pollMemberCount = 0;
    687     }
    688 
    689     pthread_mutex_unlock(&(nat->thread_mutex));
    690 #endif // HAVE_BLUETOOTH
    691     return result;
    692 }
    693 
    694 static void stopEventLoopNative(JNIEnv *env, jobject object) {
    695 #ifdef HAVE_BLUETOOTH
    696     native_data_t *nat = get_native_data(env, object);
    697 
    698     pthread_mutex_lock(&(nat->thread_mutex));
    699     if (nat->pollData) {
    700         char data = EVENT_LOOP_EXIT;
    701         ssize_t t = write(nat->controlFdW, &data, sizeof(char));
    702         void *ret;
    703         pthread_join(nat->thread, &ret);
    704 
    705         env->DeleteGlobalRef(nat->me);
    706         nat->me = NULL;
    707         free(nat->pollData);
    708         nat->pollData = NULL;
    709         free(nat->watchData);
    710         nat->watchData = NULL;
    711         nat->pollDataSize = 0;
    712         nat->pollMemberCount = 0;
    713 
    714         int fd = nat->controlFdW;
    715         nat->controlFdW = 0;
    716         close(fd);
    717     }
    718     nat->running = false;
    719     pthread_mutex_unlock(&(nat->thread_mutex));
    720 #endif // HAVE_BLUETOOTH
    721 }
    722 
    723 static jboolean isEventLoopRunningNative(JNIEnv *env, jobject object) {
    724     jboolean result = JNI_FALSE;
    725 #ifdef HAVE_BLUETOOTH
    726     native_data_t *nat = get_native_data(env, object);
    727 
    728     pthread_mutex_lock(&(nat->thread_mutex));
    729     if (nat->running) {
    730         result = JNI_TRUE;
    731     }
    732     pthread_mutex_unlock(&(nat->thread_mutex));
    733 
    734 #endif // HAVE_BLUETOOTH
    735     return result;
    736 }
    737 
    738 #ifdef HAVE_BLUETOOTH
    739 extern DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env);
    740 
    741 // Called by dbus during WaitForAndDispatchEventNative()
    742 static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
    743                                       void *data) {
    744     native_data_t *nat;
    745     JNIEnv *env;
    746     DBusError err;
    747     DBusHandlerResult ret;
    748 
    749     dbus_error_init(&err);
    750 
    751     nat = (native_data_t *)data;
    752     nat->vm->GetEnv((void**)&env, nat->envVer);
    753     if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) {
    754         LOGV("%s: not interested (not a signal).", __FUNCTION__);
    755         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    756     }
    757 
    758     LOGE("%s: Received signal %s:%s from %s", __FUNCTION__,
    759         dbus_message_get_interface(msg), dbus_message_get_member(msg),
    760         dbus_message_get_path(msg));
    761 
    762     env->PushLocalFrame(EVENT_LOOP_REFS);
    763     if (dbus_message_is_signal(msg,
    764                                "org.bluez.Adapter",
    765                                "DeviceFound")) {
    766         char *c_address;
    767         DBusMessageIter iter;
    768         jobjectArray str_array = NULL;
    769         if (dbus_message_iter_init(msg, &iter)) {
    770             dbus_message_iter_get_basic(&iter, &c_address);
    771             if (dbus_message_iter_next(&iter))
    772                 str_array =
    773                     parse_remote_device_properties(env, &iter);
    774         }
    775         if (str_array != NULL) {
    776             env->CallVoidMethod(nat->me,
    777                                 method_onDeviceFound,
    778                                 env->NewStringUTF(c_address),
    779                                 str_array);
    780         } else
    781             LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    782         goto success;
    783     } else if (dbus_message_is_signal(msg,
    784                                      "org.bluez.Adapter",
    785                                      "DeviceDisappeared")) {
    786         char *c_address;
    787         if (dbus_message_get_args(msg, &err,
    788                                   DBUS_TYPE_STRING, &c_address,
    789                                   DBUS_TYPE_INVALID)) {
    790             LOGV("... address = %s", c_address);
    791             env->CallVoidMethod(nat->me, method_onDeviceDisappeared,
    792                                 env->NewStringUTF(c_address));
    793         } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    794         goto success;
    795     } else if (dbus_message_is_signal(msg,
    796                                      "org.bluez.Adapter",
    797                                      "DeviceCreated")) {
    798         char *c_object_path;
    799         if (dbus_message_get_args(msg, &err,
    800                                   DBUS_TYPE_OBJECT_PATH, &c_object_path,
    801                                   DBUS_TYPE_INVALID)) {
    802             LOGV("... address = %s", c_object_path);
    803             env->CallVoidMethod(nat->me,
    804                                 method_onDeviceCreated,
    805                                 env->NewStringUTF(c_object_path));
    806         } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    807         goto success;
    808     } else if (dbus_message_is_signal(msg,
    809                                      "org.bluez.Adapter",
    810                                      "DeviceRemoved")) {
    811         char *c_object_path;
    812         if (dbus_message_get_args(msg, &err,
    813                                  DBUS_TYPE_OBJECT_PATH, &c_object_path,
    814                                  DBUS_TYPE_INVALID)) {
    815            LOGV("... Object Path = %s", c_object_path);
    816            env->CallVoidMethod(nat->me,
    817                                method_onDeviceRemoved,
    818                                env->NewStringUTF(c_object_path));
    819         } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    820         goto success;
    821     } else if (dbus_message_is_signal(msg,
    822                                       "org.bluez.Adapter",
    823                                       "PropertyChanged")) {
    824         jobjectArray str_array = parse_adapter_property_change(env, msg);
    825         if (str_array != NULL) {
    826             /* Check if bluetoothd has (re)started, if so update the path. */
    827             jstring property =(jstring) env->GetObjectArrayElement(str_array, 0);
    828             const char *c_property = env->GetStringUTFChars(property, NULL);
    829             if (!strncmp(c_property, "Powered", strlen("Powered"))) {
    830                 jstring value =
    831                     (jstring) env->GetObjectArrayElement(str_array, 1);
    832                 const char *c_value = env->GetStringUTFChars(value, NULL);
    833                 if (!strncmp(c_value, "true", strlen("true")))
    834                     nat->adapter = get_adapter_path(nat->conn);
    835                 env->ReleaseStringUTFChars(value, c_value);
    836             }
    837             env->ReleaseStringUTFChars(property, c_property);
    838 
    839             env->CallVoidMethod(nat->me,
    840                               method_onPropertyChanged,
    841                               str_array);
    842         } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    843         goto success;
    844     } else if (dbus_message_is_signal(msg,
    845                                       "org.bluez.Device",
    846                                       "PropertyChanged")) {
    847         jobjectArray str_array = parse_remote_device_property_change(env, msg);
    848         if (str_array != NULL) {
    849             const char *remote_device_path = dbus_message_get_path(msg);
    850             env->CallVoidMethod(nat->me,
    851                             method_onDevicePropertyChanged,
    852                             env->NewStringUTF(remote_device_path),
    853                             str_array);
    854         } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    855         goto success;
    856     } else if (dbus_message_is_signal(msg,
    857                                       "org.bluez.Device",
    858                                       "DisconnectRequested")) {
    859         const char *remote_device_path = dbus_message_get_path(msg);
    860         env->CallVoidMethod(nat->me,
    861                             method_onDeviceDisconnectRequested,
    862                             env->NewStringUTF(remote_device_path));
    863         goto success;
    864     }
    865 
    866     ret = a2dp_event_filter(msg, env);
    867     env->PopLocalFrame(NULL);
    868     return ret;
    869 
    870 success:
    871     env->PopLocalFrame(NULL);
    872     return DBUS_HANDLER_RESULT_HANDLED;
    873 }
    874 
    875 // Called by dbus during WaitForAndDispatchEventNative()
    876 DBusHandlerResult agent_event_filter(DBusConnection *conn,
    877                                      DBusMessage *msg, void *data) {
    878     native_data_t *nat = (native_data_t *)data;
    879     JNIEnv *env;
    880     if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) {
    881         LOGV("%s: not interested (not a method call).", __FUNCTION__);
    882         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    883     }
    884     LOGI("%s: Received method %s:%s", __FUNCTION__,
    885          dbus_message_get_interface(msg), dbus_message_get_member(msg));
    886 
    887     if (nat == NULL) return DBUS_HANDLER_RESULT_HANDLED;
    888 
    889     nat->vm->GetEnv((void**)&env, nat->envVer);
    890     env->PushLocalFrame(EVENT_LOOP_REFS);
    891 
    892     if (dbus_message_is_method_call(msg,
    893             "org.bluez.Agent", "Cancel")) {
    894         env->CallVoidMethod(nat->me, method_onAgentCancel);
    895         // reply
    896         DBusMessage *reply = dbus_message_new_method_return(msg);
    897         if (!reply) {
    898             LOGE("%s: Cannot create message reply\n", __FUNCTION__);
    899             goto failure;
    900         }
    901         dbus_connection_send(nat->conn, reply, NULL);
    902         dbus_message_unref(reply);
    903         goto success;
    904 
    905     } else if (dbus_message_is_method_call(msg,
    906             "org.bluez.Agent", "Authorize")) {
    907         char *object_path;
    908         const char *uuid;
    909         if (!dbus_message_get_args(msg, NULL,
    910                                    DBUS_TYPE_OBJECT_PATH, &object_path,
    911                                    DBUS_TYPE_STRING, &uuid,
    912                                    DBUS_TYPE_INVALID)) {
    913             LOGE("%s: Invalid arguments for Authorize() method", __FUNCTION__);
    914             goto failure;
    915         }
    916 
    917         LOGV("... object_path = %s", object_path);
    918         LOGV("... uuid = %s", uuid);
    919 
    920         dbus_message_ref(msg);  // increment refcount because we pass to java
    921         env->CallBooleanMethod(nat->me, method_onAgentAuthorize,
    922                 env->NewStringUTF(object_path), env->NewStringUTF(uuid),
    923                 int(msg));
    924 
    925         goto success;
    926     } else if (dbus_message_is_method_call(msg,
    927             "org.bluez.Agent", "OutOfBandAvailable")) {
    928         char *object_path;
    929         if (!dbus_message_get_args(msg, NULL,
    930                                    DBUS_TYPE_OBJECT_PATH, &object_path,
    931                                    DBUS_TYPE_INVALID)) {
    932             LOGE("%s: Invalid arguments for OutOfBandData available() method", __FUNCTION__);
    933             goto failure;
    934         }
    935 
    936         LOGV("... object_path = %s", object_path);
    937 
    938         bool available =
    939             env->CallBooleanMethod(nat->me, method_onAgentOutOfBandDataAvailable,
    940                 env->NewStringUTF(object_path));
    941 
    942 
    943         // reply
    944         if (available) {
    945             DBusMessage *reply = dbus_message_new_method_return(msg);
    946             if (!reply) {
    947                 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
    948                 goto failure;
    949             }
    950             dbus_connection_send(nat->conn, reply, NULL);
    951             dbus_message_unref(reply);
    952         } else {
    953             DBusMessage *reply = dbus_message_new_error(msg,
    954                     "org.bluez.Error.DoesNotExist", "OutofBand data not available");
    955             if (!reply) {
    956                 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
    957                 goto failure;
    958             }
    959             dbus_connection_send(nat->conn, reply, NULL);
    960             dbus_message_unref(reply);
    961         }
    962         goto success;
    963     } else if (dbus_message_is_method_call(msg,
    964             "org.bluez.Agent", "RequestPinCode")) {
    965         char *object_path;
    966         if (!dbus_message_get_args(msg, NULL,
    967                                    DBUS_TYPE_OBJECT_PATH, &object_path,
    968                                    DBUS_TYPE_INVALID)) {
    969             LOGE("%s: Invalid arguments for RequestPinCode() method", __FUNCTION__);
    970             goto failure;
    971         }
    972 
    973         dbus_message_ref(msg);  // increment refcount because we pass to java
    974         env->CallVoidMethod(nat->me, method_onRequestPinCode,
    975                                        env->NewStringUTF(object_path),
    976                                        int(msg));
    977         goto success;
    978     } else if (dbus_message_is_method_call(msg,
    979             "org.bluez.Agent", "RequestPasskey")) {
    980         char *object_path;
    981         if (!dbus_message_get_args(msg, NULL,
    982                                    DBUS_TYPE_OBJECT_PATH, &object_path,
    983                                    DBUS_TYPE_INVALID)) {
    984             LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
    985             goto failure;
    986         }
    987 
    988         dbus_message_ref(msg);  // increment refcount because we pass to java
    989         env->CallVoidMethod(nat->me, method_onRequestPasskey,
    990                                        env->NewStringUTF(object_path),
    991                                        int(msg));
    992         goto success;
    993     } else if (dbus_message_is_method_call(msg,
    994             "org.bluez.Agent", "RequestOobData")) {
    995         char *object_path;
    996         if (!dbus_message_get_args(msg, NULL,
    997                                    DBUS_TYPE_OBJECT_PATH, &object_path,
    998                                    DBUS_TYPE_INVALID)) {
    999             LOGE("%s: Invalid arguments for RequestOobData() method", __FUNCTION__);
   1000             goto failure;
   1001         }
   1002 
   1003         dbus_message_ref(msg);  // increment refcount because we pass to java
   1004         env->CallVoidMethod(nat->me, method_onRequestOobData,
   1005                                        env->NewStringUTF(object_path),
   1006                                        int(msg));
   1007         goto success;
   1008     } else if (dbus_message_is_method_call(msg,
   1009             "org.bluez.Agent", "DisplayPasskey")) {
   1010         char *object_path;
   1011         uint32_t passkey;
   1012         if (!dbus_message_get_args(msg, NULL,
   1013                                    DBUS_TYPE_OBJECT_PATH, &object_path,
   1014                                    DBUS_TYPE_UINT32, &passkey,
   1015                                    DBUS_TYPE_INVALID)) {
   1016             LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
   1017             goto failure;
   1018         }
   1019 
   1020         dbus_message_ref(msg);  // increment refcount because we pass to java
   1021         env->CallVoidMethod(nat->me, method_onDisplayPasskey,
   1022                                        env->NewStringUTF(object_path),
   1023                                        passkey,
   1024                                        int(msg));
   1025         goto success;
   1026     } else if (dbus_message_is_method_call(msg,
   1027             "org.bluez.Agent", "RequestConfirmation")) {
   1028         char *object_path;
   1029         uint32_t passkey;
   1030         if (!dbus_message_get_args(msg, NULL,
   1031                                    DBUS_TYPE_OBJECT_PATH, &object_path,
   1032                                    DBUS_TYPE_UINT32, &passkey,
   1033                                    DBUS_TYPE_INVALID)) {
   1034             LOGE("%s: Invalid arguments for RequestConfirmation() method", __FUNCTION__);
   1035             goto failure;
   1036         }
   1037 
   1038         dbus_message_ref(msg);  // increment refcount because we pass to java
   1039         env->CallVoidMethod(nat->me, method_onRequestPasskeyConfirmation,
   1040                                        env->NewStringUTF(object_path),
   1041                                        passkey,
   1042                                        int(msg));
   1043         goto success;
   1044     } else if (dbus_message_is_method_call(msg,
   1045             "org.bluez.Agent", "RequestPairingConsent")) {
   1046         char *object_path;
   1047         if (!dbus_message_get_args(msg, NULL,
   1048                                    DBUS_TYPE_OBJECT_PATH, &object_path,
   1049                                    DBUS_TYPE_INVALID)) {
   1050             LOGE("%s: Invalid arguments for RequestPairingConsent() method", __FUNCTION__);
   1051             goto failure;
   1052         }
   1053 
   1054         dbus_message_ref(msg);  // increment refcount because we pass to java
   1055         env->CallVoidMethod(nat->me, method_onRequestPairingConsent,
   1056                                        env->NewStringUTF(object_path),
   1057                                        int(msg));
   1058         goto success;
   1059     } else if (dbus_message_is_method_call(msg,
   1060                   "org.bluez.Agent", "Release")) {
   1061         // reply
   1062         DBusMessage *reply = dbus_message_new_method_return(msg);
   1063         if (!reply) {
   1064             LOGE("%s: Cannot create message reply\n", __FUNCTION__);
   1065             goto failure;
   1066         }
   1067         dbus_connection_send(nat->conn, reply, NULL);
   1068         dbus_message_unref(reply);
   1069         goto success;
   1070     } else {
   1071         LOGV("%s:%s is ignored", dbus_message_get_interface(msg), dbus_message_get_member(msg));
   1072     }
   1073 
   1074 failure:
   1075     env->PopLocalFrame(NULL);
   1076     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   1077 
   1078 success:
   1079     env->PopLocalFrame(NULL);
   1080     return DBUS_HANDLER_RESULT_HANDLED;
   1081 
   1082 }
   1083 #endif
   1084 
   1085 
   1086 #ifdef HAVE_BLUETOOTH
   1087 //TODO: Unify result codes in a header
   1088 #define BOND_RESULT_ERROR -1000
   1089 #define BOND_RESULT_SUCCESS 0
   1090 #define BOND_RESULT_AUTH_FAILED 1
   1091 #define BOND_RESULT_AUTH_REJECTED 2
   1092 #define BOND_RESULT_AUTH_CANCELED 3
   1093 #define BOND_RESULT_REMOTE_DEVICE_DOWN 4
   1094 #define BOND_RESULT_DISCOVERY_IN_PROGRESS 5
   1095 #define BOND_RESULT_AUTH_TIMEOUT 6
   1096 #define BOND_RESULT_REPEATED_ATTEMPTS 7
   1097 
   1098 void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) {
   1099     LOGV(__FUNCTION__);
   1100 
   1101     native_data_t *nat = (native_data_t *)n;
   1102     const char *address = (const char *)user;
   1103     DBusError err;
   1104     dbus_error_init(&err);
   1105     JNIEnv *env;
   1106     jstring addr;
   1107 
   1108     nat->vm->GetEnv((void**)&env, nat->envVer);
   1109 
   1110     LOGV("... address = %s", address);
   1111 
   1112     jint result = BOND_RESULT_SUCCESS;
   1113     if (dbus_set_error_from_message(&err, msg)) {
   1114         if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) {
   1115             // Pins did not match, or remote device did not respond to pin
   1116             // request in time
   1117             LOGV("... error = %s (%s)\n", err.name, err.message);
   1118             result = BOND_RESULT_AUTH_FAILED;
   1119         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationRejected")) {
   1120             // We rejected pairing, or the remote side rejected pairing. This
   1121             // happens if either side presses 'cancel' at the pairing dialog.
   1122             LOGV("... error = %s (%s)\n", err.name, err.message);
   1123             result = BOND_RESULT_AUTH_REJECTED;
   1124         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationCanceled")) {
   1125             // Not sure if this happens
   1126             LOGV("... error = %s (%s)\n", err.name, err.message);
   1127             result = BOND_RESULT_AUTH_CANCELED;
   1128         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.ConnectionAttemptFailed")) {
   1129             // Other device is not responding at all
   1130             LOGV("... error = %s (%s)\n", err.name, err.message);
   1131             result = BOND_RESULT_REMOTE_DEVICE_DOWN;
   1132         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AlreadyExists")) {
   1133             // already bonded
   1134             LOGV("... error = %s (%s)\n", err.name, err.message);
   1135             result = BOND_RESULT_SUCCESS;
   1136         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") &&
   1137                    !strcmp(err.message, "Bonding in progress")) {
   1138             LOGV("... error = %s (%s)\n", err.name, err.message);
   1139             goto done;
   1140         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") &&
   1141                    !strcmp(err.message, "Discover in progress")) {
   1142             LOGV("... error = %s (%s)\n", err.name, err.message);
   1143             result = BOND_RESULT_DISCOVERY_IN_PROGRESS;
   1144         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.RepeatedAttempts")) {
   1145             LOGV("... error = %s (%s)\n", err.name, err.message);
   1146             result = BOND_RESULT_REPEATED_ATTEMPTS;
   1147         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationTimeout")) {
   1148             LOGV("... error = %s (%s)\n", err.name, err.message);
   1149             result = BOND_RESULT_AUTH_TIMEOUT;
   1150         } else {
   1151             LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
   1152             result = BOND_RESULT_ERROR;
   1153         }
   1154     }
   1155 
   1156     addr = env->NewStringUTF(address);
   1157     env->CallVoidMethod(nat->me,
   1158                         method_onCreatePairedDeviceResult,
   1159                         addr,
   1160                         result);
   1161     env->DeleteLocalRef(addr);
   1162 done:
   1163     dbus_error_free(&err);
   1164     free(user);
   1165 }
   1166 
   1167 void onCreateDeviceResult(DBusMessage *msg, void *user, void *n) {
   1168     LOGV(__FUNCTION__);
   1169 
   1170     native_data_t *nat = (native_data_t *)n;
   1171     const char *address= (const char *)user;
   1172     DBusError err;
   1173     dbus_error_init(&err);
   1174     JNIEnv *env;
   1175     nat->vm->GetEnv((void**)&env, nat->envVer);
   1176 
   1177     LOGV("... Address = %s", address);
   1178 
   1179     jint result = CREATE_DEVICE_SUCCESS;
   1180     if (dbus_set_error_from_message(&err, msg)) {
   1181         if (dbus_error_has_name(&err, "org.bluez.Error.AlreadyExists")) {
   1182             result = CREATE_DEVICE_ALREADY_EXISTS;
   1183         } else {
   1184             result = CREATE_DEVICE_FAILED;
   1185         }
   1186         LOG_AND_FREE_DBUS_ERROR(&err);
   1187     }
   1188     jstring addr = env->NewStringUTF(address);
   1189     env->CallVoidMethod(nat->me,
   1190                         method_onCreateDeviceResult,
   1191                         addr,
   1192                         result);
   1193     env->DeleteLocalRef(addr);
   1194     free(user);
   1195 }
   1196 
   1197 void onDiscoverServicesResult(DBusMessage *msg, void *user, void *n) {
   1198     LOGV(__FUNCTION__);
   1199 
   1200     native_data_t *nat = (native_data_t *)n;
   1201     const char *path = (const char *)user;
   1202     DBusError err;
   1203     dbus_error_init(&err);
   1204     JNIEnv *env;
   1205     nat->vm->GetEnv((void**)&env, nat->envVer);
   1206 
   1207     LOGV("... Device Path = %s", path);
   1208 
   1209     bool result = JNI_TRUE;
   1210     if (dbus_set_error_from_message(&err, msg)) {
   1211         LOG_AND_FREE_DBUS_ERROR(&err);
   1212         result = JNI_FALSE;
   1213     }
   1214     jstring jPath = env->NewStringUTF(path);
   1215     env->CallVoidMethod(nat->me,
   1216                         method_onDiscoverServicesResult,
   1217                         jPath,
   1218                         result);
   1219     env->DeleteLocalRef(jPath);
   1220     free(user);
   1221 }
   1222 
   1223 void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) {
   1224     LOGV(__FUNCTION__);
   1225 
   1226     const char *address = (const char *) user;
   1227     native_data_t *nat = (native_data_t *) n;
   1228 
   1229     DBusError err;
   1230     dbus_error_init(&err);
   1231     JNIEnv *env;
   1232     nat->vm->GetEnv((void**)&env, nat->envVer);
   1233 
   1234     jint channel = -2;
   1235 
   1236     LOGV("... address = %s", address);
   1237 
   1238     if (dbus_set_error_from_message(&err, msg) ||
   1239         !dbus_message_get_args(msg, &err,
   1240                                DBUS_TYPE_INT32, &channel,
   1241                                DBUS_TYPE_INVALID)) {
   1242         LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
   1243         dbus_error_free(&err);
   1244     }
   1245 
   1246 done:
   1247     jstring addr = env->NewStringUTF(address);
   1248     env->CallVoidMethod(nat->me,
   1249                         method_onGetDeviceServiceChannelResult,
   1250                         addr,
   1251                         channel);
   1252     env->DeleteLocalRef(addr);
   1253     free(user);
   1254 }
   1255 #endif
   1256 
   1257 static JNINativeMethod sMethods[] = {
   1258      /* name, signature, funcPtr */
   1259     {"classInitNative", "()V", (void *)classInitNative},
   1260     {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
   1261     {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
   1262     {"startEventLoopNative", "()V", (void *)startEventLoopNative},
   1263     {"stopEventLoopNative", "()V", (void *)stopEventLoopNative},
   1264     {"isEventLoopRunningNative", "()Z", (void *)isEventLoopRunningNative}
   1265 };
   1266 
   1267 int register_android_server_BluetoothEventLoop(JNIEnv *env) {
   1268     return AndroidRuntime::registerNativeMethods(env,
   1269             "android/server/BluetoothEventLoop", sMethods, NELEM(sMethods));
   1270 }
   1271 
   1272 } /* namespace android */
   1273