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