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;)Z");
    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         bool auth_granted =
    921             env->CallBooleanMethod(nat->me, method_onAgentAuthorize,
    922                 env->NewStringUTF(object_path), env->NewStringUTF(uuid));
    923 
    924         // reply
    925         if (auth_granted) {
    926             DBusMessage *reply = dbus_message_new_method_return(msg);
    927             if (!reply) {
    928                 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
    929                 goto failure;
    930             }
    931             dbus_connection_send(nat->conn, reply, NULL);
    932             dbus_message_unref(reply);
    933         } else {
    934             DBusMessage *reply = dbus_message_new_error(msg,
    935                     "org.bluez.Error.Rejected", "Authorization rejected");
    936             if (!reply) {
    937                 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
    938                 goto failure;
    939             }
    940             dbus_connection_send(nat->conn, reply, NULL);
    941             dbus_message_unref(reply);
    942         }
    943         goto success;
    944     } else if (dbus_message_is_method_call(msg,
    945             "org.bluez.Agent", "OutOfBandAvailable")) {
    946         char *object_path;
    947         if (!dbus_message_get_args(msg, NULL,
    948                                    DBUS_TYPE_OBJECT_PATH, &object_path,
    949                                    DBUS_TYPE_INVALID)) {
    950             LOGE("%s: Invalid arguments for OutOfBandData available() method", __FUNCTION__);
    951             goto failure;
    952         }
    953 
    954         LOGV("... object_path = %s", object_path);
    955 
    956         bool available =
    957             env->CallBooleanMethod(nat->me, method_onAgentOutOfBandDataAvailable,
    958                 env->NewStringUTF(object_path));
    959 
    960 
    961         // reply
    962         if (available) {
    963             DBusMessage *reply = dbus_message_new_method_return(msg);
    964             if (!reply) {
    965                 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
    966                 goto failure;
    967             }
    968             dbus_connection_send(nat->conn, reply, NULL);
    969             dbus_message_unref(reply);
    970         } else {
    971             DBusMessage *reply = dbus_message_new_error(msg,
    972                     "org.bluez.Error.DoesNotExist", "OutofBand data not available");
    973             if (!reply) {
    974                 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
    975                 goto failure;
    976             }
    977             dbus_connection_send(nat->conn, reply, NULL);
    978             dbus_message_unref(reply);
    979         }
    980         goto success;
    981     } else if (dbus_message_is_method_call(msg,
    982             "org.bluez.Agent", "RequestPinCode")) {
    983         char *object_path;
    984         if (!dbus_message_get_args(msg, NULL,
    985                                    DBUS_TYPE_OBJECT_PATH, &object_path,
    986                                    DBUS_TYPE_INVALID)) {
    987             LOGE("%s: Invalid arguments for RequestPinCode() method", __FUNCTION__);
    988             goto failure;
    989         }
    990 
    991         dbus_message_ref(msg);  // increment refcount because we pass to java
    992         env->CallVoidMethod(nat->me, method_onRequestPinCode,
    993                                        env->NewStringUTF(object_path),
    994                                        int(msg));
    995         goto success;
    996     } else if (dbus_message_is_method_call(msg,
    997             "org.bluez.Agent", "RequestPasskey")) {
    998         char *object_path;
    999         if (!dbus_message_get_args(msg, NULL,
   1000                                    DBUS_TYPE_OBJECT_PATH, &object_path,
   1001                                    DBUS_TYPE_INVALID)) {
   1002             LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
   1003             goto failure;
   1004         }
   1005 
   1006         dbus_message_ref(msg);  // increment refcount because we pass to java
   1007         env->CallVoidMethod(nat->me, method_onRequestPasskey,
   1008                                        env->NewStringUTF(object_path),
   1009                                        int(msg));
   1010         goto success;
   1011     } else if (dbus_message_is_method_call(msg,
   1012             "org.bluez.Agent", "RequestOobData")) {
   1013         char *object_path;
   1014         if (!dbus_message_get_args(msg, NULL,
   1015                                    DBUS_TYPE_OBJECT_PATH, &object_path,
   1016                                    DBUS_TYPE_INVALID)) {
   1017             LOGE("%s: Invalid arguments for RequestOobData() method", __FUNCTION__);
   1018             goto failure;
   1019         }
   1020 
   1021         dbus_message_ref(msg);  // increment refcount because we pass to java
   1022         env->CallVoidMethod(nat->me, method_onRequestOobData,
   1023                                        env->NewStringUTF(object_path),
   1024                                        int(msg));
   1025         goto success;
   1026     } else if (dbus_message_is_method_call(msg,
   1027             "org.bluez.Agent", "DisplayPasskey")) {
   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 RequestPasskey() 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_onDisplayPasskey,
   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", "RequestConfirmation")) {
   1046         char *object_path;
   1047         uint32_t passkey;
   1048         if (!dbus_message_get_args(msg, NULL,
   1049                                    DBUS_TYPE_OBJECT_PATH, &object_path,
   1050                                    DBUS_TYPE_UINT32, &passkey,
   1051                                    DBUS_TYPE_INVALID)) {
   1052             LOGE("%s: Invalid arguments for RequestConfirmation() method", __FUNCTION__);
   1053             goto failure;
   1054         }
   1055 
   1056         dbus_message_ref(msg);  // increment refcount because we pass to java
   1057         env->CallVoidMethod(nat->me, method_onRequestPasskeyConfirmation,
   1058                                        env->NewStringUTF(object_path),
   1059                                        passkey,
   1060                                        int(msg));
   1061         goto success;
   1062     } else if (dbus_message_is_method_call(msg,
   1063             "org.bluez.Agent", "RequestPairingConsent")) {
   1064         char *object_path;
   1065         if (!dbus_message_get_args(msg, NULL,
   1066                                    DBUS_TYPE_OBJECT_PATH, &object_path,
   1067                                    DBUS_TYPE_INVALID)) {
   1068             LOGE("%s: Invalid arguments for RequestPairingConsent() method", __FUNCTION__);
   1069             goto failure;
   1070         }
   1071 
   1072         dbus_message_ref(msg);  // increment refcount because we pass to java
   1073         env->CallVoidMethod(nat->me, method_onRequestPairingConsent,
   1074                                        env->NewStringUTF(object_path),
   1075                                        int(msg));
   1076         goto success;
   1077     } else if (dbus_message_is_method_call(msg,
   1078                   "org.bluez.Agent", "Release")) {
   1079         // reply
   1080         DBusMessage *reply = dbus_message_new_method_return(msg);
   1081         if (!reply) {
   1082             LOGE("%s: Cannot create message reply\n", __FUNCTION__);
   1083             goto failure;
   1084         }
   1085         dbus_connection_send(nat->conn, reply, NULL);
   1086         dbus_message_unref(reply);
   1087         goto success;
   1088     } else {
   1089         LOGV("%s:%s is ignored", dbus_message_get_interface(msg), dbus_message_get_member(msg));
   1090     }
   1091 
   1092 failure:
   1093     env->PopLocalFrame(NULL);
   1094     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   1095 
   1096 success:
   1097     env->PopLocalFrame(NULL);
   1098     return DBUS_HANDLER_RESULT_HANDLED;
   1099 
   1100 }
   1101 #endif
   1102 
   1103 
   1104 #ifdef HAVE_BLUETOOTH
   1105 //TODO: Unify result codes in a header
   1106 #define BOND_RESULT_ERROR -1000
   1107 #define BOND_RESULT_SUCCESS 0
   1108 #define BOND_RESULT_AUTH_FAILED 1
   1109 #define BOND_RESULT_AUTH_REJECTED 2
   1110 #define BOND_RESULT_AUTH_CANCELED 3
   1111 #define BOND_RESULT_REMOTE_DEVICE_DOWN 4
   1112 #define BOND_RESULT_DISCOVERY_IN_PROGRESS 5
   1113 #define BOND_RESULT_AUTH_TIMEOUT 6
   1114 #define BOND_RESULT_REPEATED_ATTEMPTS 7
   1115 
   1116 void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) {
   1117     LOGV(__FUNCTION__);
   1118 
   1119     native_data_t *nat = (native_data_t *)n;
   1120     const char *address = (const char *)user;
   1121     DBusError err;
   1122     dbus_error_init(&err);
   1123     JNIEnv *env;
   1124     jstring addr;
   1125 
   1126     nat->vm->GetEnv((void**)&env, nat->envVer);
   1127 
   1128     LOGV("... address = %s", address);
   1129 
   1130     jint result = BOND_RESULT_SUCCESS;
   1131     if (dbus_set_error_from_message(&err, msg)) {
   1132         if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) {
   1133             // Pins did not match, or remote device did not respond to pin
   1134             // request in time
   1135             LOGV("... error = %s (%s)\n", err.name, err.message);
   1136             result = BOND_RESULT_AUTH_FAILED;
   1137         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationRejected")) {
   1138             // We rejected pairing, or the remote side rejected pairing. This
   1139             // happens if either side presses 'cancel' at the pairing dialog.
   1140             LOGV("... error = %s (%s)\n", err.name, err.message);
   1141             result = BOND_RESULT_AUTH_REJECTED;
   1142         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationCanceled")) {
   1143             // Not sure if this happens
   1144             LOGV("... error = %s (%s)\n", err.name, err.message);
   1145             result = BOND_RESULT_AUTH_CANCELED;
   1146         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.ConnectionAttemptFailed")) {
   1147             // Other device is not responding at all
   1148             LOGV("... error = %s (%s)\n", err.name, err.message);
   1149             result = BOND_RESULT_REMOTE_DEVICE_DOWN;
   1150         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AlreadyExists")) {
   1151             // already bonded
   1152             LOGV("... error = %s (%s)\n", err.name, err.message);
   1153             result = BOND_RESULT_SUCCESS;
   1154         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") &&
   1155                    !strcmp(err.message, "Bonding in progress")) {
   1156             LOGV("... error = %s (%s)\n", err.name, err.message);
   1157             goto done;
   1158         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") &&
   1159                    !strcmp(err.message, "Discover in progress")) {
   1160             LOGV("... error = %s (%s)\n", err.name, err.message);
   1161             result = BOND_RESULT_DISCOVERY_IN_PROGRESS;
   1162         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.RepeatedAttempts")) {
   1163             LOGV("... error = %s (%s)\n", err.name, err.message);
   1164             result = BOND_RESULT_REPEATED_ATTEMPTS;
   1165         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationTimeout")) {
   1166             LOGV("... error = %s (%s)\n", err.name, err.message);
   1167             result = BOND_RESULT_AUTH_TIMEOUT;
   1168         } else {
   1169             LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
   1170             result = BOND_RESULT_ERROR;
   1171         }
   1172     }
   1173 
   1174     addr = env->NewStringUTF(address);
   1175     env->CallVoidMethod(nat->me,
   1176                         method_onCreatePairedDeviceResult,
   1177                         addr,
   1178                         result);
   1179     env->DeleteLocalRef(addr);
   1180 done:
   1181     dbus_error_free(&err);
   1182     free(user);
   1183 }
   1184 
   1185 void onCreateDeviceResult(DBusMessage *msg, void *user, void *n) {
   1186     LOGV(__FUNCTION__);
   1187 
   1188     native_data_t *nat = (native_data_t *)n;
   1189     const char *address= (const char *)user;
   1190     DBusError err;
   1191     dbus_error_init(&err);
   1192     JNIEnv *env;
   1193     nat->vm->GetEnv((void**)&env, nat->envVer);
   1194 
   1195     LOGV("... Address = %s", address);
   1196 
   1197     jint result = CREATE_DEVICE_SUCCESS;
   1198     if (dbus_set_error_from_message(&err, msg)) {
   1199         if (dbus_error_has_name(&err, "org.bluez.Error.AlreadyExists")) {
   1200             result = CREATE_DEVICE_ALREADY_EXISTS;
   1201         } else {
   1202             result = CREATE_DEVICE_FAILED;
   1203         }
   1204         LOG_AND_FREE_DBUS_ERROR(&err);
   1205     }
   1206     jstring addr = env->NewStringUTF(address);
   1207     env->CallVoidMethod(nat->me,
   1208                         method_onCreateDeviceResult,
   1209                         addr,
   1210                         result);
   1211     env->DeleteLocalRef(addr);
   1212     free(user);
   1213 }
   1214 
   1215 void onDiscoverServicesResult(DBusMessage *msg, void *user, void *n) {
   1216     LOGV(__FUNCTION__);
   1217 
   1218     native_data_t *nat = (native_data_t *)n;
   1219     const char *path = (const char *)user;
   1220     DBusError err;
   1221     dbus_error_init(&err);
   1222     JNIEnv *env;
   1223     nat->vm->GetEnv((void**)&env, nat->envVer);
   1224 
   1225     LOGV("... Device Path = %s", path);
   1226 
   1227     bool result = JNI_TRUE;
   1228     if (dbus_set_error_from_message(&err, msg)) {
   1229         LOG_AND_FREE_DBUS_ERROR(&err);
   1230         result = JNI_FALSE;
   1231     }
   1232     jstring jPath = env->NewStringUTF(path);
   1233     env->CallVoidMethod(nat->me,
   1234                         method_onDiscoverServicesResult,
   1235                         jPath,
   1236                         result);
   1237     env->DeleteLocalRef(jPath);
   1238     free(user);
   1239 }
   1240 
   1241 void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) {
   1242     LOGV(__FUNCTION__);
   1243 
   1244     const char *address = (const char *) user;
   1245     native_data_t *nat = (native_data_t *) n;
   1246 
   1247     DBusError err;
   1248     dbus_error_init(&err);
   1249     JNIEnv *env;
   1250     nat->vm->GetEnv((void**)&env, nat->envVer);
   1251 
   1252     jint channel = -2;
   1253 
   1254     LOGV("... address = %s", address);
   1255 
   1256     if (dbus_set_error_from_message(&err, msg) ||
   1257         !dbus_message_get_args(msg, &err,
   1258                                DBUS_TYPE_INT32, &channel,
   1259                                DBUS_TYPE_INVALID)) {
   1260         LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
   1261         dbus_error_free(&err);
   1262     }
   1263 
   1264 done:
   1265     jstring addr = env->NewStringUTF(address);
   1266     env->CallVoidMethod(nat->me,
   1267                         method_onGetDeviceServiceChannelResult,
   1268                         addr,
   1269                         channel);
   1270     env->DeleteLocalRef(addr);
   1271     free(user);
   1272 }
   1273 #endif
   1274 
   1275 static JNINativeMethod sMethods[] = {
   1276      /* name, signature, funcPtr */
   1277     {"classInitNative", "()V", (void *)classInitNative},
   1278     {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
   1279     {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
   1280     {"startEventLoopNative", "()V", (void *)startEventLoopNative},
   1281     {"stopEventLoopNative", "()V", (void *)stopEventLoopNative},
   1282     {"isEventLoopRunningNative", "()Z", (void *)isEventLoopRunningNative}
   1283 };
   1284 
   1285 int register_android_server_BluetoothEventLoop(JNIEnv *env) {
   1286     return AndroidRuntime::registerNativeMethods(env,
   1287             "android/server/BluetoothEventLoop", sMethods, NELEM(sMethods));
   1288 }
   1289 
   1290 } /* namespace android */
   1291