• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
get_native_data(JNIEnv * env,jobject object)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 
get_EventLoop_native_data(JNIEnv * env,jobject object)78 native_data_t *get_EventLoop_native_data(JNIEnv *env, jobject object) {
79     return get_native_data(env, object);
80 }
81 
82 #endif
classInitNative(JNIEnv * env,jclass clazz)83 static void classInitNative(JNIEnv* env, jclass clazz) {
84     LOGV(__FUNCTION__);
85 
86 #ifdef HAVE_BLUETOOTH
87     method_onPropertyChanged = env->GetMethodID(clazz, "onPropertyChanged",
88                                                 "([Ljava/lang/String;)V");
89     method_onDevicePropertyChanged = env->GetMethodID(clazz,
90                                                       "onDevicePropertyChanged",
91                                                       "(Ljava/lang/String;[Ljava/lang/String;)V");
92     method_onDeviceFound = env->GetMethodID(clazz, "onDeviceFound",
93                                             "(Ljava/lang/String;[Ljava/lang/String;)V");
94     method_onDeviceDisappeared = env->GetMethodID(clazz, "onDeviceDisappeared",
95                                                   "(Ljava/lang/String;)V");
96     method_onDeviceCreated = env->GetMethodID(clazz, "onDeviceCreated", "(Ljava/lang/String;)V");
97     method_onDeviceRemoved = env->GetMethodID(clazz, "onDeviceRemoved", "(Ljava/lang/String;)V");
98     method_onDeviceDisconnectRequested = env->GetMethodID(clazz, "onDeviceDisconnectRequested",
99                                                         "(Ljava/lang/String;)V");
100 
101     method_onCreatePairedDeviceResult = env->GetMethodID(clazz, "onCreatePairedDeviceResult",
102                                                          "(Ljava/lang/String;I)V");
103     method_onCreateDeviceResult = env->GetMethodID(clazz, "onCreateDeviceResult",
104                                                          "(Ljava/lang/String;I)V");
105     method_onDiscoverServicesResult = env->GetMethodID(clazz, "onDiscoverServicesResult",
106                                                          "(Ljava/lang/String;Z)V");
107 
108     method_onAgentAuthorize = env->GetMethodID(clazz, "onAgentAuthorize",
109                                                "(Ljava/lang/String;Ljava/lang/String;I)V");
110     method_onAgentOutOfBandDataAvailable = env->GetMethodID(clazz, "onAgentOutOfBandDataAvailable",
111                                                "(Ljava/lang/String;)Z");
112     method_onAgentCancel = env->GetMethodID(clazz, "onAgentCancel", "()V");
113     method_onRequestPinCode = env->GetMethodID(clazz, "onRequestPinCode",
114                                                "(Ljava/lang/String;I)V");
115     method_onRequestPasskey = env->GetMethodID(clazz, "onRequestPasskey",
116                                                "(Ljava/lang/String;I)V");
117     method_onRequestPasskeyConfirmation = env->GetMethodID(clazz, "onRequestPasskeyConfirmation",
118                                                "(Ljava/lang/String;II)V");
119     method_onRequestPairingConsent = env->GetMethodID(clazz, "onRequestPairingConsent",
120                                                "(Ljava/lang/String;I)V");
121     method_onDisplayPasskey = env->GetMethodID(clazz, "onDisplayPasskey",
122                                                "(Ljava/lang/String;II)V");
123     method_onRequestOobData = env->GetMethodID(clazz, "onRequestOobData",
124                                                "(Ljava/lang/String;I)V");
125 
126     field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I");
127 #endif
128 }
129 
initializeNativeDataNative(JNIEnv * env,jobject object)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 
cleanupNativeDataNative(JNIEnv * env,jobject object)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 
unix_events_to_dbus_flags(short events)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 
dbus_flags_to_unix_events(unsigned int flags)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 
setUpEventLoop(native_data_t * nat)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 
get_adapter_path(DBusConnection * conn)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 
register_agent(native_data_t * nat,const char * agent_path,const char * capabilities)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 
tearDownEventLoop(native_data_t * nat)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 
dbusAddWatch(DBusWatch * watch,void * data)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 
dbusRemoveWatch(DBusWatch * watch,void * data)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 
dbusToggleWatch(DBusWatch * watch,void * data)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 
handleWatchAdd(native_data_t * nat)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 
handleWatchRemove(native_data_t * nat)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 
eventLoopMain(void * ptr)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 
startEventLoopNative(JNIEnv * env,jobject object)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 
stopEventLoopNative(JNIEnv * env,jobject object)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 
isEventLoopRunningNative(JNIEnv * env,jobject object)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()
event_filter(DBusConnection * conn,DBusMessage * msg,void * data)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()
agent_event_filter(DBusConnection * conn,DBusMessage * msg,void * data)876 DBusHandlerResult agent_event_filter(DBusConnection *conn,
877                                      DBusMessage *msg, void *data) {
878     native_data_t *nat = (native_data_t *)data;
879     JNIEnv *env;
880     if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) {
881         LOGV("%s: not interested (not a method call).", __FUNCTION__);
882         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
883     }
884     LOGI("%s: Received method %s:%s", __FUNCTION__,
885          dbus_message_get_interface(msg), dbus_message_get_member(msg));
886 
887     if (nat == NULL) return DBUS_HANDLER_RESULT_HANDLED;
888 
889     nat->vm->GetEnv((void**)&env, nat->envVer);
890     env->PushLocalFrame(EVENT_LOOP_REFS);
891 
892     if (dbus_message_is_method_call(msg,
893             "org.bluez.Agent", "Cancel")) {
894         env->CallVoidMethod(nat->me, method_onAgentCancel);
895         // reply
896         DBusMessage *reply = dbus_message_new_method_return(msg);
897         if (!reply) {
898             LOGE("%s: Cannot create message reply\n", __FUNCTION__);
899             goto failure;
900         }
901         dbus_connection_send(nat->conn, reply, NULL);
902         dbus_message_unref(reply);
903         goto success;
904 
905     } else if (dbus_message_is_method_call(msg,
906             "org.bluez.Agent", "Authorize")) {
907         char *object_path;
908         const char *uuid;
909         if (!dbus_message_get_args(msg, NULL,
910                                    DBUS_TYPE_OBJECT_PATH, &object_path,
911                                    DBUS_TYPE_STRING, &uuid,
912                                    DBUS_TYPE_INVALID)) {
913             LOGE("%s: Invalid arguments for Authorize() method", __FUNCTION__);
914             goto failure;
915         }
916 
917         LOGV("... object_path = %s", object_path);
918         LOGV("... uuid = %s", uuid);
919 
920         dbus_message_ref(msg);  // increment refcount because we pass to java
921         env->CallBooleanMethod(nat->me, method_onAgentAuthorize,
922                 env->NewStringUTF(object_path), env->NewStringUTF(uuid),
923                 int(msg));
924 
925         goto success;
926     } else if (dbus_message_is_method_call(msg,
927             "org.bluez.Agent", "OutOfBandAvailable")) {
928         char *object_path;
929         if (!dbus_message_get_args(msg, NULL,
930                                    DBUS_TYPE_OBJECT_PATH, &object_path,
931                                    DBUS_TYPE_INVALID)) {
932             LOGE("%s: Invalid arguments for OutOfBandData available() method", __FUNCTION__);
933             goto failure;
934         }
935 
936         LOGV("... object_path = %s", object_path);
937 
938         bool available =
939             env->CallBooleanMethod(nat->me, method_onAgentOutOfBandDataAvailable,
940                 env->NewStringUTF(object_path));
941 
942 
943         // reply
944         if (available) {
945             DBusMessage *reply = dbus_message_new_method_return(msg);
946             if (!reply) {
947                 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
948                 goto failure;
949             }
950             dbus_connection_send(nat->conn, reply, NULL);
951             dbus_message_unref(reply);
952         } else {
953             DBusMessage *reply = dbus_message_new_error(msg,
954                     "org.bluez.Error.DoesNotExist", "OutofBand data not available");
955             if (!reply) {
956                 LOGE("%s: Cannot create message reply\n", __FUNCTION__);
957                 goto failure;
958             }
959             dbus_connection_send(nat->conn, reply, NULL);
960             dbus_message_unref(reply);
961         }
962         goto success;
963     } else if (dbus_message_is_method_call(msg,
964             "org.bluez.Agent", "RequestPinCode")) {
965         char *object_path;
966         if (!dbus_message_get_args(msg, NULL,
967                                    DBUS_TYPE_OBJECT_PATH, &object_path,
968                                    DBUS_TYPE_INVALID)) {
969             LOGE("%s: Invalid arguments for RequestPinCode() method", __FUNCTION__);
970             goto failure;
971         }
972 
973         dbus_message_ref(msg);  // increment refcount because we pass to java
974         env->CallVoidMethod(nat->me, method_onRequestPinCode,
975                                        env->NewStringUTF(object_path),
976                                        int(msg));
977         goto success;
978     } else if (dbus_message_is_method_call(msg,
979             "org.bluez.Agent", "RequestPasskey")) {
980         char *object_path;
981         if (!dbus_message_get_args(msg, NULL,
982                                    DBUS_TYPE_OBJECT_PATH, &object_path,
983                                    DBUS_TYPE_INVALID)) {
984             LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
985             goto failure;
986         }
987 
988         dbus_message_ref(msg);  // increment refcount because we pass to java
989         env->CallVoidMethod(nat->me, method_onRequestPasskey,
990                                        env->NewStringUTF(object_path),
991                                        int(msg));
992         goto success;
993     } else if (dbus_message_is_method_call(msg,
994             "org.bluez.Agent", "RequestOobData")) {
995         char *object_path;
996         if (!dbus_message_get_args(msg, NULL,
997                                    DBUS_TYPE_OBJECT_PATH, &object_path,
998                                    DBUS_TYPE_INVALID)) {
999             LOGE("%s: Invalid arguments for RequestOobData() method", __FUNCTION__);
1000             goto failure;
1001         }
1002 
1003         dbus_message_ref(msg);  // increment refcount because we pass to java
1004         env->CallVoidMethod(nat->me, method_onRequestOobData,
1005                                        env->NewStringUTF(object_path),
1006                                        int(msg));
1007         goto success;
1008     } else if (dbus_message_is_method_call(msg,
1009             "org.bluez.Agent", "DisplayPasskey")) {
1010         char *object_path;
1011         uint32_t passkey;
1012         if (!dbus_message_get_args(msg, NULL,
1013                                    DBUS_TYPE_OBJECT_PATH, &object_path,
1014                                    DBUS_TYPE_UINT32, &passkey,
1015                                    DBUS_TYPE_INVALID)) {
1016             LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
1017             goto failure;
1018         }
1019 
1020         dbus_message_ref(msg);  // increment refcount because we pass to java
1021         env->CallVoidMethod(nat->me, method_onDisplayPasskey,
1022                                        env->NewStringUTF(object_path),
1023                                        passkey,
1024                                        int(msg));
1025         goto success;
1026     } else if (dbus_message_is_method_call(msg,
1027             "org.bluez.Agent", "RequestConfirmation")) {
1028         char *object_path;
1029         uint32_t passkey;
1030         if (!dbus_message_get_args(msg, NULL,
1031                                    DBUS_TYPE_OBJECT_PATH, &object_path,
1032                                    DBUS_TYPE_UINT32, &passkey,
1033                                    DBUS_TYPE_INVALID)) {
1034             LOGE("%s: Invalid arguments for RequestConfirmation() method", __FUNCTION__);
1035             goto failure;
1036         }
1037 
1038         dbus_message_ref(msg);  // increment refcount because we pass to java
1039         env->CallVoidMethod(nat->me, method_onRequestPasskeyConfirmation,
1040                                        env->NewStringUTF(object_path),
1041                                        passkey,
1042                                        int(msg));
1043         goto success;
1044     } else if (dbus_message_is_method_call(msg,
1045             "org.bluez.Agent", "RequestPairingConsent")) {
1046         char *object_path;
1047         if (!dbus_message_get_args(msg, NULL,
1048                                    DBUS_TYPE_OBJECT_PATH, &object_path,
1049                                    DBUS_TYPE_INVALID)) {
1050             LOGE("%s: Invalid arguments for RequestPairingConsent() method", __FUNCTION__);
1051             goto failure;
1052         }
1053 
1054         dbus_message_ref(msg);  // increment refcount because we pass to java
1055         env->CallVoidMethod(nat->me, method_onRequestPairingConsent,
1056                                        env->NewStringUTF(object_path),
1057                                        int(msg));
1058         goto success;
1059     } else if (dbus_message_is_method_call(msg,
1060                   "org.bluez.Agent", "Release")) {
1061         // reply
1062         DBusMessage *reply = dbus_message_new_method_return(msg);
1063         if (!reply) {
1064             LOGE("%s: Cannot create message reply\n", __FUNCTION__);
1065             goto failure;
1066         }
1067         dbus_connection_send(nat->conn, reply, NULL);
1068         dbus_message_unref(reply);
1069         goto success;
1070     } else {
1071         LOGV("%s:%s is ignored", dbus_message_get_interface(msg), dbus_message_get_member(msg));
1072     }
1073 
1074 failure:
1075     env->PopLocalFrame(NULL);
1076     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1077 
1078 success:
1079     env->PopLocalFrame(NULL);
1080     return DBUS_HANDLER_RESULT_HANDLED;
1081 
1082 }
1083 #endif
1084 
1085 
1086 #ifdef HAVE_BLUETOOTH
1087 //TODO: Unify result codes in a header
1088 #define BOND_RESULT_ERROR -1000
1089 #define BOND_RESULT_SUCCESS 0
1090 #define BOND_RESULT_AUTH_FAILED 1
1091 #define BOND_RESULT_AUTH_REJECTED 2
1092 #define BOND_RESULT_AUTH_CANCELED 3
1093 #define BOND_RESULT_REMOTE_DEVICE_DOWN 4
1094 #define BOND_RESULT_DISCOVERY_IN_PROGRESS 5
1095 #define BOND_RESULT_AUTH_TIMEOUT 6
1096 #define BOND_RESULT_REPEATED_ATTEMPTS 7
1097 
onCreatePairedDeviceResult(DBusMessage * msg,void * user,void * n)1098 void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) {
1099     LOGV(__FUNCTION__);
1100 
1101     native_data_t *nat = (native_data_t *)n;
1102     const char *address = (const char *)user;
1103     DBusError err;
1104     dbus_error_init(&err);
1105     JNIEnv *env;
1106     jstring addr;
1107 
1108     nat->vm->GetEnv((void**)&env, nat->envVer);
1109 
1110     LOGV("... address = %s", address);
1111 
1112     jint result = BOND_RESULT_SUCCESS;
1113     if (dbus_set_error_from_message(&err, msg)) {
1114         if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) {
1115             // Pins did not match, or remote device did not respond to pin
1116             // request in time
1117             LOGV("... error = %s (%s)\n", err.name, err.message);
1118             result = BOND_RESULT_AUTH_FAILED;
1119         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationRejected")) {
1120             // We rejected pairing, or the remote side rejected pairing. This
1121             // happens if either side presses 'cancel' at the pairing dialog.
1122             LOGV("... error = %s (%s)\n", err.name, err.message);
1123             result = BOND_RESULT_AUTH_REJECTED;
1124         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationCanceled")) {
1125             // Not sure if this happens
1126             LOGV("... error = %s (%s)\n", err.name, err.message);
1127             result = BOND_RESULT_AUTH_CANCELED;
1128         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.ConnectionAttemptFailed")) {
1129             // Other device is not responding at all
1130             LOGV("... error = %s (%s)\n", err.name, err.message);
1131             result = BOND_RESULT_REMOTE_DEVICE_DOWN;
1132         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AlreadyExists")) {
1133             // already bonded
1134             LOGV("... error = %s (%s)\n", err.name, err.message);
1135             result = BOND_RESULT_SUCCESS;
1136         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") &&
1137                    !strcmp(err.message, "Bonding in progress")) {
1138             LOGV("... error = %s (%s)\n", err.name, err.message);
1139             goto done;
1140         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") &&
1141                    !strcmp(err.message, "Discover in progress")) {
1142             LOGV("... error = %s (%s)\n", err.name, err.message);
1143             result = BOND_RESULT_DISCOVERY_IN_PROGRESS;
1144         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.RepeatedAttempts")) {
1145             LOGV("... error = %s (%s)\n", err.name, err.message);
1146             result = BOND_RESULT_REPEATED_ATTEMPTS;
1147         } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationTimeout")) {
1148             LOGV("... error = %s (%s)\n", err.name, err.message);
1149             result = BOND_RESULT_AUTH_TIMEOUT;
1150         } else {
1151             LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
1152             result = BOND_RESULT_ERROR;
1153         }
1154     }
1155 
1156     addr = env->NewStringUTF(address);
1157     env->CallVoidMethod(nat->me,
1158                         method_onCreatePairedDeviceResult,
1159                         addr,
1160                         result);
1161     env->DeleteLocalRef(addr);
1162 done:
1163     dbus_error_free(&err);
1164     free(user);
1165 }
1166 
onCreateDeviceResult(DBusMessage * msg,void * user,void * n)1167 void onCreateDeviceResult(DBusMessage *msg, void *user, void *n) {
1168     LOGV(__FUNCTION__);
1169 
1170     native_data_t *nat = (native_data_t *)n;
1171     const char *address= (const char *)user;
1172     DBusError err;
1173     dbus_error_init(&err);
1174     JNIEnv *env;
1175     nat->vm->GetEnv((void**)&env, nat->envVer);
1176 
1177     LOGV("... Address = %s", address);
1178 
1179     jint result = CREATE_DEVICE_SUCCESS;
1180     if (dbus_set_error_from_message(&err, msg)) {
1181         if (dbus_error_has_name(&err, "org.bluez.Error.AlreadyExists")) {
1182             result = CREATE_DEVICE_ALREADY_EXISTS;
1183         } else {
1184             result = CREATE_DEVICE_FAILED;
1185         }
1186         LOG_AND_FREE_DBUS_ERROR(&err);
1187     }
1188     jstring addr = env->NewStringUTF(address);
1189     env->CallVoidMethod(nat->me,
1190                         method_onCreateDeviceResult,
1191                         addr,
1192                         result);
1193     env->DeleteLocalRef(addr);
1194     free(user);
1195 }
1196 
onDiscoverServicesResult(DBusMessage * msg,void * user,void * n)1197 void onDiscoverServicesResult(DBusMessage *msg, void *user, void *n) {
1198     LOGV(__FUNCTION__);
1199 
1200     native_data_t *nat = (native_data_t *)n;
1201     const char *path = (const char *)user;
1202     DBusError err;
1203     dbus_error_init(&err);
1204     JNIEnv *env;
1205     nat->vm->GetEnv((void**)&env, nat->envVer);
1206 
1207     LOGV("... Device Path = %s", path);
1208 
1209     bool result = JNI_TRUE;
1210     if (dbus_set_error_from_message(&err, msg)) {
1211         LOG_AND_FREE_DBUS_ERROR(&err);
1212         result = JNI_FALSE;
1213     }
1214     jstring jPath = env->NewStringUTF(path);
1215     env->CallVoidMethod(nat->me,
1216                         method_onDiscoverServicesResult,
1217                         jPath,
1218                         result);
1219     env->DeleteLocalRef(jPath);
1220     free(user);
1221 }
1222 
onGetDeviceServiceChannelResult(DBusMessage * msg,void * user,void * n)1223 void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) {
1224     LOGV(__FUNCTION__);
1225 
1226     const char *address = (const char *) user;
1227     native_data_t *nat = (native_data_t *) n;
1228 
1229     DBusError err;
1230     dbus_error_init(&err);
1231     JNIEnv *env;
1232     nat->vm->GetEnv((void**)&env, nat->envVer);
1233 
1234     jint channel = -2;
1235 
1236     LOGV("... address = %s", address);
1237 
1238     if (dbus_set_error_from_message(&err, msg) ||
1239         !dbus_message_get_args(msg, &err,
1240                                DBUS_TYPE_INT32, &channel,
1241                                DBUS_TYPE_INVALID)) {
1242         LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
1243         dbus_error_free(&err);
1244     }
1245 
1246 done:
1247     jstring addr = env->NewStringUTF(address);
1248     env->CallVoidMethod(nat->me,
1249                         method_onGetDeviceServiceChannelResult,
1250                         addr,
1251                         channel);
1252     env->DeleteLocalRef(addr);
1253     free(user);
1254 }
1255 #endif
1256 
1257 static JNINativeMethod sMethods[] = {
1258      /* name, signature, funcPtr */
1259     {"classInitNative", "()V", (void *)classInitNative},
1260     {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
1261     {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
1262     {"startEventLoopNative", "()V", (void *)startEventLoopNative},
1263     {"stopEventLoopNative", "()V", (void *)stopEventLoopNative},
1264     {"isEventLoopRunningNative", "()Z", (void *)isEventLoopRunningNative}
1265 };
1266 
register_android_server_BluetoothEventLoop(JNIEnv * env)1267 int register_android_server_BluetoothEventLoop(JNIEnv *env) {
1268     return AndroidRuntime::registerNativeMethods(env,
1269             "android/server/BluetoothEventLoop", sMethods, NELEM(sMethods));
1270 }
1271 
1272 } /* namespace android */
1273