[Android源码解析]Eventloop在jni层的分析

3 eventloopjni层的详细分析

         Eventloop在整个bluetoothjni层和bluez之间的交互,以及jniframework层之间的交互过程中有着举足轻重的作用。所以,本文仍然需要花费一定的笔墨来分析它,当然由于它更像是一个桥梁,我们的分析有可能就不是那么的深入了,会从比较宏观地角度来看待这个东西的作用。

         当然,一切的一切还是要从源码来说:

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关联起来,同时设置了devio 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的角色,所以再你第三个设备连接之后会出现问题。


若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·

你可能感兴趣的:(android,蓝牙,EventLoop)