diff options
author | Robert Greenwalt <> | 2009-04-02 09:53:35 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-04-02 09:53:35 -0700 |
commit | d30b2568cd309053e0e7a0ac7a433d8dafcd3e28 (patch) | |
tree | 4f3111c9305cb2825128ab89d3c835463a62347c | |
parent | 570d05f776106a715d00099c8bd5e716be1f4aa3 (diff) | |
download | frameworks_base-d30b2568cd309053e0e7a0ac7a433d8dafcd3e28.zip frameworks_base-d30b2568cd309053e0e7a0ac7a433d8dafcd3e28.tar.gz frameworks_base-d30b2568cd309053e0e7a0ac7a433d8dafcd3e28.tar.bz2 |
AI 144241: Stop polling dbus.
BUG=1244263
Automated import of CL 144241
-rw-r--r-- | core/java/android/server/BluetoothEventLoop.java | 56 | ||||
-rw-r--r-- | core/jni/android_bluetooth_common.cpp | 18 | ||||
-rw-r--r-- | core/jni/android_bluetooth_common.h | 41 | ||||
-rw-r--r-- | core/jni/android_server_BluetoothA2dpService.cpp | 19 | ||||
-rw-r--r-- | core/jni/android_server_BluetoothDeviceService.cpp | 24 | ||||
-rw-r--r-- | core/jni/android_server_BluetoothEventLoop.cpp | 393 |
6 files changed, 420 insertions, 131 deletions
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index 11c297c..8cc229b 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -111,57 +111,27 @@ class BluetoothEventLoop { return mPasskeyAgentRequestData; } - private synchronized boolean waitForAndDispatchEvent(int timeout_ms) { - return waitForAndDispatchEventNative(timeout_ms); - } - private native boolean waitForAndDispatchEventNative(int timeout_ms); + private native void startEventLoopNative(); + private native void stopEventLoopNative(); + private native boolean isEventLoopRunningNative(); - /* package */ synchronized void start() { + /* package */ void start() { - if (mThread != null) { - // Already running. - return; + if (!isEventLoopRunningNative()) { + if (DBG) log("Starting Event Loop thread"); + startEventLoopNative(); } - mThread = new Thread("Bluetooth Event Loop") { - @Override - public void run() { - try { - if (setUpEventLoopNative()) { - mStarted = true; - while (!mInterrupted) { - waitForAndDispatchEvent(0); - sleep(500); - } - } - // tear down even in the error case to clean - // up anything we started to setup - tearDownEventLoopNative(); - } catch (InterruptedException e) { } - if (DBG) log("Event Loop thread finished"); - mThread = null; - } - }; - if (DBG) log("Starting Event Loop thread"); - mInterrupted = false; - mThread.start(); } - private native boolean setUpEventLoopNative(); - private native void tearDownEventLoopNative(); - public synchronized void stop() { - if (mThread != null) { - mInterrupted = true; - try { - mThread.join(); - mThread = null; - } catch (InterruptedException e) { - Log.i(TAG, "Interrupted waiting for Event Loop thread to join"); - } + public void stop() { + if (isEventLoopRunningNative()) { + if (DBG) log("Stopping Event Loop thread"); + stopEventLoopNative(); } } - public synchronized boolean isEventLoopRunning() { - return mThread != null && mStarted; + public boolean isEventLoopRunning() { + return isEventLoopRunningNative(); } /*package*/ void onModeChanged(String bluezMode) { diff --git a/core/jni/android_bluetooth_common.cpp b/core/jni/android_bluetooth_common.cpp index c81af1ce..0b8a604 100644 --- a/core/jni/android_bluetooth_common.cpp +++ b/core/jni/android_bluetooth_common.cpp @@ -46,8 +46,9 @@ jfieldID get_field(JNIEnv *env, jclass clazz, const char *member, } typedef struct { - void (*user_cb)(DBusMessage *, void *); + void (*user_cb)(DBusMessage *, void *, void *); void *user; + void *nat; JNIEnv *env; } dbus_async_call_t; @@ -63,7 +64,7 @@ void dbus_func_args_async_callback(DBusPendingCall *call, void *data) { if (msg) { if (req->user_cb) { // The user may not deref the message object. - req->user_cb(msg, req->user); + req->user_cb(msg, req->user, req->nat); } dbus_message_unref(msg); } @@ -74,11 +75,14 @@ void dbus_func_args_async_callback(DBusPendingCall *call, void *data) { free(req); } -dbus_bool_t dbus_func_args_async_valist(JNIEnv *env, +static dbus_bool_t dbus_func_args_async_valist(JNIEnv *env, DBusConnection *conn, int timeout_ms, - void (*user_cb)(DBusMessage *, void *), + void (*user_cb)(DBusMessage *, + void *, + void*), void *user, + void *nat, const char *path, const char *ifc, const char *func, @@ -111,6 +115,7 @@ dbus_bool_t dbus_func_args_async_valist(JNIEnv *env, pending->env = env; pending->user_cb = user_cb; pending->user = user; + pending->nat = nat; //pending->method = msg; reply = dbus_connection_send_with_reply(conn, msg, @@ -132,8 +137,9 @@ done: dbus_bool_t dbus_func_args_async(JNIEnv *env, DBusConnection *conn, int timeout_ms, - void (*reply)(DBusMessage *, void *), + void (*reply)(DBusMessage *, void *, void*), void *user, + void *nat, const char *path, const char *ifc, const char *func, @@ -144,7 +150,7 @@ dbus_bool_t dbus_func_args_async(JNIEnv *env, va_start(lst, first_arg_type); ret = dbus_func_args_async_valist(env, conn, timeout_ms, - reply, user, + reply, user, nat, path, ifc, func, first_arg_type, lst); va_end(lst); diff --git a/core/jni/android_bluetooth_common.h b/core/jni/android_bluetooth_common.h index c30ba22..69092dd 100644 --- a/core/jni/android_bluetooth_common.h +++ b/core/jni/android_bluetooth_common.h @@ -24,7 +24,9 @@ #include "utils/Log.h" #include <errno.h> +#include <pthread.h> #include <stdint.h> +#include <sys/poll.h> #ifdef HAVE_BLUETOOTH #include <dbus/dbus.h> @@ -45,6 +47,9 @@ namespace android { #define BTADDR_SIZE 18 // size of BT address character array (including null) +// size of the dbus event loops pollfd structure, hopefully never to be grown +#define DEFAULT_INITIAL_POLLFD_COUNT 8 + jfieldID get_field(JNIEnv *env, jclass clazz, const char *member, @@ -63,29 +68,33 @@ jfieldID get_field(JNIEnv *env, struct event_loop_native_data_t { DBusConnection *conn; - /* These variables are set in waitForAndDispatchEventNative() and are - valid only within the scope of this function. At any other time, they - are NULL. */ + + /* protects the thread */ + pthread_mutex_t thread_mutex; + pthread_t thread; + /* our comms socket */ + /* mem for the list of sockets to listen to */ + struct pollfd *pollData; + int pollMemberCount; + int pollDataSize; + /* mem for matching set of dbus watch ptrs */ + DBusWatch **watchData; + /* pair of sockets for event loop control, Reader and Writer */ + int controlFdR; + int controlFdW; + /* our vm and env Version for future env generation */ + JavaVM *vm; + int envVer; + /* reference to our java self */ jobject me; - JNIEnv *env; }; -dbus_bool_t dbus_func_args_async_valist(JNIEnv *env, - DBusConnection *conn, - int timeout_ms, - void (*reply)(DBusMessage *, void *), - void *user, - const char *path, - const char *ifc, - const char *func, - int first_arg_type, - va_list args); - dbus_bool_t dbus_func_args_async(JNIEnv *env, DBusConnection *conn, int timeout_ms, - void (*reply)(DBusMessage *, void *), + void (*reply)(DBusMessage *, void *, void *), void *user, + void *nat, const char *path, const char *ifc, const char *func, diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp index 062f893..b320c09 100644 --- a/core/jni/android_server_BluetoothA2dpService.cpp +++ b/core/jni/android_server_BluetoothA2dpService.cpp @@ -52,12 +52,11 @@ typedef struct { static native_data_t *nat = NULL; // global native data -extern event_loop_native_data_t *event_loop_nat; // for the event loop JNIEnv #endif #ifdef HAVE_BLUETOOTH -static void onConnectSinkResult(DBusMessage *msg, void *user); -static void onDisconnectSinkResult(DBusMessage *msg, void *user); +static void onConnectSinkResult(DBusMessage *msg, void *user, void *nat); +static void onDisconnectSinkResult(DBusMessage *msg, void *user, void *nat); #endif /* Returns true on success (even if adapter is present but disabled). @@ -175,7 +174,8 @@ static jboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) { bool ret = dbus_func_args_async(env, nat->conn, -1, - onConnectSinkResult, (void *)c_path_copy, c_path, + onConnectSinkResult, (void *)c_path_copy, nat, + c_path, "org.bluez.audio.Sink", "Connect", DBUS_TYPE_INVALID); @@ -202,7 +202,8 @@ static jboolean disconnectSinkNative(JNIEnv *env, jobject object, bool ret = dbus_func_args_async(env, nat->conn, -1, - onDisconnectSinkResult, (void *)c_path_copy, c_path, + onDisconnectSinkResult, (void *)c_path_copy, nat, + c_path, "org.bluez.audio.Sink", "Disconnect", DBUS_TYPE_INVALID); env->ReleaseStringUTFChars(path, c_path); @@ -233,13 +234,13 @@ static jboolean isSinkConnectedNative(JNIEnv *env, jobject object, jstring path) } #ifdef HAVE_BLUETOOTH -static void onConnectSinkResult(DBusMessage *msg, void *user) { +static void onConnectSinkResult(DBusMessage *msg, void *user, void *natData) { LOGV(__FUNCTION__); char *c_path = (char *)user; DBusError err; dbus_error_init(&err); - JNIEnv *env = event_loop_nat->env; + JNIEnv *env = nat->env; LOGV("... path = %s", c_path); if (dbus_set_error_from_message(&err, msg)) { @@ -258,13 +259,13 @@ static void onConnectSinkResult(DBusMessage *msg, void *user) { free(c_path); } -static void onDisconnectSinkResult(DBusMessage *msg, void *user) { +static void onDisconnectSinkResult(DBusMessage *msg, void *user, void *natData) { LOGV(__FUNCTION__); char *c_path = (char *)user; DBusError err; dbus_error_init(&err); - JNIEnv *env = event_loop_nat->env; + JNIEnv *env = nat->env; LOGV("... path = %s", c_path); if (dbus_set_error_from_message(&err, msg)) { diff --git a/core/jni/android_server_BluetoothDeviceService.cpp b/core/jni/android_server_BluetoothDeviceService.cpp index a0e0b84..b6e9798 100644 --- a/core/jni/android_server_BluetoothDeviceService.cpp +++ b/core/jni/android_server_BluetoothDeviceService.cpp @@ -50,6 +50,7 @@ namespace android { // We initialize these variables when we load class // android.server.BluetoothDeviceService static jfieldID field_mNativeData; +static jfieldID field_mEventLoop; typedef struct { JNIEnv *env; @@ -57,8 +58,10 @@ typedef struct { const char *adapter; // dbus object name of the local adapter } native_data_t; -void onCreateBondingResult(DBusMessage *msg, void *user); -void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user); +extern event_loop_native_data_t *get_EventLoop_native_data(JNIEnv *, + jobject); +void onCreateBondingResult(DBusMessage *msg, void *user, void *nat); +void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user, void *nat); /** Get native data stored in the opaque (Java code maintained) pointer mNativeData * Perform quick sanity check, if there are any problems return NULL @@ -78,6 +81,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) { LOGV(__FUNCTION__); #ifdef HAVE_BLUETOOTH field_mNativeData = get_field(env, clazz, "mNativeData", "I"); + field_mEventLoop = get_field(env, clazz, "mEventLoop", + "Landroid/server/BluetoothEventLoop;"); #endif } @@ -472,14 +477,19 @@ static jboolean createBondingNative(JNIEnv *env, jobject object, LOGV(__FUNCTION__); #ifdef HAVE_BLUETOOTH native_data_t *nat = get_native_data(env, object); - if (nat) { + jobject eventLoop = env->GetObjectField(object, field_mEventLoop); + struct event_loop_native_data_t *eventLoopNat = + get_EventLoop_native_data(env, eventLoop); + + if (nat && eventLoopNat) { const char *c_address = env->GetStringUTFChars(address, NULL); LOGV("... address = %s", c_address); char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char)); strlcpy(context_address, c_address, BTADDR_SIZE); // for callback bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms, onCreateBondingResult, // callback - context_address, // user data + context_address, + eventLoopNat, nat->adapter, DBUS_CLASS_NAME, "CreateBonding", DBUS_TYPE_STRING, &c_address, @@ -856,7 +866,10 @@ static jboolean getRemoteServiceChannelNative(JNIEnv *env, jobject object, #ifdef HAVE_BLUETOOTH LOGV(__FUNCTION__); native_data_t *nat = get_native_data(env, object); - if (nat) { + jobject eventLoop = env->GetObjectField(object, field_mEventLoop); + struct event_loop_native_data_t *eventLoopNat = + get_EventLoop_native_data(env, eventLoop); + if (nat && eventLoopNat) { const char *c_address = env->GetStringUTFChars(address, NULL); char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char)); strlcpy(context_address, c_address, BTADDR_SIZE); @@ -866,6 +879,7 @@ static jboolean getRemoteServiceChannelNative(JNIEnv *env, jobject object, bool ret = dbus_func_args_async(env, nat->conn, 20000, // ms onGetRemoteServiceChannelResult, context_address, + eventLoopNat, nat->adapter, DBUS_CLASS_NAME, "GetRemoteServiceChannel", DBUS_TYPE_STRING, &c_address, diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp index c03bab6..7c5da5b 100644 --- a/core/jni/android_server_BluetoothEventLoop.cpp +++ b/core/jni/android_server_BluetoothEventLoop.cpp @@ -18,6 +18,7 @@ #include "android_bluetooth_common.h" #include "android_runtime/AndroidRuntime.h" +#include "cutils/sockets.h" #include "JNIHelp.h" #include "jni.h" #include "utils/Log.h" @@ -65,14 +66,15 @@ static jmethodID method_onRestartRequired; typedef event_loop_native_data_t native_data_t; -// Only valid during waitForAndDispatchEventNative() -native_data_t *event_loop_nat; - static inline native_data_t * get_native_data(JNIEnv *env, jobject object) { return (native_data_t *)(env->GetIntField(object, field_mNativeData)); } +native_data_t *get_EventLoop_native_data(JNIEnv *env, jobject object) { + return get_native_data(env, object); +} + #endif static void classInitNative(JNIEnv* env, jclass clazz) { LOGV(__FUNCTION__); @@ -115,6 +117,10 @@ static void initializeNativeDataNative(JNIEnv* env, jobject object) { LOGE("%s: out of memory!", __FUNCTION__); return; } + memset(nat, 0, sizeof(native_data_t)); + + pthread_mutex_init(&(nat->thread_mutex), NULL); + env->SetIntField(object, field_mNativeData, (jint)nat); { @@ -135,6 +141,9 @@ static void cleanupNativeDataNative(JNIEnv* env, jobject object) { #ifdef HAVE_BLUETOOTH native_data_t *nat = (native_data_t *)env->GetIntField(object, field_mNativeData); + + pthread_mutex_destroy(&(nat->thread_mutex)); + if (nat) { free(nat); } @@ -151,13 +160,11 @@ static DBusHandlerResult agent_event_filter(DBusConnection *conn, static const DBusObjectPathVTable agent_vtable = { NULL, agent_event_filter, NULL, NULL, NULL, NULL }; -#endif -static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) { -#ifdef HAVE_BLUETOOTH + +static jboolean setUpEventLoop(native_data_t *nat) { LOGV(__FUNCTION__); dbus_threads_init_default(); - native_data_t *nat = get_native_data(env, object); DBusError err; dbus_error_init(&err); @@ -207,7 +214,7 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) { // Add an object handler for passkey agent method calls const char *path = "/android/bluetooth/Agent"; if (!dbus_connection_register_object_path(nat->conn, path, - &agent_vtable, NULL)) { + &agent_vtable, nat)) { LOGE("%s: Can't register object path %s for agent!", __FUNCTION__, path); return JNI_FALSE; @@ -217,7 +224,7 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) { // trying for 10 seconds. int attempt; for (attempt = 0; attempt < 1000; attempt++) { - DBusMessage *reply = dbus_func_args_error(env, nat->conn, &err, + DBusMessage *reply = dbus_func_args_error(NULL, nat->conn, &err, BLUEZ_DBUS_BASE_PATH, "org.bluez.Security", "RegisterDefaultPasskeyAgent", DBUS_TYPE_STRING, &path, @@ -245,7 +252,7 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) { } // Now register the Auth agent - DBusMessage *reply = dbus_func_args_error(env, nat->conn, &err, + DBusMessage *reply = dbus_func_args_error(NULL, nat->conn, &err, BLUEZ_DBUS_BASE_PATH, "org.bluez.Security", "RegisterDefaultAuthorizationAgent", DBUS_TYPE_STRING, &path, @@ -259,14 +266,11 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) { return JNI_TRUE; } -#endif return JNI_FALSE; } -static void tearDownEventLoopNative(JNIEnv *env, jobject object) { +static void tearDownEventLoop(native_data_t *nat) { LOGV(__FUNCTION__); -#ifdef HAVE_BLUETOOTH - native_data_t *nat = get_native_data(env, object); if (nat != NULL && nat->conn != NULL) { DBusError err; @@ -274,14 +278,14 @@ static void tearDownEventLoopNative(JNIEnv *env, jobject object) { const char *path = "/android/bluetooth/Agent"; DBusMessage *reply = - dbus_func_args(env, nat->conn, BLUEZ_DBUS_BASE_PATH, + dbus_func_args(NULL, nat->conn, BLUEZ_DBUS_BASE_PATH, "org.bluez.Security", "UnregisterDefaultPasskeyAgent", DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); if (reply) dbus_message_unref(reply); reply = - dbus_func_args(env, nat->conn, BLUEZ_DBUS_BASE_PATH, + dbus_func_args(NULL, nat->conn, BLUEZ_DBUS_BASE_PATH, "org.bluez.Security", "UnregisterDefaultAuthorizationAgent", DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); @@ -322,7 +326,308 @@ static void tearDownEventLoopNative(JNIEnv *env, jobject object) { dbus_connection_remove_filter(nat->conn, event_filter, nat); } -#endif +} + + +#define EVENT_LOOP_EXIT 1 +#define EVENT_LOOP_ADD 2 +#define EVENT_LOOP_REMOVE 3 + +dbus_bool_t dbusAddWatch(DBusWatch *watch, void *data) { + native_data_t *nat = (native_data_t *)data; + + if (dbus_watch_get_enabled(watch)) { + // note that we can't just send the watch and inspect it later + // because we may get a removeWatch call before this data is reacted + // to by our eventloop and remove this watch.. reading the add first + // and then inspecting the recently deceased watch would be bad. + char control = EVENT_LOOP_ADD; + write(nat->controlFdW, &control, sizeof(char)); + + int fd = dbus_watch_get_fd(watch); + write(nat->controlFdW, &fd, sizeof(int)); + + unsigned int flags = dbus_watch_get_flags(watch); + write(nat->controlFdW, &flags, sizeof(unsigned int)); + + write(nat->controlFdW, &watch, sizeof(DBusWatch*)); + } + return true; +} + +void dbusRemoveWatch(DBusWatch *watch, void *data) { + native_data_t *nat = (native_data_t *)data; + + char control = EVENT_LOOP_REMOVE; + write(nat->controlFdW, &control, sizeof(char)); + + int fd = dbus_watch_get_fd(watch); + write(nat->controlFdW, &fd, sizeof(int)); + + unsigned int flags = dbus_watch_get_flags(watch); + write(nat->controlFdW, &flags, sizeof(unsigned int)); +} + +void dbusToggleWatch(DBusWatch *watch, void *data) { + if (dbus_watch_get_enabled(watch)) { + dbusAddWatch(watch, data); + } else { + dbusRemoveWatch(watch, data); + } +} + +static void handleWatchAdd(native_data_t *nat) { + DBusWatch *watch; + int newFD; + unsigned int flags; + + read(nat->controlFdR, &newFD, sizeof(int)); + read(nat->controlFdR, &flags, sizeof(unsigned int)); + read(nat->controlFdR, &watch, sizeof(DBusWatch *)); + int events = (flags & DBUS_WATCH_READABLE ? POLLIN : 0) + | (flags & DBUS_WATCH_WRITABLE ? POLLOUT : 0); + + for (int y = 0; y<nat->pollMemberCount; y++) { + if ((nat->pollData[y].fd == newFD) && + (nat->pollData[y].events == events)) { + LOGV("DBusWatch duplicate add"); + return; + } + } + if (nat->pollMemberCount == nat->pollDataSize) { + LOGV("Bluetooth EventLoop poll struct growing"); + struct pollfd *temp = (struct pollfd *)malloc( + sizeof(struct pollfd) * (nat->pollMemberCount+1)); + if (!temp) { + return; + } + memcpy(temp, nat->pollData, sizeof(struct pollfd) * + nat->pollMemberCount); + free(nat->pollData); + nat->pollData = temp; + DBusWatch **temp2 = (DBusWatch **)malloc(sizeof(DBusWatch *) * + (nat->pollMemberCount+1)); + if (!temp2) { + return; + } + memcpy(temp2, nat->watchData, sizeof(DBusWatch *) * + nat->pollMemberCount); + free(nat->watchData); + nat->watchData = temp2; + nat->pollDataSize++; + } + nat->pollData[nat->pollMemberCount].fd = newFD; + nat->pollData[nat->pollMemberCount].revents = 0; + nat->pollData[nat->pollMemberCount].events = events; + nat->watchData[nat->pollMemberCount] = watch; + nat->pollMemberCount++; +} + +static void handleWatchRemove(native_data_t *nat) { + int removeFD; + unsigned int flags; + + read(nat->controlFdR, &removeFD, sizeof(int)); + read(nat->controlFdR, &flags, sizeof(unsigned int)); + int events = (flags & DBUS_WATCH_READABLE ? POLLIN : 0) + | (flags & DBUS_WATCH_WRITABLE ? POLLOUT : 0); + + for (int y = 0; y < nat->pollMemberCount; y++) { + if ((nat->pollData[y].fd == removeFD) && + (nat->pollData[y].events == events)) { + int newCount = --nat->pollMemberCount; + // copy the last live member over this one + nat->pollData[y].fd = nat->pollData[newCount].fd; + nat->pollData[y].events = nat->pollData[newCount].events; + nat->pollData[y].revents = nat->pollData[newCount].revents; + nat->watchData[y] = nat->watchData[newCount]; + return; + } + } + LOGW("WatchRemove given with unknown watch"); +} + +static void *eventLoopMain(void *ptr) { + native_data_t *nat = (native_data_t *)ptr; + JNIEnv *env; + + JavaVMAttachArgs args; + char name[] = "BT EventLoop"; + args.version = nat->envVer; + args.name = name; + args.group = NULL; + + nat->vm->AttachCurrentThread(&env, &args); + + dbus_connection_set_watch_functions(nat->conn, dbusAddWatch, + dbusRemoveWatch, dbusToggleWatch, ptr, NULL); + + while (1) { + for (int i = 0; i < nat->pollMemberCount; i++) { + if (!nat->pollData[i].revents) { + continue; + } + if (nat->pollData[i].fd == nat->controlFdR) { + char data; + while (recv(nat->controlFdR, &data, sizeof(char), MSG_DONTWAIT) + != -1) { + switch (data) { + case EVENT_LOOP_EXIT: + { + dbus_connection_set_watch_functions(nat->conn, + NULL, NULL, NULL, NULL, NULL); + tearDownEventLoop(nat); + nat->vm->DetachCurrentThread(); + shutdown(nat->controlFdR,SHUT_RDWR); + return NULL; + } + case EVENT_LOOP_ADD: + { + handleWatchAdd(nat); + break; + } + case EVENT_LOOP_REMOVE: + { + handleWatchRemove(nat); + break; + } + } + } + } else { + int event = nat->pollData[i].revents; + int flags = (event & POLLIN ? DBUS_WATCH_READABLE : 0) | + (event & POLLOUT ? DBUS_WATCH_WRITABLE : 0); + dbus_watch_handle(nat->watchData[i], event); + nat->pollData[i].revents = 0; + // can only do one - it may have caused a 'remove' + break; + } + } + while (dbus_connection_dispatch(nat->conn) == + DBUS_DISPATCH_DATA_REMAINS) { + } + + poll(nat->pollData, nat->pollMemberCount, -1); + } +} +#endif // HAVE_BLUETOOTH + +static jboolean startEventLoopNative(JNIEnv *env, jobject object) { + jboolean result = JNI_FALSE; +#ifdef HAVE_BLUETOOTH + event_loop_native_data_t *nat = get_native_data(env, object); + + pthread_mutex_lock(&(nat->thread_mutex)); + + if (nat->pollData) { + LOGW("trying to start EventLoop a second time!"); + pthread_mutex_unlock( &(nat->thread_mutex) ); + return JNI_FALSE; + } + + nat->pollData = (struct pollfd *)malloc(sizeof(struct pollfd) * + DEFAULT_INITIAL_POLLFD_COUNT); + if (!nat->pollData) { + LOGE("out of memory error starting EventLoop!"); + goto done; + } + + nat->watchData = (DBusWatch **)malloc(sizeof(DBusWatch *) * + DEFAULT_INITIAL_POLLFD_COUNT); + if (!nat->watchData) { + LOGE("out of memory error starting EventLoop!"); + goto done; + } + + memset(nat->pollData, 0, sizeof(struct pollfd) * + DEFAULT_INITIAL_POLLFD_COUNT); + memset(nat->watchData, 0, sizeof(DBusWatch *) * + DEFAULT_INITIAL_POLLFD_COUNT); + nat->pollDataSize = DEFAULT_INITIAL_POLLFD_COUNT; + nat->pollMemberCount = 1; + + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, &(nat->controlFdR))) { + LOGE("Error getting BT control socket"); + goto done; + } + nat->pollData[0].fd = nat->controlFdR; + nat->pollData[0].events = POLLIN; + + env->GetJavaVM( &(nat->vm) ); + nat->envVer = env->GetVersion(); + + nat->me = env->NewGlobalRef(object); + + if (setUpEventLoop(nat) != JNI_TRUE) { + LOGE("failure setting up Event Loop!"); + goto done; + } + + pthread_create(&(nat->thread), NULL, eventLoopMain, nat); + result = JNI_TRUE; + +done: + if (JNI_FALSE == result) { + if (nat->controlFdW || nat->controlFdR) { + shutdown(nat->controlFdW, SHUT_RDWR); + nat->controlFdW = 0; + nat->controlFdR = 0; + } + if (nat->me) env->DeleteGlobalRef(nat->me); + nat->me = NULL; + if (nat->pollData) free(nat->pollData); + nat->pollData = NULL; + if (nat->watchData) free(nat->watchData); + nat->watchData = NULL; + nat->pollDataSize = 0; + nat->pollMemberCount = 0; + } + + pthread_mutex_unlock(&(nat->thread_mutex)); +#endif // HAVE_BLUETOOTH + return result; +} + +static void stopEventLoopNative(JNIEnv *env, jobject object) { +#ifdef HAVE_BLUETOOTH + native_data_t *nat = get_native_data(env, object); + + pthread_mutex_lock(&(nat->thread_mutex)); + if (nat->pollData) { + char data = EVENT_LOOP_EXIT; + ssize_t t = write(nat->controlFdW, &data, sizeof(char)); + void *ret; + pthread_join(nat->thread, &ret); + + env->DeleteGlobalRef(nat->me); + nat->me = NULL; + free(nat->pollData); + nat->pollData = NULL; + free(nat->watchData); + nat->watchData = NULL; + nat->pollDataSize = 0; + nat->pollMemberCount = 0; + shutdown(nat->controlFdW, SHUT_RDWR); + nat->controlFdW = 0; + nat->controlFdR = 0; + } + pthread_mutex_unlock(&(nat->thread_mutex)); +#endif // HAVE_BLUETOOTH +} + +static jboolean isEventLoopRunningNative(JNIEnv *env, jobject object) { + jboolean result = JNI_FALSE; +#ifdef HAVE_BLUETOOTH + native_data_t *nat = get_native_data(env, object); + + pthread_mutex_lock(&(nat->thread_mutex)); + if (nat->pollData) { + result = JNI_TRUE; + } + pthread_mutex_unlock(&(nat->thread_mutex)); + +#endif // HAVE_BLUETOOTH + return result; } #ifdef HAVE_BLUETOOTH @@ -338,7 +643,7 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, dbus_error_init(&err); nat = (native_data_t *)data; - env = nat->env; + nat->vm->GetEnv((void**)&env, nat->envVer); if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) { LOGV("%s: not interested (not a signal).", __FUNCTION__); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -556,11 +861,9 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg, // Called by dbus during WaitForAndDispatchEventNative() static DBusHandlerResult agent_event_filter(DBusConnection *conn, DBusMessage *msg, void *data) { - native_data_t *nat = event_loop_nat; + native_data_t *nat = (native_data_t *)data; JNIEnv *env; - - - env = nat->env; + nat->vm->GetEnv((void**)&env, nat->envVer); if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) { LOGV("%s: not interested (not a method call).", __FUNCTION__); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -730,27 +1033,6 @@ static DBusHandlerResult agent_event_filter(DBusConnection *conn, } #endif -static jboolean waitForAndDispatchEventNative(JNIEnv *env, jobject object, - jint timeout_ms) { -#ifdef HAVE_BLUETOOTH - //LOGV("%s: %8d (pid %d tid %d)",__FUNCTION__, time(NULL), getpid(), gettid()); // too chatty - native_data_t *nat = get_native_data(env, object); - if (nat != NULL && nat->conn != NULL) { - jboolean ret; - nat->me = object; - nat->env = env; - event_loop_nat = nat; - ret = dbus_connection_read_write_dispatch_greedy(nat->conn, - timeout_ms) == TRUE ? - JNI_TRUE : JNI_FALSE; - event_loop_nat = NULL; - nat->me = NULL; - nat->env = NULL; - return ret; - } -#endif - return JNI_FALSE; -} #ifdef HAVE_BLUETOOTH //TODO: Unify result codes in a header @@ -761,13 +1043,16 @@ static jboolean waitForAndDispatchEventNative(JNIEnv *env, jobject object, #define BOND_RESULT_AUTH_CANCELED 3 #define BOND_RESULT_REMOTE_DEVICE_DOWN 4 #define BOND_RESULT_DISCOVERY_IN_PROGRESS 5 -void onCreateBondingResult(DBusMessage *msg, void *user) { + +void onCreateBondingResult(DBusMessage *msg, void *user, void *n) { LOGV(__FUNCTION__); + native_data_t *nat = (native_data_t *)n; const char *address = (const char *)user; DBusError err; dbus_error_init(&err); - JNIEnv *env = event_loop_nat->env; + JNIEnv *env; + nat->vm->GetEnv((void**)&env, nat->envVer); LOGV("... address = %s", address); @@ -809,7 +1094,7 @@ void onCreateBondingResult(DBusMessage *msg, void *user) { } } - env->CallVoidMethod(event_loop_nat->me, + env->CallVoidMethod(nat->me, method_onCreateBondingResult, env->NewStringUTF(address), result); @@ -818,13 +1103,17 @@ done: free(user); } -void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user) { +void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user, void *n) { LOGV(__FUNCTION__); const char *address = (const char *) user; + native_data_t *nat = (native_data_t *) n; + DBusError err; dbus_error_init(&err); - JNIEnv *env = event_loop_nat->env; + JNIEnv *env; + nat->vm->GetEnv((void**)&env, nat->envVer); + jint channel = -2; LOGV("... address = %s", address); @@ -839,7 +1128,7 @@ void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user) { } done: - env->CallVoidMethod(event_loop_nat->me, + env->CallVoidMethod(nat->me, method_onGetRemoteServiceChannelResult, env->NewStringUTF(address), channel); @@ -852,9 +1141,9 @@ static JNINativeMethod sMethods[] = { {"classInitNative", "()V", (void *)classInitNative}, {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative}, {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative}, - {"setUpEventLoopNative", "()Z", (void *)setUpEventLoopNative}, - {"tearDownEventLoopNative", "()V", (void *)tearDownEventLoopNative}, - {"waitForAndDispatchEventNative", "(I)Z", (void *)waitForAndDispatchEventNative} + {"startEventLoopNative", "()V", (void *)startEventLoopNative}, + {"stopEventLoopNative", "()V", (void *)stopEventLoopNative}, + {"isEventLoopRunningNative", "()Z", (void *)isEventLoopRunningNative} }; int register_android_server_BluetoothEventLoop(JNIEnv *env) { |