summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorRobert Greenwalt <>2009-04-02 22:41:08 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2009-04-02 22:41:08 -0700
commit28d139fa953c0b3bf2c66d92587e5287ec4dd5ab (patch)
tree86a1b99f94c796e770240d585324205389314f11 /core
parent460ae0c910e46f6aeb48316f8745be810f68b5a4 (diff)
downloadframeworks_base-28d139fa953c0b3bf2c66d92587e5287ec4dd5ab.zip
frameworks_base-28d139fa953c0b3bf2c66d92587e5287ec4dd5ab.tar.gz
frameworks_base-28d139fa953c0b3bf2c66d92587e5287ec4dd5ab.tar.bz2
AI 144392: am: CL 144241 Stop polling dbus.
Original author: rgreenwalt Automated import of CL 144392
Diffstat (limited to 'core')
-rw-r--r--core/java/android/server/BluetoothEventLoop.java56
-rw-r--r--core/jni/android_bluetooth_common.cpp18
-rw-r--r--core/jni/android_bluetooth_common.h41
-rw-r--r--core/jni/android_server_BluetoothA2dpService.cpp19
-rw-r--r--core/jni/android_server_BluetoothDeviceService.cpp24
-rw-r--r--core/jni/android_server_BluetoothEventLoop.cpp393
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) {