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