AI 144392: am: CL 144241 Stop polling dbus.

Original author: rgreenwalt

Automated import of CL 144392
This commit is contained in:
Robert Greenwalt
2009-04-02 22:41:08 -07:00
committed by The Android Open Source Project
parent 460ae0c910
commit 28d139fa95
6 changed files with 424 additions and 135 deletions

View File

@@ -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;
}
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");
}
if (!isEventLoopRunningNative()) {
if (DBG) log("Starting Event Loop thread");
startEventLoopNative();
}
}
public synchronized boolean isEventLoopRunning() {
return mThread != null && mStarted;
public void stop() {
if (isEventLoopRunningNative()) {
if (DBG) log("Stopping Event Loop thread");
stopEventLoopNative();
}
}
public boolean isEventLoopRunning() {
return isEventLoopRunningNative();
}
/*package*/ void onModeChanged(String bluezMode) {

View File

@@ -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);

View File

@@ -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. */
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);
/* 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;
};
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,

View File

@@ -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)) {

View File

@@ -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,

View File

@@ -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) {