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 static jmethodID method_onNetworkDeviceDisconnected;
     54 static jmethodID method_onNetworkDeviceConnected;
     55 
     56 static jmethodID method_onCreatePairedDeviceResult;
     57 static jmethodID method_onCreateDeviceResult;
     58 static jmethodID method_onDiscoverServicesResult;
     59 static jmethodID method_onGetDeviceServiceChannelResult;
     60 
     61 static jmethodID method_onRequestPinCode;
     62 static jmethodID method_onRequestPasskey;
     63 static jmethodID method_onRequestPasskeyConfirmation;
     64 static jmethodID method_onRequestPairingConsent;
     65 static jmethodID method_onDisplayPasskey;
     66 static jmethodID method_onRequestOobData;
     67 static jmethodID method_onAgentOutOfBandDataAvailable;
     68 static jmethodID method_onAgentAuthorize;
     69 static jmethodID method_onAgentCancel;
     70 
     71 static jmethodID method_onInputDevicePropertyChanged;
     72 static jmethodID method_onInputDeviceConnectionResult;
     73 static jmethodID method_onPanDevicePropertyChanged;
     74 static jmethodID method_onPanDeviceConnectionResult;
     75 static jmethodID method_onHealthDevicePropertyChanged;
     76 static jmethodID method_onHealthDeviceChannelChanged;
     77 static jmethodID method_onHealthDeviceConnectionResult;
     78 
     79 typedef event_loop_native_data_t native_data_t;
     80 
     81 #define EVENT_LOOP_REFS 10
     82 
     83 static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
     84     return (native_data_t *)(env->GetIntField(object,
     85                                                  field_mNativeData));
     86 }
     87 
     88 native_data_t *get_EventLoop_native_data(JNIEnv *env, jobject object) {
     89     return get_native_data(env, object);
     90 }
     91 
     92 #endif
     93 static void classInitNative(JNIEnv* env, jclass clazz) {
     94     LOGV("%s", __FUNCTION__);
     95 
     96 #ifdef HAVE_BLUETOOTH
     97     method_onPropertyChanged = env->GetMethodID(clazz, "onPropertyChanged",
     98                                                 "([Ljava/lang/String;)V");
     99     method_onDevicePropertyChanged = env->GetMethodID(clazz,
    100                                                       "onDevicePropertyChanged",
    101                                                       "(Ljava/lang/String;[Ljava/lang/String;)V");
    102     method_onDeviceFound = env->GetMethodID(clazz, "onDeviceFound",
    103                                             "(Ljava/lang/String;[Ljava/lang/String;)V");
    104     method_onDeviceDisappeared = env->GetMethodID(clazz, "onDeviceDisappeared",
    105                                                   "(Ljava/lang/String;)V");
    106     method_onDeviceCreated = env->GetMethodID(clazz, "onDeviceCreated", "(Ljava/lang/String;)V");
    107     method_onDeviceRemoved = env->GetMethodID(clazz, "onDeviceRemoved", "(Ljava/lang/String;)V");
    108     method_onDeviceDisconnectRequested = env->GetMethodID(clazz, "onDeviceDisconnectRequested",
    109                                                         "(Ljava/lang/String;)V");
    110     method_onNetworkDeviceConnected = env->GetMethodID(clazz, "onNetworkDeviceConnected",
    111                                                      "(Ljava/lang/String;Ljava/lang/String;I)V");
    112     method_onNetworkDeviceDisconnected = env->GetMethodID(clazz, "onNetworkDeviceDisconnected",
    113                                                               "(Ljava/lang/String;)V");
    114 
    115     method_onCreatePairedDeviceResult = env->GetMethodID(clazz, "onCreatePairedDeviceResult",
    116                                                          "(Ljava/lang/String;I)V");
    117     method_onCreateDeviceResult = env->GetMethodID(clazz, "onCreateDeviceResult",
    118                                                          "(Ljava/lang/String;I)V");
    119     method_onDiscoverServicesResult = env->GetMethodID(clazz, "onDiscoverServicesResult",
    120                                                          "(Ljava/lang/String;Z)V");
    121 
    122     method_onAgentAuthorize = env->GetMethodID(clazz, "onAgentAuthorize",
    123                                                "(Ljava/lang/String;Ljava/lang/String;I)V");
    124     method_onAgentOutOfBandDataAvailable = env->GetMethodID(clazz, "onAgentOutOfBandDataAvailable",
    125                                                "(Ljava/lang/String;)Z");
    126     method_onAgentCancel = env->GetMethodID(clazz, "onAgentCancel", "()V");
    127     method_onRequestPinCode = env->GetMethodID(clazz, "onRequestPinCode",
    128                                                "(Ljava/lang/String;I)V");
    129     method_onRequestPasskey = env->GetMethodID(clazz, "onRequestPasskey",
    130                                                "(Ljava/lang/String;I)V");
    131     method_onRequestPasskeyConfirmation = env->GetMethodID(clazz, "onRequestPasskeyConfirmation",
    132                                                "(Ljava/lang/String;II)V");
    133     method_onRequestPairingConsent = env->GetMethodID(clazz, "onRequestPairingConsent",
    134                                                "(Ljava/lang/String;I)V");
    135     method_onDisplayPasskey = env->GetMethodID(clazz, "onDisplayPasskey",
    136                                                "(Ljava/lang/String;II)V");
    137     method_onInputDevicePropertyChanged = env->GetMethodID(clazz, "onInputDevicePropertyChanged",
    138                                                "(Ljava/lang/String;[Ljava/lang/String;)V");
    139     method_onInputDeviceConnectionResult = env->GetMethodID(clazz, "onInputDeviceConnectionResult",
    140                                                "(Ljava/lang/String;I)V");
    141     method_onPanDevicePropertyChanged = env->GetMethodID(clazz, "onPanDevicePropertyChanged",
    142                                                "(Ljava/lang/String;[Ljava/lang/String;)V");
    143     method_onPanDeviceConnectionResult = env->GetMethodID(clazz, "onPanDeviceConnectionResult",
    144                                                "(Ljava/lang/String;I)V");
    145     method_onHealthDeviceConnectionResult = env->GetMethodID(clazz,
    146                                                              "onHealthDeviceConnectionResult",
    147                                                              "(II)V");
    148     method_onHealthDevicePropertyChanged = env->GetMethodID(clazz, "onHealthDevicePropertyChanged",
    149                                                "(Ljava/lang/String;[Ljava/lang/String;)V");
    150     method_onHealthDeviceChannelChanged = env->GetMethodID(clazz, "onHealthDeviceChannelChanged",
    151                                                "(Ljava/lang/String;Ljava/lang/String;Z)V");
    152     method_onRequestOobData = env->GetMethodID(clazz, "onRequestOobData",
    153                                                "(Ljava/lang/String;I)V");
    154 
    155     field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I");
    156 #endif
    157 }
    158 
    159 static void initializeNativeDataNative(JNIEnv* env, jobject object) {
    160     LOGV("%s", __FUNCTION__);
    161 #ifdef HAVE_BLUETOOTH
    162     native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
    163     if (NULL == nat) {
    164         LOGE("%s: out of memory!", __FUNCTION__);
    165         return;
    166     }
    167     memset(nat, 0, sizeof(native_data_t));
    168 
    169     pthread_mutex_init(&(nat->thread_mutex), NULL);
    170 
    171     env->SetIntField(object, field_mNativeData, (jint)nat);
    172 
    173     {
    174         DBusError err;
    175         dbus_error_init(&err);
    176         dbus_threads_init_default();
    177         nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
    178         if (dbus_error_is_set(&err)) {
    179             LOGE("%s: Could not get onto the system bus!", __FUNCTION__);
    180             dbus_error_free(&err);
    181         }
    182         dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
    183     }
    184 #endif
    185 }
    186 
    187 static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
    188     LOGV("%s", __FUNCTION__);
    189 #ifdef HAVE_BLUETOOTH
    190     native_data_t *nat =
    191             (native_data_t *)env->GetIntField(object, field_mNativeData);
    192 
    193     pthread_mutex_destroy(&(nat->thread_mutex));
    194 
    195     if (nat) {
    196         free(nat);
    197     }
    198 #endif
    199 }
    200 
    201 #ifdef HAVE_BLUETOOTH
    202 static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
    203                                       void *data);
    204 DBusHandlerResult agent_event_filter(DBusConnection *conn,
    205                                      DBusMessage *msg,
    206                                      void *data);
    207 static int register_agent(native_data_t *nat,
    208                           const char *agent_path, const char *capabilities);
    209 
    210 static const DBusObjectPathVTable agent_vtable = {
    211     NULL, agent_event_filter, NULL, NULL, NULL, NULL
    212 };
    213 
    214 static unsigned int unix_events_to_dbus_flags(short events) {
    215     return (events & DBUS_WATCH_READABLE ? POLLIN : 0) |
    216            (events & DBUS_WATCH_WRITABLE ? POLLOUT : 0) |
    217            (events & DBUS_WATCH_ERROR ? POLLERR : 0) |
    218            (events & DBUS_WATCH_HANGUP ? POLLHUP : 0);
    219 }
    220 
    221 static short dbus_flags_to_unix_events(unsigned int flags) {
    222     return (flags & POLLIN ? DBUS_WATCH_READABLE : 0) |
    223            (flags & POLLOUT ? DBUS_WATCH_WRITABLE : 0) |
    224            (flags & POLLERR ? DBUS_WATCH_ERROR : 0) |
    225            (flags & POLLHUP ? DBUS_WATCH_HANGUP : 0);
    226 }
    227 
    228 static jboolean setUpEventLoop(native_data_t *nat) {
    229     LOGV("%s", __FUNCTION__);
    230 
    231     if (nat != NULL && nat->conn != NULL) {
    232         dbus_threads_init_default();
    233         DBusError err;
    234         dbus_error_init(&err);
    235 
    236         const char *agent_path = "/android/bluetooth/agent";
    237         const char *capabilities = "DisplayYesNo";
    238         if (register_agent(nat, agent_path, capabilities) < 0) {
    239             dbus_connection_unregister_object_path (nat->conn, agent_path);
    240             return JNI_FALSE;
    241         }
    242 
    243         // Add a filter for all incoming messages
    244         if (!dbus_connection_add_filter(nat->conn, event_filter, nat, NULL)){
    245             return JNI_FALSE;
    246         }
    247 
    248         // Set which messages will be processed by this dbus connection
    249         dbus_bus_add_match(nat->conn,
    250                 "type='signal',interface='org.freedesktop.DBus'",
    251                 &err);
    252         if (dbus_error_is_set(&err)) {
    253             LOG_AND_FREE_DBUS_ERROR(&err);
    254             return JNI_FALSE;
    255         }
    256         dbus_bus_add_match(nat->conn,
    257                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'",
    258                 &err);
    259         if (dbus_error_is_set(&err)) {
    260             LOG_AND_FREE_DBUS_ERROR(&err);
    261             return JNI_FALSE;
    262         }
    263         dbus_bus_add_match(nat->conn,
    264                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Device'",
    265                 &err);
    266         if (dbus_error_is_set(&err)) {
    267             LOG_AND_FREE_DBUS_ERROR(&err);
    268             return JNI_FALSE;
    269         }
    270         dbus_bus_add_match(nat->conn,
    271                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Input'",
    272                 &err);
    273         if (dbus_error_is_set(&err)) {
    274             LOG_AND_FREE_DBUS_ERROR(&err);
    275             return JNI_FALSE;
    276         }
    277         dbus_bus_add_match(nat->conn,
    278                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Network'",
    279                 &err);
    280         if (dbus_error_is_set(&err)) {
    281             LOG_AND_FREE_DBUS_ERROR(&err);
    282             return JNI_FALSE;
    283         }
    284         dbus_bus_add_match(nat->conn,
    285                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".NetworkServer'",
    286                 &err);
    287         if (dbus_error_is_set(&err)) {
    288             LOG_AND_FREE_DBUS_ERROR(&err);
    289             return JNI_FALSE;
    290         }
    291 
    292         dbus_bus_add_match(nat->conn,
    293                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".HealthDevice'",
    294                 &err);
    295         if (dbus_error_is_set(&err)) {
    296             LOG_AND_FREE_DBUS_ERROR(&err);
    297             return JNI_FALSE;
    298         }
    299 
    300         dbus_bus_add_match(nat->conn,
    301                 "type='signal',interface='org.bluez.AudioSink'",
    302                 &err);
    303         if (dbus_error_is_set(&err)) {
    304             LOG_AND_FREE_DBUS_ERROR(&err);
    305             return JNI_FALSE;
    306         }
    307 
    308         return JNI_TRUE;
    309     }
    310     return JNI_FALSE;
    311 }
    312 
    313 
    314 const char * get_adapter_path(DBusConnection *conn) {
    315     DBusMessage *msg = NULL, *reply = NULL;
    316     DBusError err;
    317     const char *device_path = NULL;
    318     int attempt = 0;
    319 
    320     for (attempt = 0; attempt < 1000 && reply == NULL; attempt ++) {
    321         msg = dbus_message_new_method_call("org.bluez", "/",
    322               "org.bluez.Manager", "DefaultAdapter");
    323         if (!msg) {
    324             LOGE("%s: Can't allocate new method call for get_adapter_path!",
    325                   __FUNCTION__);
    326             return NULL;
    327         }
    328         dbus_message_append_args(msg, DBUS_TYPE_INVALID);
    329         dbus_error_init(&err);
    330         reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
    331 
    332         if (!reply) {
    333             if (dbus_error_is_set(&err)) {
    334                 if (dbus_error_has_name(&err,
    335                     "org.freedesktop.DBus.Error.ServiceUnknown")) {
    336                     // bluetoothd is still down, retry
    337                     LOG_AND_FREE_DBUS_ERROR(&err);
    338                     usleep(10000);  // 10 ms
    339                     continue;
    340                 } else {
    341                     // Some other error we weren't expecting
    342                     LOG_AND_FREE_DBUS_ERROR(&err);
    343                 }
    344             }
    345             goto failed;
    346         }
    347     }
    348     if (attempt == 1000) {
    349         LOGE("Time out while trying to get Adapter path, is bluetoothd up ?");
    350         goto failed;
    351     }
    352 
    353     if (!dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH,
    354                                &device_path, DBUS_TYPE_INVALID)
    355                                || !device_path){
    356         if (dbus_error_is_set(&err)) {
    357             LOG_AND_FREE_DBUS_ERROR(&err);
    358         }
    359         goto failed;
    360     }
    361     dbus_message_unref(msg);
    362     return device_path;
    363 
    364 failed:
    365     dbus_message_unref(msg);
    366     return NULL;
    367 }
    368 
    369 static int register_agent(native_data_t *nat,
    370                           const char * agent_path, const char * capabilities)
    371 {
    372     DBusMessage *msg, *reply;
    373     DBusError err;
    374     dbus_bool_t oob = TRUE;
    375 
    376     if (!dbus_connection_register_object_path(nat->conn, agent_path,
    377             &agent_vtable, nat)) {
    378         LOGE("%s: Can't register object path %s for agent!",
    379               __FUNCTION__, agent_path);
    380         return -1;
    381     }
    382 
    383     nat->adapter = get_adapter_path(nat->conn);
    384     if (nat->adapter == NULL) {
    385         return -1;
    386     }
    387     msg = dbus_message_new_method_call("org.bluez", nat->adapter,
    388           "org.bluez.Adapter", "RegisterAgent");
    389     if (!msg) {
    390         LOGE("%s: Can't allocate new method call for agent!",
    391               __FUNCTION__);
    392         return -1;
    393     }
    394     dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
    395                              DBUS_TYPE_STRING, &capabilities,
    396                              DBUS_TYPE_INVALID);
    397 
    398     dbus_error_init(&err);
    399     reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
    400     dbus_message_unref(msg);
    401 
    402     if (!reply) {
    403         LOGE("%s: Can't register agent!", __FUNCTION__);
    404         if (dbus_error_is_set(&err)) {
    405             LOG_AND_FREE_DBUS_ERROR(&err);
    406         }
    407         return -1;
    408     }
    409 
    410     dbus_message_unref(reply);
    411     dbus_connection_flush(nat->conn);
    412 
    413     return 0;
    414 }
    415 
    416 static void tearDownEventLoop(native_data_t *nat) {
    417     LOGV("%s", __FUNCTION__);
    418     if (nat != NULL && nat->conn != NULL) {
    419 
    420         DBusMessage *msg, *reply;
    421         DBusError err;
    422         dbus_error_init(&err);
    423         const char * agent_path = "/android/bluetooth/agent";
    424 
    425         msg = dbus_message_new_method_call("org.bluez",
    426                                            nat->adapter,
    427                                            "org.bluez.Adapter",
    428                                            "UnregisterAgent");
    429         if (msg != NULL) {
    430             dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
    431                                      DBUS_TYPE_INVALID);
    432             reply = dbus_connection_send_with_reply_and_block(nat->conn,
    433                                                               msg, -1, &err);
    434 
    435             if (!reply) {
    436                 if (dbus_error_is_set(&err)) {
    437                     LOG_AND_FREE_DBUS_ERROR(&err);
    438                     dbus_error_free(&err);
    439                 }
    440             } else {
    441                 dbus_message_unref(reply);
    442             }
    443             dbus_message_unref(msg);
    444         } else {
    445              LOGE("%s: Can't create new method call!", __FUNCTION__);
    446         }
    447 
    448         dbus_connection_flush(nat->conn);
    449         dbus_connection_unregister_object_path(nat->conn, agent_path);
    450 
    451         dbus_bus_remove_match(nat->conn,
    452                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".AudioSink'",
    453                 &err);
    454         if (dbus_error_is_set(&err)) {
    455             LOG_AND_FREE_DBUS_ERROR(&err);
    456         }
    457         dbus_bus_remove_match(nat->conn,
    458                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Device'",
    459                 &err);
    460         if (dbus_error_is_set(&err)) {
    461             LOG_AND_FREE_DBUS_ERROR(&err);
    462         }
    463         dbus_bus_remove_match(nat->conn,
    464                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Input'",
    465                 &err);
    466         if (dbus_error_is_set(&err)) {
    467             LOG_AND_FREE_DBUS_ERROR(&err);
    468         }
    469         dbus_bus_remove_match(nat->conn,
    470                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Network'",
    471                 &err);
    472         if (dbus_error_is_set(&err)) {
    473             LOG_AND_FREE_DBUS_ERROR(&err);
    474         }
    475         dbus_bus_remove_match(nat->conn,
    476                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".NetworkServer'",
    477                 &err);
    478         if (dbus_error_is_set(&err)) {
    479             LOG_AND_FREE_DBUS_ERROR(&err);
    480         }
    481         dbus_bus_remove_match(nat->conn,
    482                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".HealthDevice'",
    483                 &err);
    484         if (dbus_error_is_set(&err)) {
    485             LOG_AND_FREE_DBUS_ERROR(&err);
    486         }
    487         dbus_bus_remove_match(nat->conn,
    488                 "type='signal',interface='org.bluez.audio.Manager'",
    489                 &err);
    490         if (dbus_error_is_set(&err)) {
    491             LOG_AND_FREE_DBUS_ERROR(&err);
    492         }
    493         dbus_bus_remove_match(nat->conn,
    494                 "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'",
    495                 &err);
    496         if (dbus_error_is_set(&err)) {
    497             LOG_AND_FREE_DBUS_ERROR(&err);
    498         }
    499         dbus_bus_remove_match(nat->conn,
    500                 "type='signal',interface='org.freedesktop.DBus'",
    501                 &err);
    502         if (dbus_error_is_set(&err)) {
    503             LOG_AND_FREE_DBUS_ERROR(&err);
    504         }
    505 
    506         dbus_connection_remove_filter(nat->conn, event_filter, nat);
    507     }
    508 }
    509 
    510 
    511 #define EVENT_LOOP_EXIT 1
    512 #define EVENT_LOOP_ADD  2
    513 #define EVENT_LOOP_REMOVE 3
    514 #define EVENT_LOOP_WAKEUP 4
    515 
    516 dbus_bool_t dbusAddWatch(DBusWatch *watch, void *data) {
    517     native_data_t *nat = (native_data_t *)data;
    518 
    519     if (dbus_watch_get_enabled(watch)) {
    520         // note that we can't just send the watch and inspect it later
    521         // because we may get a removeWatch call before this data is reacted
    522         // to by our eventloop and remove this watch..  reading the add first
    523         // and then inspecting the recently deceased watch would be bad.
    524         char control = EVENT_LOOP_ADD;
    525         write(nat->controlFdW, &control, sizeof(char));
    526 
    527         int fd = dbus_watch_get_fd(watch);
    528         write(nat->controlFdW, &fd, sizeof(int));
    529 
    530         unsigned int flags = dbus_watch_get_flags(watch);
    531         write(nat->controlFdW, &flags, sizeof(unsigned int));
    532 
    533         write(nat->controlFdW, &watch, sizeof(DBusWatch*));
    534     }
    535     return true;
    536 }
    537 
    538 void dbusRemoveWatch(DBusWatch *watch, void *data) {
    539     native_data_t *nat = (native_data_t *)data;
    540 
    541     char control = EVENT_LOOP_REMOVE;
    542     write(nat->controlFdW, &control, sizeof(char));
    543 
    544     int fd = dbus_watch_get_fd(watch);
    545     write(nat->controlFdW, &fd, sizeof(int));
    546 
    547     unsigned int flags = dbus_watch_get_flags(watch);
    548     write(nat->controlFdW, &flags, sizeof(unsigned int));
    549 }
    550 
    551 void dbusToggleWatch(DBusWatch *watch, void *data) {
    552     if (dbus_watch_get_enabled(watch)) {
    553         dbusAddWatch(watch, data);
    554     } else {
    555         dbusRemoveWatch(watch, data);
    556     }
    557 }
    558 
    559 void dbusWakeup(void *data) {
    560     native_data_t *nat = (native_data_t *)data;
    561 
    562     char control = EVENT_LOOP_WAKEUP;
    563     write(nat->controlFdW, &control, sizeof(char));
    564 }
    565 
    566 static void handleWatchAdd(native_data_t *nat) {
    567     DBusWatch *watch;
    568     int newFD;
    569     unsigned int flags;
    570 
    571     read(nat->controlFdR, &newFD, sizeof(int));
    572     read(nat->controlFdR, &flags, sizeof(unsigned int));
    573     read(nat->controlFdR, &watch, sizeof(DBusWatch *));
    574     short events = dbus_flags_to_unix_events(flags);
    575 
    576     for (int y = 0; y<nat->pollMemberCount; y++) {
    577         if ((nat->pollData[y].fd == newFD) &&
    578                 (nat->pollData[y].events == events)) {
    579             LOGV("DBusWatch duplicate add");
    580             return;
    581         }
    582     }
    583     if (nat->pollMemberCount == nat->pollDataSize) {
    584         LOGV("Bluetooth EventLoop poll struct growing");
    585         struct pollfd *temp = (struct pollfd *)malloc(
    586                 sizeof(struct pollfd) * (nat->pollMemberCount+1));
    587         if (!temp) {
    588             return;
    589         }
    590         memcpy(temp, nat->pollData, sizeof(struct pollfd) *
    591                 nat->pollMemberCount);
    592         free(nat->pollData);
    593         nat->pollData = temp;
    594         DBusWatch **temp2 = (DBusWatch **)malloc(sizeof(DBusWatch *) *
    595                 (nat->pollMemberCount+1));
    596         if (!temp2) {
    597             return;
    598         }
    599         memcpy(temp2, nat->watchData, sizeof(DBusWatch *) *
    600                 nat->pollMemberCount);
    601         free(nat->watchData);
    602         nat->watchData = temp2;
    603         nat->pollDataSize++;
    604     }
    605     nat->pollData[nat->pollMemberCount].fd = newFD;
    606     nat->pollData[nat->pollMemberCount].revents = 0;
    607     nat->pollData[nat->pollMemberCount].events = events;
    608     nat->watchData[nat->pollMemberCount] = watch;
    609     nat->pollMemberCount++;
    610 }
    611 
    612 static void handleWatchRemove(native_data_t *nat) {
    613     int removeFD;
    614     unsigned int flags;
    615 
    616     read(nat->controlFdR, &removeFD, sizeof(int));
    617     read(nat->controlFdR, &flags, sizeof(unsigned int));
    618     short events = dbus_flags_to_unix_events(flags);
    619 
    620     for (int y = 0; y < nat->pollMemberCount; y++) {
    621         if ((nat->pollData[y].fd == removeFD) &&
    622                 (nat->pollData[y].events == events)) {
    623             int newCount = --nat->pollMemberCount;
    624             // copy the last live member over this one
    625             nat->pollData[y].fd = nat->pollData[newCount].fd;
    626             nat->pollData[y].events = nat->pollData[newCount].events;
    627             nat->pollData[y].revents = nat->pollData[newCount].revents;
    628             nat->watchData[y] = nat->watchData[newCount];
    629             return;
    630         }
    631     }
    632     LOGW("WatchRemove given with unknown watch");
    633 }
    634 
    635 static void *eventLoopMain(void *ptr) {
    636     native_data_t *nat = (native_data_t *)ptr;
    637     JNIEnv *env;
    638 
    639     JavaVMAttachArgs args;
    640     char name[] = "BT EventLoop";
    641     args.version = nat->envVer;
    642     args.name = name;
    643     args.group = NULL;
    644 
    645     nat->vm->AttachCurrentThread(&env, &args);
    646 
    647     dbus_connection_set_watch_functions(nat->conn, dbusAddWatch,
    648             dbusRemoveWatch, dbusToggleWatch, ptr, NULL);
    649     dbus_connection_set_wakeup_main_function(nat->conn, dbusWakeup, ptr, NULL);
    650 
    651     nat->running = true;
    652 
    653     while (1) {
    654         for (int i = 0; i < nat->pollMemberCount; i++) {
    655             if (!nat->pollData[i].revents) {
    656                 continue;
    657             }
    658             if (nat->pollData[i].fd == nat->controlFdR) {
    659                 char data;
    660                 while (recv(nat->controlFdR, &data, sizeof(char), MSG_DONTWAIT)
    661                         != -1) {
    662                     switch (data) {
    663                     case EVENT_LOOP_EXIT:
    664                     {
    665                         dbus_connection_set_watch_functions(nat->conn,
    666                                 NULL, NULL, NULL, NULL, NULL);
    667                         tearDownEventLoop(nat);
    668                         nat->vm->DetachCurrentThread();
    669 
    670                         int fd = nat->controlFdR;
    671                         nat->controlFdR = 0;
    672                         close(fd);
    673                         return NULL;
    674                     }
    675                     case EVENT_LOOP_ADD:
    676                     {
    677                         handleWatchAdd(nat);
    678                         break;
    679                     }
    680                     case EVENT_LOOP_REMOVE:
    681                     {
    682                         handleWatchRemove(nat);
    683                         break;
    684                     }
    685                     case EVENT_LOOP_WAKEUP:
    686                     {
    687                         // noop
    688                         break;
    689                     }
    690                     }
    691                 }
    692             } else {
    693                 short events = nat->pollData[i].revents;
    694                 unsigned int flags = unix_events_to_dbus_flags(events);
    695                 dbus_watch_handle(nat->watchData[i], flags);
    696                 nat->pollData[i].revents = 0;
    697                 // can only do one - it may have caused a 'remove'
    698                 break;
    699             }
    700         }
    701         while (dbus_connection_dispatch(nat->conn) ==
    702                 DBUS_DISPATCH_DATA_REMAINS) {
    703         }
    704 
    705         poll(nat->pollData, nat->pollMemberCount, -1);
    706     }
    707 }
    708 #endif // HAVE_BLUETOOTH
    709 
    710 static jboolean startEventLoopNative(JNIEnv *env, jobject object) {
    711     jboolean result = JNI_FALSE;
    712 #ifdef HAVE_BLUETOOTH
    713     event_loop_native_data_t *nat = get_native_data(env, object);
    714 
    715     pthread_mutex_lock(&(nat->thread_mutex));
    716 
    717     nat->running = false;
    718 
    719     if (nat->pollData) {
    720         LOGW("trying to start EventLoop a second time!");
    721         pthread_mutex_unlock( &(nat->thread_mutex) );
    722         return JNI_FALSE;
    723     }
    724 
    725     nat->pollData = (struct pollfd *)malloc(sizeof(struct pollfd) *
    726             DEFAULT_INITIAL_POLLFD_COUNT);
    727     if (!nat->pollData) {
    728         LOGE("out of memory error starting EventLoop!");
    729         goto done;
    730     }
    731 
    732     nat->watchData = (DBusWatch **)malloc(sizeof(DBusWatch *) *
    733             DEFAULT_INITIAL_POLLFD_COUNT);
    734     if (!nat->watchData) {
    735         LOGE("out of memory error starting EventLoop!");
    736         goto done;
    737     }
    738 
    739     memset(nat->pollData, 0, sizeof(struct pollfd) *
    740             DEFAULT_INITIAL_POLLFD_COUNT);
    741     memset(nat->watchData, 0, sizeof(DBusWatch *) *
    742             DEFAULT_INITIAL_POLLFD_COUNT);
    743     nat->pollDataSize = DEFAULT_INITIAL_POLLFD_COUNT;
    744     nat->pollMemberCount = 1;
    745 
    746     if (socketpair(AF_LOCAL, SOCK_STREAM, 0, &(nat->controlFdR))) {
    747         LOGE("Error getting BT control socket");
    748         goto done;
    749     }
    750     nat->pollData[0].fd = nat->controlFdR;
    751     nat->pollData[0].events = POLLIN;
    752 
    753     env->GetJavaVM( &(nat->vm) );
    754     nat->envVer = env->GetVersion();
    755 
    756     nat->me = env->NewGlobalRef(object);
    757 
    758     if (setUpEventLoop(nat) != JNI_TRUE) {
    759         LOGE("failure setting up Event Loop!");
    760         goto done;
    761     }
    762 
    763     pthread_create(&(nat->thread), NULL, eventLoopMain, nat);
    764     result = JNI_TRUE;
    765 
    766 done:
    767     if (JNI_FALSE == result) {
    768         if (nat->controlFdW) {
    769             close(nat->controlFdW);
    770             nat->controlFdW = 0;
    771         }
    772         if (nat->controlFdR) {
    773             close(nat->controlFdR);
    774             nat->controlFdR = 0;
    775         }
    776         if (nat->me) env->DeleteGlobalRef(nat->me);
    777         nat->me = NULL;
    778         if (nat->pollData) free(nat->pollData);
    779         nat->pollData = NULL;
    780         if (nat->watchData) free(nat->watchData);
    781         nat->watchData = NULL;
    782         nat->pollDataSize = 0;
    783         nat->pollMemberCount = 0;
    784     }
    785 
    786     pthread_mutex_unlock(&(nat->thread_mutex));
    787 #endif // HAVE_BLUETOOTH
    788     return result;
    789 }
    790 
    791 static void stopEventLoopNative(JNIEnv *env, jobject object) {
    792 #ifdef HAVE_BLUETOOTH
    793     native_data_t *nat = get_native_data(env, object);
    794 
    795     pthread_mutex_lock(&(nat->thread_mutex));
    796     if (nat->pollData) {
    797         char data = EVENT_LOOP_EXIT;
    798         ssize_t t = write(nat->controlFdW, &data, sizeof(char));
    799         void *ret;
    800         pthread_join(nat->thread, &ret);
    801 
    802         env->DeleteGlobalRef(nat->me);
    803         nat->me = NULL;
    804         free(nat->pollData);
    805         nat->pollData = NULL;
    806         free(nat->watchData);
    807         nat->watchData = NULL;
    808         nat->pollDataSize = 0;
    809         nat->pollMemberCount = 0;
    810 
    811         int fd = nat->controlFdW;
    812         nat->controlFdW = 0;
    813         close(fd);
    814     }
    815     nat->running = false;
    816     pthread_mutex_unlock(&(nat->thread_mutex));
    817 #endif // HAVE_BLUETOOTH
    818 }
    819 
    820 static jboolean isEventLoopRunningNative(JNIEnv *env, jobject object) {
    821     jboolean result = JNI_FALSE;
    822 #ifdef HAVE_BLUETOOTH
    823     native_data_t *nat = get_native_data(env, object);
    824 
    825     pthread_mutex_lock(&(nat->thread_mutex));
    826     if (nat->running) {
    827         result = JNI_TRUE;
    828     }
    829     pthread_mutex_unlock(&(nat->thread_mutex));
    830 
    831 #endif // HAVE_BLUETOOTH
    832     return result;
    833 }
    834 
    835 #ifdef HAVE_BLUETOOTH
    836 extern DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env);
    837 
    838 // Called by dbus during WaitForAndDispatchEventNative()
    839 static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
    840                                       void *data) {
    841     native_data_t *nat;
    842     JNIEnv *env;
    843     DBusError err;
    844     DBusHandlerResult ret;
    845 
    846     dbus_error_init(&err);
    847 
    848     nat = (native_data_t *)data;
    849     nat->vm->GetEnv((void**)&env, nat->envVer);
    850     if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) {
    851         LOGV("%s: not interested (not a signal).", __FUNCTION__);
    852         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    853     }
    854 
    855     LOGV("%s: Received signal %s:%s from %s", __FUNCTION__,
    856         dbus_message_get_interface(msg), dbus_message_get_member(msg),
    857         dbus_message_get_path(msg));
    858 
    859     env->PushLocalFrame(EVENT_LOOP_REFS);
    860     if (dbus_message_is_signal(msg,
    861                                "org.bluez.Adapter",
    862                                "DeviceFound")) {
    863         char *c_address;
    864         DBusMessageIter iter;
    865         jobjectArray str_array = NULL;
    866         if (dbus_message_iter_init(msg, &iter)) {
    867             dbus_message_iter_get_basic(&iter, &c_address);
    868             if (dbus_message_iter_next(&iter))
    869                 str_array =
    870                     parse_remote_device_properties(env, &iter);
    871         }
    872         if (str_array != NULL) {
    873             env->CallVoidMethod(nat->me,
    874                                 method_onDeviceFound,
    875                                 env->NewStringUTF(c_address),
    876                                 str_array);
    877         } else
    878             LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    879         goto success;
    880     } else if (dbus_message_is_signal(msg,
    881                                      "org.bluez.Adapter",
    882                                      "DeviceDisappeared")) {
    883         char *c_address;
    884         if (dbus_message_get_args(msg, &err,
    885                                   DBUS_TYPE_STRING, &c_address,
    886                                   DBUS_TYPE_INVALID)) {
    887             LOGV("... address = %s", c_address);
    888             env->CallVoidMethod(nat->me, method_onDeviceDisappeared,
    889                                 env->NewStringUTF(c_address));
    890         } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    891         goto success;
    892     } else if (dbus_message_is_signal(msg,
    893                                      "org.bluez.Adapter",
    894                                      "DeviceCreated")) {
    895         char *c_object_path;
    896         if (dbus_message_get_args(msg, &err,
    897                                   DBUS_TYPE_OBJECT_PATH, &c_object_path,
    898                                   DBUS_TYPE_INVALID)) {
    899             LOGV("... address = %s", c_object_path);
    900             env->CallVoidMethod(nat->me,
    901                                 method_onDeviceCreated,
    902                                 env->NewStringUTF(c_object_path));
    903         } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    904         goto success;
    905     } else if (dbus_message_is_signal(msg,
    906                                      "org.bluez.Adapter",
    907                                      "DeviceRemoved")) {
    908         char *c_object_path;
    909         if (dbus_message_get_args(msg, &err,
    910                                  DBUS_TYPE_OBJECT_PATH, &c_object_path,
    911                                  DBUS_TYPE_INVALID)) {
    912            LOGV("... Object Path = %s", c_object_path);
    913            env->CallVoidMethod(nat->me,
    914                                method_onDeviceRemoved,
    915                                env->NewStringUTF(c_object_path));
    916         } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    917         goto success;
    918     } else if (dbus_message_is_signal(msg,
    919                                       "org.bluez.Adapter",
    920                                       "PropertyChanged")) {
    921         jobjectArray str_array = parse_adapter_property_change(env, msg);
    922         if (str_array != NULL) {
    923             /* Check if bluetoothd has (re)started, if so update the path. */
    924             jstring property =(jstring) env->GetObjectArrayElement(str_array, 0);
    925             const char *c_property = env->GetStringUTFChars(property, NULL);
    926             if (!strncmp(c_property, "Powered", strlen("Powered"))) {
    927                 jstring value =
    928                     (jstring) env->GetObjectArrayElement(str_array, 1);
    929                 const char *c_value = env->GetStringUTFChars(value, NULL);
    930                 if (!strncmp(c_value, "true", strlen("true")))
    931                     nat->adapter = get_adapter_path(nat->conn);
    932                 env->ReleaseStringUTFChars(value, c_value);
    933             }
    934             env->ReleaseStringUTFChars(property, c_property);
    935 
    936             env->CallVoidMethod(nat->me,
    937                               method_onPropertyChanged,
    938                               str_array);
    939         } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    940         goto success;
    941     } else if (dbus_message_is_signal(msg,
    942                                       "org.bluez.Device",
    943                                       "PropertyChanged")) {
    944         jobjectArray str_array = parse_remote_device_property_change(env, msg);
    945         if (str_array != NULL) {
    946             const char *remote_device_path = dbus_message_get_path(msg);
    947             env->CallVoidMethod(nat->me,
    948                             method_onDevicePropertyChanged,
    949                             env->NewStringUTF(remote_device_path),
    950                             str_array);
    951         } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    952         goto success;
    953     } else if (dbus_message_is_signal(msg,
    954                                       "org.bluez.Device",
    955                                       "DisconnectRequested")) {
    956         const char *remote_device_path = dbus_message_get_path(msg);
    957         env->CallVoidMethod(nat->me,
    958                             method_onDeviceDisconnectRequested,
    959                             env->NewStringUTF(remote_device_path));
    960         goto success;
    961     } else if (dbus_message_is_signal(msg,
    962                                       "org.bluez.Input",
    963                                       "PropertyChanged")) {
    964 
    965         jobjectArray str_array =
    966                     parse_input_property_change(env, msg);
    967         if (str_array != NULL) {
    968             const char *c_path = dbus_message_get_path(msg);
    969             env->CallVoidMethod(nat->me,
    970                                 method_onInputDevicePropertyChanged,
    971                                 env->NewStringUTF(c_path),
    972                                 str_array);
    973         } else {
    974             LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    975         }
    976         goto success;
    977     } else if (dbus_message_is_signal(msg,
    978                                      "org.bluez.Network",
    979                                      "PropertyChanged")) {
    980 
    981        jobjectArray str_array =
    982                    parse_pan_property_change(env, msg);
    983        if (str_array != NULL) {
    984            const char *c_path = dbus_message_get_path(msg);
    985            env->CallVoidMethod(nat->me,
    986                                method_onPanDevicePropertyChanged,
    987                                env->NewStringUTF(c_path),
    988                                str_array);
    989        } else {
    990            LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
    991        }
    992        goto success;
    993     } else if (dbus_message_is_signal(msg,
    994                                      "org.bluez.NetworkServer",
    995                                      "DeviceDisconnected")) {
    996        char *c_address;
    997        if (dbus_message_get_args(msg, &err,
    998                                   DBUS_TYPE_STRING, &c_address,
    999                                   DBUS_TYPE_INVALID)) {
   1000            env->CallVoidMethod(nat->me,
   1001                                method_onNetworkDeviceDisconnected,
   1002                                env->NewStringUTF(c_address));
   1003        } else {
   1004            LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
   1005        }
   1006        goto success;
   1007     } else if (dbus_message_is_signal(msg,
   1008                                      "org.bluez.NetworkServer",
   1009                                      "DeviceConnected")) {
   1010        char *c_address;
   1011        char *c_iface;
   1012        uint16_t uuid;
   1013 
   1014        if (dbus_message_get_args(msg, &err,
   1015                                   DBUS_TYPE_STRING, &c_address,
   1016                                   DBUS_TYPE_STRING, &c_iface,
   1017                                   DBUS_TYPE_UINT16, &uuid,
   1018                                   DBUS_TYPE_INVALID)) {
   1019            env->CallVoidMethod(nat->me,
   1020                                method_onNetworkDeviceConnected,
   1021                                env->NewStringUTF(c_address),
   1022                                env->NewStringUTF(c_iface),
   1023                                uuid);
   1024        } else {
   1025            LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
   1026        }
   1027        goto success;
   1028     } else if (dbus_message_is_signal(msg,
   1029                                      "org.bluez.HealthDevice",
   1030                                      "ChannelConnected")) {
   1031        const char *c_path = dbus_message_get_path(msg);
   1032        const char *c_channel_path;
   1033        jboolean exists = JNI_TRUE;
   1034        if (dbus_message_get_args(msg, &err,
   1035                                   DBUS_TYPE_OBJECT_PATH, &c_channel_path,
   1036                                   DBUS_TYPE_INVALID)) {
   1037            env->CallVoidMethod(nat->me,
   1038                                method_onHealthDeviceChannelChanged,
   1039                                env->NewStringUTF(c_path),
   1040                                env->NewStringUTF(c_channel_path),
   1041                                exists);
   1042        } else {
   1043            LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
   1044        }
   1045        goto success;
   1046     } else if (dbus_message_is_signal(msg,
   1047                                      "org.bluez.HealthDevice",
   1048                                      "ChannelDeleted")) {
   1049 
   1050        const char *c_path = dbus_message_get_path(msg);
   1051        const char *c_channel_path;
   1052        jboolean exists = JNI_FALSE;
   1053        if (dbus_message_get_args(msg, &err,
   1054                                   DBUS_TYPE_OBJECT_PATH, &c_channel_path,
   1055                                   DBUS_TYPE_INVALID)) {
   1056            env->CallVoidMethod(nat->me,
   1057                                method_onHealthDeviceChannelChanged,
   1058                                env->NewStringUTF(c_path),
   1059                                env->NewStringUTF(c_channel_path),
   1060                                exists);
   1061        } else {
   1062            LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
   1063        }
   1064        goto success;
   1065     } else if (dbus_message_is_signal(msg,
   1066                                      "org.bluez.HealthDevice",
   1067                                      "PropertyChanged")) {
   1068         jobjectArray str_array =
   1069                     parse_health_device_property_change(env, msg);
   1070         if (str_array != NULL) {
   1071             const char *c_path = dbus_message_get_path(msg);
   1072             env->CallVoidMethod(nat->me,
   1073                                 method_onHealthDevicePropertyChanged,
   1074                                 env->NewStringUTF(c_path),
   1075                                 str_array);
   1076        } else {
   1077            LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
   1078        }
   1079        goto success;
   1080     }
   1081 
   1082     ret = a2dp_event_filter(msg, env);
   1083     env->PopLocalFrame(NULL);
   1084     return ret;
   1085 
   1086 success:
   1087     env->PopLocalFrame(NULL);
   1088     return DBUS_HANDLER_RESULT_HANDLED;
   1089 }
   1090 
   1091 // Called by dbus during WaitForAndDispatchEventNative()
   1092 DBusHandlerResult agent_event_filter(DBusConnection *conn,
   1093                                      DBusMessage *msg, void *data) {
   1094     native_data_t *nat = (native_data_t *)data;
   1095     JNIEnv *env;
   1096     if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) {
   1097         LOGV("%s: not interested (not a method call).", __FUNCTION__);
   1098         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   1099     }
   1100     LOGI("%s: Received method %s:%s", __FUNCTION__,
   1101          dbus_message_get_interface(msg), dbus_message_get_member(msg));
   1102 
   1103     if (nat == NULL) return DBUS_HANDLER_RESULT_HANDLED;
   1104 
   1105     nat->vm->GetEnv((void**)&env, nat->envVer);
   1106     env->PushLocalFrame(EVENT_LOOP_REFS);
   1107 
   1108     if (dbus_message_is_method_call(msg,
   1109             "org.bluez.Agent", "Cancel")) {
   1110         env->CallVoidMethod(nat->me, method_onAgentCancel);
   1111         // reply
   1112         DBusMessage *reply = dbus_message_new_method_return(msg);
   1113         if (!reply) {
   1114             LOGE("%s: Cannot create message reply\n", __FUNCTION__);
   1115             goto failure;
   1116         }
   1117         dbus_connection_send(nat->conn, reply, NULL);
   1118         dbus_message_unref(reply);
   1119         goto success;
   1120 
   1121     } else if (dbus_message_is_method_call(msg,
   1122             "org.bluez.Agent", "Authorize")) {
   1123         char *object_path;
   1124         const char *uuid;
   1125         if (!dbus_message_get_args(msg, NULL,
   1126                                    DBUS_TYPE_OBJECT_PATH, &object_path,
   1127                                    DBUS_TYPE_STRING, &uuid,
   1128                                    DBUS_TYPE_INVALID)) {
   1129             LOGE("%s: Invalid arguments for Authorize() method", __FUNCTION__);
   1130             goto failure;
   1131         }
   1132 
   1133         LOGV("... object_path = %s", object_path);
   1134         LOGV("... uuid = %s", uuid);
   1135 
   1136         dbus_message_ref(msg);  // increment refcount because we pass to java
   1137         env->CallVoidMethod(nat->me, method_onAgentAuthorize,
   1138                 env->NewStringUTF(object_path), env->NewStringUTF(uuid),
   1139                 int(msg));
   1140 
   1141         goto success;
   1142     } else if (dbus_message_is_method_call(msg,
   1143             "org.bluez.Agent", "OutOfBandAvailable")) {
   1144         char *object_path;
   1145         if (!dbus_message_get_args(msg, NULL,
   1146                                    DBUS_TYPE_OBJECT_PATH, &object_path,
   1147                                    DBUS_TYPE_INVALID)) {
   1148             LOGE("%s: Invalid arguments for OutOfBandData available() method", __FUNCTION__);
   1149             goto failure;
   1150         }
   1151 
   1152         LOGV("... object_path = %s", object_path);
   1153 
   1154         bool available =
   1155             env->CallBooleanMethod(nat->me, method_onAgentOutOfBandDataAvailable,
   1156                 env->NewStringUTF(object_path));
   1157 
   1158 
   1159         // reply
   1160         if (available) {
   1161             DBusMessage *reply = dbus_message_new_method_return(msg);
   1162             if (!reply) {
   1163                 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
   1164                 goto failure;
   1165             }
   1166             dbus_connection_send(nat->conn, reply, NULL);
   1167             dbus_message_unref(reply);
   1168         } else {
   1169             DBusMessage *reply = dbus_message_new_error(msg,
   1170                     "org.bluez.Error.DoesNotExist", "OutofBand data not available");
   1171             if (!reply) {
   1172                 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
   1173                 goto failure;
   1174             }
   1175             dbus_connection_send(nat->conn, reply, NULL);
   1176             dbus_message_unref(reply);
   1177         }
   1178         goto success;
   1179     } else if (dbus_message_is_method_call(msg,
   1180             "org.bluez.Agent", "RequestPinCode")) {
   1181         char *object_path;
   1182         if (!dbus_message_get_args(msg, NULL,
   1183                                    DBUS_TYPE_OBJECT_PATH, &object_path,
   1184                                    DBUS_TYPE_INVALID)) {
   1185             LOGE("%s: Invalid arguments for RequestPinCode() method", __FUNCTION__);
   1186             goto failure;
   1187         }
   1188 
   1189         dbus_message_ref(msg);  // increment refcount because we pass to java
   1190         env->CallVoidMethod(nat->me, method_onRequestPinCode,
   1191                                        env->NewStringUTF(object_path),
   1192                                        int(msg));
   1193         goto success;
   1194     } else if (dbus_message_is_method_call(msg,
   1195             "org.bluez.Agent", "RequestPasskey")) {
   1196         char *object_path;
   1197         if (!dbus_message_get_args(msg, NULL,
   1198                                    DBUS_TYPE_OBJECT_PATH, &object_path,
   1199                                    DBUS_TYPE_INVALID)) {
   1200             LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
   1201             goto failure;
   1202         }
   1203 
   1204         dbus_message_ref(msg);  // increment refcount because we pass to java
   1205         env->CallVoidMethod(nat->me, method_onRequestPasskey,
   1206                                        env->NewStringUTF(object_path),
   1207                                        int(msg));
   1208         goto success;
   1209     } else if (dbus_message_is_method_call(msg,
   1210             "org.bluez.Agent", "RequestOobData")) {
   1211         char *object_path;
   1212         if (!dbus_message_get_args(msg, NULL,
   1213                                    DBUS_TYPE_OBJECT_PATH, &object_path,
   1214                                    DBUS_TYPE_INVALID)) {
   1215             LOGE("%s: Invalid arguments for RequestOobData() method", __FUNCTION__);
   1216             goto failure;
   1217         }
   1218 
   1219         dbus_message_ref(msg);  // increment refcount because we pass to java
   1220         env->CallVoidMethod(nat->me, method_onRequestOobData,
   1221                                        env->NewStringUTF(object_path),
   1222                                        int(msg));
   1223         goto success;
   1224     } else if (dbus_message_is_method_call(msg,
   1225             "org.bluez.Agent", "DisplayPasskey")) {
   1226         char *object_path;
   1227         uint32_t passkey;
   1228         if (!dbus_message_get_args(msg, NULL,
   1229                                    DBUS_TYPE_OBJECT_PATH, &object_path,
   1230                                    DBUS_TYPE_UINT32, &passkey,
   1231                                    DBUS_TYPE_INVALID)) {
   1232             LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
   1233             goto failure;
   1234         }
   1235 
   1236         dbus_message_ref(msg);  // increment refcount because we pass to java
   1237         env->CallVoidMethod(nat->me, method_onDisplayPasskey,
   1238                                        env->NewStringUTF(object_path),
   1239                                        passkey,
   1240                                        int(msg));
   1241         goto success;
   1242     } else if (dbus_message_is_method_call(msg,
   1243             "org.bluez.Agent", "RequestConfirmation")) {
   1244         char *object_path;
   1245         uint32_t passkey;
   1246         if (!dbus_message_get_args(msg, NULL,
   1247                                    DBUS_TYPE_OBJECT_PATH, &object_path,
   1248                                    DBUS_TYPE_UINT32, &passkey,
   1249                                    DBUS_TYPE_INVALID)) {
   1250             LOGE("%s: Invalid arguments for RequestConfirmation() method", __FUNCTION__);
   1251             goto failure;
   1252         }
   1253 
   1254         dbus_message_ref(msg);  // increment refcount because we pass to java
   1255         env->CallVoidMethod(nat->me, method_onRequestPasskeyConfirmation,
   1256                                        env->NewStringUTF(object_path),
   1257                                        passkey,
   1258                                        int(msg));
   1259         goto success;
   1260     } else if (dbus_message_is_method_call(msg,
   1261             "org.bluez.Agent", "RequestPairingConsent")) {
   1262         char *object_path;
   1263         if (!dbus_message_get_args(msg, NULL,
   1264                                    DBUS_TYPE_OBJECT_PATH, &object_path,
   1265                                    DBUS_TYPE_INVALID)) {
   1266             LOGE("%s: Invalid arguments for RequestPairingConsent() method", __FUNCTION__);
   1267             goto failure;
   1268         }
   1269 
   1270         dbus_message_ref(msg);  // increment refcount because we pass to java
   1271         env->CallVoidMethod(nat->me, method_onRequestPairingConsent,
   1272                                        env->NewStringUTF(object_path),
   1273                                        int(msg));
   1274         goto success;
   1275     } else if (dbus_message_is_method_call(msg,
   1276                   "org.bluez.Agent", "Release")) {
   1277         // reply
   1278         DBusMessage *reply = dbus_message_new_method_return(msg);
   1279         if (!reply) {
   1280             LOGE("%s: Cannot create message reply\n", __FUNCTION__);
   1281             goto failure;
   1282         }
   1283         dbus_connection_send(nat->conn, reply, NULL);
   1284         dbus_message_unref(reply);
   1285         goto success;
   1286     } else {
   1287         LOGV("%s:%s is ignored", dbus_message_get_interface(msg), dbus_message_get_member(msg));
   1288     }
   1289 
   1290 failure:
   1291     env->PopLocalFrame(NULL);
   1292     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   1293 
   1294 success:
   1295     env->PopLocalFrame(NULL);
   1296     return DBUS_HANDLER_RESULT_HANDLED;
   1297 
   1298 }
   1299 #endif
   1300 
   1301 
   1302 #ifdef HAVE_BLUETOOTH
   1303 
   1304 void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) {
   1305     LOGV("%s", __FUNCTION__);
   1306 
   1307     native_data_t *nat = (native_data_t *)n;
   1308     const char *address = (const char *)user;
   1309     DBusError err;
   1310     dbus_error_init(&err);
   1311     JNIEnv *env;
   1312     jstring addr;
   1313 
   1314     nat->vm->GetEnv((void**)&env, nat->envVer);
   1315 
   1316     LOGV("... address = %s", address);
   1317 
   1318     jint result = BOND_RESULT_SUCCESS;
   1319     if (dbus_set_error_from_message(&err, msg)) {
   1320         if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) {
   1321             // Pins did not match, or remote device did not respond to pin
   1322             // request in time
   1323             LOGV("... error = %s (%s)\n", err.name, err.message);
   1324             result = BOND_RESULT_AUTH_FAILED;
   1325         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationRejected")) {
   1326             // We rejected pairing, or the remote side rejected pairing. This
   1327             // happens if either side presses 'cancel' at the pairing dialog.
   1328             LOGV("... error = %s (%s)\n", err.name, err.message);
   1329             result = BOND_RESULT_AUTH_REJECTED;
   1330         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationCanceled")) {
   1331             // Not sure if this happens
   1332             LOGV("... error = %s (%s)\n", err.name, err.message);
   1333             result = BOND_RESULT_AUTH_CANCELED;
   1334         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.ConnectionAttemptFailed")) {
   1335             // Other device is not responding at all
   1336             LOGV("... error = %s (%s)\n", err.name, err.message);
   1337             result = BOND_RESULT_REMOTE_DEVICE_DOWN;
   1338         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AlreadyExists")) {
   1339             // already bonded
   1340             LOGV("... error = %s (%s)\n", err.name, err.message);
   1341             result = BOND_RESULT_SUCCESS;
   1342         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") &&
   1343                    !strcmp(err.message, "Bonding in progress")) {
   1344             LOGV("... error = %s (%s)\n", err.name, err.message);
   1345             goto done;
   1346         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") &&
   1347                    !strcmp(err.message, "Discover in progress")) {
   1348             LOGV("... error = %s (%s)\n", err.name, err.message);
   1349             result = BOND_RESULT_DISCOVERY_IN_PROGRESS;
   1350         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.RepeatedAttempts")) {
   1351             LOGV("... error = %s (%s)\n", err.name, err.message);
   1352             result = BOND_RESULT_REPEATED_ATTEMPTS;
   1353         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationTimeout")) {
   1354             LOGV("... error = %s (%s)\n", err.name, err.message);
   1355             result = BOND_RESULT_AUTH_TIMEOUT;
   1356         } else {
   1357             LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
   1358             result = BOND_RESULT_ERROR;
   1359         }
   1360     }
   1361 
   1362     addr = env->NewStringUTF(address);
   1363     env->CallVoidMethod(nat->me,
   1364                         method_onCreatePairedDeviceResult,
   1365                         addr,
   1366                         result);
   1367     env->DeleteLocalRef(addr);
   1368 done:
   1369     dbus_error_free(&err);
   1370     free(user);
   1371 }
   1372 
   1373 void onCreateDeviceResult(DBusMessage *msg, void *user, void *n) {
   1374     LOGV("%s", __FUNCTION__);
   1375 
   1376     native_data_t *nat = (native_data_t *)n;
   1377     const char *address= (const char *)user;
   1378     DBusError err;
   1379     dbus_error_init(&err);
   1380     JNIEnv *env;
   1381     nat->vm->GetEnv((void**)&env, nat->envVer);
   1382 
   1383     LOGV("... Address = %s", address);
   1384 
   1385     jint result = CREATE_DEVICE_SUCCESS;
   1386     if (dbus_set_error_from_message(&err, msg)) {
   1387         if (dbus_error_has_name(&err, "org.bluez.Error.AlreadyExists")) {
   1388             result = CREATE_DEVICE_ALREADY_EXISTS;
   1389         } else {
   1390             result = CREATE_DEVICE_FAILED;
   1391         }
   1392         LOG_AND_FREE_DBUS_ERROR(&err);
   1393     }
   1394     jstring addr = env->NewStringUTF(address);
   1395     env->CallVoidMethod(nat->me,
   1396                         method_onCreateDeviceResult,
   1397                         addr,
   1398                         result);
   1399     env->DeleteLocalRef(addr);
   1400     free(user);
   1401 }
   1402 
   1403 void onDiscoverServicesResult(DBusMessage *msg, void *user, void *n) {
   1404     LOGV("%s", __FUNCTION__);
   1405 
   1406     native_data_t *nat = (native_data_t *)n;
   1407     const char *path = (const char *)user;
   1408     DBusError err;
   1409     dbus_error_init(&err);
   1410     JNIEnv *env;
   1411     nat->vm->GetEnv((void**)&env, nat->envVer);
   1412 
   1413     LOGV("... Device Path = %s", path);
   1414 
   1415     bool result = JNI_TRUE;
   1416     if (dbus_set_error_from_message(&err, msg)) {
   1417         LOG_AND_FREE_DBUS_ERROR(&err);
   1418         result = JNI_FALSE;
   1419     }
   1420     jstring jPath = env->NewStringUTF(path);
   1421     env->CallVoidMethod(nat->me,
   1422                         method_onDiscoverServicesResult,
   1423                         jPath,
   1424                         result);
   1425     env->DeleteLocalRef(jPath);
   1426     free(user);
   1427 }
   1428 
   1429 void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) {
   1430     LOGV("%s", __FUNCTION__);
   1431 
   1432     const char *address = (const char *) user;
   1433     native_data_t *nat = (native_data_t *) n;
   1434 
   1435     DBusError err;
   1436     dbus_error_init(&err);
   1437     JNIEnv *env;
   1438     nat->vm->GetEnv((void**)&env, nat->envVer);
   1439 
   1440     jint channel = -2;
   1441 
   1442     LOGV("... address = %s", address);
   1443 
   1444     if (dbus_set_error_from_message(&err, msg) ||
   1445         !dbus_message_get_args(msg, &err,
   1446                                DBUS_TYPE_INT32, &channel,
   1447                                DBUS_TYPE_INVALID)) {
   1448         LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
   1449         dbus_error_free(&err);
   1450     }
   1451 
   1452 done:
   1453     jstring addr = env->NewStringUTF(address);
   1454     env->CallVoidMethod(nat->me,
   1455                         method_onGetDeviceServiceChannelResult,
   1456                         addr,
   1457                         channel);
   1458     env->DeleteLocalRef(addr);
   1459     free(user);
   1460 }
   1461 
   1462 void onInputDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
   1463     LOGV("%s", __FUNCTION__);
   1464 
   1465     native_data_t *nat = (native_data_t *)n;
   1466     const char *path = (const char *)user;
   1467     DBusError err;
   1468     dbus_error_init(&err);
   1469     JNIEnv *env;
   1470     nat->vm->GetEnv((void**)&env, nat->envVer);
   1471 
   1472     jint result = INPUT_OPERATION_SUCCESS;
   1473     if (dbus_set_error_from_message(&err, msg)) {
   1474         if (!strcmp(err.name, BLUEZ_ERROR_IFC ".ConnectionAttemptFailed")) {
   1475             result = INPUT_CONNECT_FAILED_ATTEMPT_FAILED;
   1476         } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".AlreadyConnected")) {
   1477             result = INPUT_CONNECT_FAILED_ALREADY_CONNECTED;
   1478         } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".Failed")) {
   1479             // TODO():This is flaky, need to change Bluez to add new error codes
   1480             if (!strcmp(err.message, "Transport endpoint is not connected")) {
   1481               result = INPUT_DISCONNECT_FAILED_NOT_CONNECTED;
   1482             } else {
   1483               result = INPUT_OPERATION_GENERIC_FAILURE;
   1484             }
   1485         } else {
   1486             result = INPUT_OPERATION_GENERIC_FAILURE;
   1487         }
   1488         LOG_AND_FREE_DBUS_ERROR(&err);
   1489     }
   1490 
   1491     LOGV("... Device Path = %s, result = %d", path, result);
   1492     jstring jPath = env->NewStringUTF(path);
   1493     env->CallVoidMethod(nat->me,
   1494                         method_onInputDeviceConnectionResult,
   1495                         jPath,
   1496                         result);
   1497     env->DeleteLocalRef(jPath);
   1498     free(user);
   1499 }
   1500 
   1501 void onPanDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
   1502     LOGV("%s", __FUNCTION__);
   1503 
   1504     native_data_t *nat = (native_data_t *)n;
   1505     const char *path = (const char *)user;
   1506     DBusError err;
   1507     dbus_error_init(&err);
   1508     JNIEnv *env;
   1509     nat->vm->GetEnv((void**)&env, nat->envVer);
   1510 
   1511     jint result = PAN_OPERATION_SUCCESS;
   1512     if (dbus_set_error_from_message(&err, msg)) {
   1513         if (!strcmp(err.name, BLUEZ_ERROR_IFC ".ConnectionAttemptFailed")) {
   1514             result = PAN_CONNECT_FAILED_ATTEMPT_FAILED;
   1515         } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".Failed")) {
   1516             // TODO():This is flaky, need to change Bluez to add new error codes
   1517             if (!strcmp(err.message, "Device already connected")) {
   1518                 result = PAN_CONNECT_FAILED_ALREADY_CONNECTED;
   1519             } else if (!strcmp(err.message, "Device not connected")) {
   1520                 result = PAN_DISCONNECT_FAILED_NOT_CONNECTED;
   1521             } else {
   1522                 result = PAN_OPERATION_GENERIC_FAILURE;
   1523             }
   1524         } else {
   1525             result = PAN_OPERATION_GENERIC_FAILURE;
   1526         }
   1527         LOG_AND_FREE_DBUS_ERROR(&err);
   1528     }
   1529 
   1530     LOGV("... Pan Device Path = %s, result = %d", path, result);
   1531     jstring jPath = env->NewStringUTF(path);
   1532     env->CallVoidMethod(nat->me,
   1533                         method_onPanDeviceConnectionResult,
   1534                         jPath,
   1535                         result);
   1536     env->DeleteLocalRef(jPath);
   1537     free(user);
   1538 }
   1539 
   1540 void onHealthDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
   1541     LOGV("%s", __FUNCTION__);
   1542 
   1543     native_data_t *nat = (native_data_t *)n;
   1544     DBusError err;
   1545     dbus_error_init(&err);
   1546     JNIEnv *env;
   1547     nat->vm->GetEnv((void**)&env, nat->envVer);
   1548 
   1549     jint result = HEALTH_OPERATION_SUCCESS;
   1550     if (dbus_set_error_from_message(&err, msg)) {
   1551         if (!strcmp(err.name, BLUEZ_ERROR_IFC ".InvalidArgs")) {
   1552             result = HEALTH_OPERATION_INVALID_ARGS;
   1553         } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".HealthError")) {
   1554             result = HEALTH_OPERATION_ERROR;
   1555         } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".NotFound")) {
   1556             result = HEALTH_OPERATION_NOT_FOUND;
   1557         } else if (!strcmp(err.name, BLUEZ_ERROR_IFC ".NotAllowed")) {
   1558             result = HEALTH_OPERATION_NOT_ALLOWED;
   1559         } else {
   1560             result = HEALTH_OPERATION_GENERIC_FAILURE;
   1561         }
   1562         LOG_AND_FREE_DBUS_ERROR(&err);
   1563     }
   1564 
   1565     jint code = *(int *) user;
   1566     LOGV("... Health Device Code = %d, result = %d", code, result);
   1567     env->CallVoidMethod(nat->me,
   1568                         method_onHealthDeviceConnectionResult,
   1569                         code,
   1570                         result);
   1571     free(user);
   1572 }
   1573 #endif
   1574 
   1575 static JNINativeMethod sMethods[] = {
   1576      /* name, signature, funcPtr */
   1577     {"classInitNative", "()V", (void *)classInitNative},
   1578     {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
   1579     {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
   1580     {"startEventLoopNative", "()V", (void *)startEventLoopNative},
   1581     {"stopEventLoopNative", "()V", (void *)stopEventLoopNative},
   1582     {"isEventLoopRunningNative", "()Z", (void *)isEventLoopRunningNative}
   1583 };
   1584 
   1585 int register_android_server_BluetoothEventLoop(JNIEnv *env) {
   1586     return AndroidRuntime::registerNativeMethods(env,
   1587             "android/server/BluetoothEventLoop", sMethods, NELEM(sMethods));
   1588 }
   1589 
   1590 } /* namespace android */
   1591