AI 144392: am: CL 144241 Stop polling dbus.
Original author: rgreenwalt Automated import of CL 144392
This commit is contained in:
committed by
The Android Open Source Project
parent
460ae0c910
commit
28d139fa95
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user