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