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