OSDN Git Service

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