3 eventloop在jni层的详细分析
Eventloop在整个bluetooth的jni层和bluez之间的交互,以及jni和framework层之间的交互过程中有着举足轻重的作用。所以,本文仍然需要花费一定的笔墨来分析它,当然由于它更像是一个桥梁,我们的分析有可能就不是那么的深入了,会从比较宏观地角度来看待这个东西的作用。
当然,一切的一切还是要从源码来说:
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));
//这个是用来判断eventloop是否启动的
nat->running = false;
if (nat->pollData) {
LOGW("trying to start EventLoop a second time!");
pthread_mutex_unlock( &(nat->thread_mutex) );
return JNI_FALSE;
}
//申请pollfa
nat->pollData = (struct pollfd *)malloc(sizeof(struct pollfd) *
DEFAULT_INITIAL_POLLFD_COUNT);
if (!nat->pollData) {
LOGE("out of memory error starting EventLoop!");
goto done;
}
//申请dbus的watch data
nat->watchData = (DBusWatch **)malloc(sizeof(DBusWatch *) *
DEFAULT_INITIAL_POLLFD_COUNT);
if (!nat->watchData) {
LOGE("out of memory error starting EventLoop!");
goto done;
}
//初始化为0
memset(nat->pollData, 0, sizeof(struct pollfd) *
DEFAULT_INITIAL_POLLFD_COUNT);
memset(nat->watchData, 0, sizeof(DBusWatch *) *
DEFAULT_INITIAL_POLLFD_COUNT);
//datasize和member count的初始化
nat->pollDataSize = DEFAULT_INITIAL_POLLFD_COUNT;
nat->pollMemberCount = 1;
//申请socket 对,保存到controlFdR
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, &(nat->controlFdR))) {
LOGE("Error getting BT control socket");
goto done;
}
//data 0是其中一个,可以猜到了是通过socket在内部通信的
nat->pollData[0].fd = nat->controlFdR;
nat->pollData[0].events = POLLIN;
env->GetJavaVM( &(nat->vm) );
nat->envVer = env->GetVersion();
nat->me = env->NewGlobalRef(object);
//建立eventloop,详细分析见3.1
if (setUpEventLoop(nat) != JNI_TRUE) {
LOGE("failure setting up Event Loop!");
goto done;
}
//建立eventloopmain的thread,他肯定就是在不停地运行了,详细分析见3.2
pthread_create(&(nat->thread), NULL, eventLoopMain, nat);
result = JNI_TRUE;
done:
if (JNI_FALSE == result) {
if (nat->controlFdW) {
close(nat->controlFdW);
nat->controlFdW = 0;
}
if (nat->controlFdR) {
close(nat->controlFdR);
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;
}
3.1 eventloop的建立
static jboolean setUpEventLoop(native_data_t *nat) {
LOGV("%s", __FUNCTION__);
if (nat != NULL && nat->conn != NULL) {
dbus_threads_init_default();
DBusError err;
dbus_error_init(&err);
const char *agent_path = "/android/bluetooth/agent";
const char *capabilities = "DisplayYesNo";
//主要就是调用bluez的registeragent函数,见3.1.1
if (register_agent(nat, agent_path, capabilities) < 0) {
dbus_connection_unregister_object_path (nat->conn, agent_path);
return JNI_FALSE;
}
//这里是加入一个对event的过滤,所以我们上文中的propertychang之类的都是在这里面处理的,我们在后面对对应的event分析处理的时候再分析
// Add a filter for all incoming messages
if (!dbus_connection_add_filter(nat->conn, event_filter, nat, NULL)){
return JNI_FALSE;
}
//下面就是我们会watch这些interface。
// Set which messages will be processed by this dbus connection
dbus_bus_add_match(nat->conn,
"type='signal',interface='org.freedesktop.DBus'",
&err);
if (dbus_error_is_set(&err)) {
LOG_AND_FREE_DBUS_ERROR(&err);
return JNI_FALSE;
……
}
3.1.1
注册agent
这个又回到了bluez,在adapter.c中
static DBusMessage *register_agent(DBusConnection *conn, DBusMessage *msg,
void *data)
{
const char *path, *name, *capability;
struct agent *agent;
struct btd_adapter *adapter = data;
uint8_t cap;
//得到capability的值
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_STRING, &capability, DBUS_TYPE_INVALID))
return NULL;
//看是否有了agent
if (adapter->agent)
return btd_error_already_exists(msg);
//解析capability,我们的输入时display yes no,所以就是有显示,有输入输出了
cap = parse_io_capability(capability);
if (cap == IO_CAPABILITY_INVALID)
return btd_error_invalid_args(msg);
name = dbus_message_get_sender(msg);
//建agent结构体
agent = agent_create(adapter, name, path, cap,
(agent_remove_cb) agent_removed, adapter);
if (!agent)
return btd_error_failed(msg, "Failed to create a new agent");
//agent和对应的adapter关联起来
adapter->agent = agent;
DBG("Agent registered for hci%d at %s:%s", adapter->dev_id, name,
path);
//设置io capability,就是设置dev的io_capability
adapter_ops->set_io_capability(adapter->dev_id, cap);
return dbus_message_new_method_return(msg);
}
所以,总的来说,还是蛮简单的,就是建了一个agent的结构体,然后把它和对应的adapter关联起来,同时设置了dev的io
capability。
3.2 eventLoopMain分析
这个函数就是eventloop的主函数了,我们可以猜到,他会一直在运行。
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的watch函数,就是监听了和wakeup,这里其实是dbus的一些通信机制,
//我们可以不了解,只要知道最终我们是使用event_filter对event进行处理的就可以了
dbus_connection_set_watch_functions(nat->conn, dbusAddWatch,
dbusRemoveWatch, dbusToggleWatch, ptr, NULL);
dbus_connection_set_wakeup_main_function(nat->conn, dbusWakeup, ptr, NULL);
//这里就表示eventloop ok了
nat->running = true;
//下面这个while大概的意思就是通过一个本地的socket进行读写,然后到最后进行处理
while (1) {
……
}
这个函数更多的是涉及机制的问题,所以我们并没有详细的解析。
至此,eventloop的分析就全部完成了,他只是一个工具,下面的章节中,我们会详细分析这个工具给我们带来的便利。
4、其它的一些操作
除了上面涉及到的一系列的操作,在蓝牙打开的过程中还有一些jni层的操作,首先一个函数就是setBluetoothTetheringNative,他的主要作用就是使能或者说注册pan相关的操作,具体的分析如下:
static jboolean setBluetoothTetheringNative(JNIEnv *env, jobject object, jboolean value,
jstring src_role, jstring bridge) {
LOGV("%s", __FUNCTION__);
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
if (nat) {
DBusMessage *reply;
const char *c_role = env->GetStringUTFChars(src_role, NULL);
const char *c_bridge = env->GetStringUTFChars(bridge, NULL);
if (value) {
LOGE("setBluetoothTetheringNative true");
//设置为true,所以,就是register了,是networkserver的interface
reply = dbus_func_args(env, nat->conn,
get_adapter_path(env, object),
DBUS_NETWORKSERVER_IFACE,
"Register",
DBUS_TYPE_STRING, &c_role,
DBUS_TYPE_STRING, &c_bridge,
DBUS_TYPE_INVALID);
} else {
LOGE("setBluetoothTetheringNative false");
reply = dbus_func_args(env, nat->conn,
get_adapter_path(env, object),
DBUS_NETWORKSERVER_IFACE,
"Unregister",
DBUS_TYPE_STRING, &c_role,
DBUS_TYPE_INVALID);
}
env->ReleaseStringUTFChars(src_role, c_role);
env->ReleaseStringUTFChars(bridge, c_bridge);
return reply ? JNI_TRUE : JNI_FALSE;
}
#endif
return JNI_FALSE;
}
在jni中,他的接口是:
static GDBusMethodTable server_methods[] = {
{ "Register", "ss", "", register_server },
……}
所以,最终会调用register_server函数来实现:
static DBusMessage *register_server(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct network_server *ns = data;
DBusMessage *reply;
const char *uuid, *bridge;
//得到参数
if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid,
DBUS_TYPE_STRING, &bridge, DBUS_TYPE_INVALID))
return NULL;
//看uuid是否是nap
if (g_strcmp0(uuid, "nap"))
return btd_error_failed(msg, "Invalid UUID");
//看recored_id是否已经存在
if (ns->record_id)
return btd_error_already_exists(msg);
reply = dbus_message_new_method_return(msg);
if (!reply)
return NULL;
//若是没有,就注册server record
ns->record_id = register_server_record(ns);
if (!ns->record_id)
return btd_error_failed(msg, "SDP record registration failed");
g_free(ns->bridge);
ns->bridge = g_strdup(bridge);
//dbus disconnect的时候有的一个监听
ns->watch_id = g_dbus_add_disconnect_watch(conn,
dbus_message_get_sender(msg),
server_disconnect, ns, NULL);
return reply;
}
所以,总的来说还是蛮简单,就不深入详细分析了。
至此,jni中所涉及的所有部分就全部分析完成了哦。
若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·
分享到:
相关推荐
Android应用源码串口通信(JNI)例子.zip
在android 2.0环境下编写的jni示例项目源码,实现了简单的四则运算
安卓Android源码——串口通信(JNI)例子.zip
Android JNI中C++层与Java层的对象交互实例代码详细介绍。Android JNI中C++层与Java层的对象交互实例代码详细介绍。Android JNI中C++层与Java层的对象交互实例代码详细介绍。Android JNI中C++层与Java层的对象交互...
Android 串口读写程序 JNI代码程序
本程序是在Eclipse中创建的一个Android Application,该项目中是在JNI中利用OpenGL ES库和OpenCV库进行一副图片的渲染。
在jni中获取android 设备的mac地址
Android 4.4.2 动态添加JNI库方法记录 (二 app应用层)配套的源码,需要的可以下载,绝对值得参考。
android jni 实现 RSA 3DES AES MD5 BASE64 加密,基于openssl
例子中包含Android 应用程序和JNI的程序,实现充JNI到java层的回调
Android应用源码串口通信(JNI)例子.rar
Android Studio中利用gradle编译jni
AndroidStudio环境下的jni调用(NDK),这个教程可以让完全不会AndroidStudio的人学会jni调用。完全步骤话,非常简单。
Android应用源码串口通信(JNI)例子.zip项目安卓应用源码下载Android应用源码串口通信(JNI)例子.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考
实现了android 应用层和通过JNI层回调函数完成应用与native 本地代码之间的相互访问,对于了解JNI回调函数的用法有帮助
Android应用源码串口通信(JNI)例子.rar Android应用源码任务提醒源码.rar Android应用源码仿360手机助手首页浮动菜单.rar Android应用源码仿Iphone抖动效果Shake Icon.rar Android应用源码仿QQ分组列表修改版.rar ...
jni封装串口通讯例子源码,在jni层封装rs232,在android用java调用实现控制 串口发送和接收数据
Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例
Android调用Jni返回自定义对象 博客:http://blog.csdn.net/lowprofile_coding/article/details/39367323