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