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中所涉及的所有部分就全部分析完成了哦。
附1:关于2L提问的回答
所谓的蓝牙上网共享,蓝牙设备会扮演三个角色,他们分别是:
1、NAP:这个是用来向连结的蓝牙设备提供网络数据包的,它需要有额外的上网能力。也就是2L提到的设备1(通过wifi上网)
2、GN:这个是用来转发从连接的蓝牙设备收到的网络数据包。它不需要额外的上网能力。
3、PANU:就是专门用来接收蓝牙设备发送过来的网络数据包,也就是可以通过连接别的设备来进行上网。
目前android的代码只支持其中的两个角色就是NAP和PANU,代码如下:
/** * The local device is acting as a Network Access Point. */ public static final int LOCAL_NAP_ROLE = 1; /** * The local device is acting as a PAN User. */ public static final int LOCAL_PANU_ROLE = 2;
没有支持GN的角色,所以再你第三个设备连接之后会出现问题。
若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·