[Android 소스 분석] jni 레이어에서 Eventloop 분석

3 이벤트loop이 jni층에 대한 상세한 분석
이벤트loop은 전체 블루투스의 jni층과 블루즈 간의 상호작용, 그리고 jni와 프레임워크 층 간의 상호작용 과정에서 매우 중요한 역할을 한다.그래서 본고는 여전히 일정한 필묵을 써서 그것을 분석해야 한다. 물론 이것은 다리와 같기 때문에 우리의 분석은 그렇게 깊이 들어가지 않고 비교적 거시적인 측면에서 이 물건의 작용을 볼 수 있다.
물론 모든 것은 원본에서 말해야 한다.
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 이벤트loop의 구축
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 등록 에이전트
이거 다시 블루즈로 돌아왔어요. 아담터에서.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);
}
 
그래서 전체적으로 말하자면 아주 간단하다. 바로 에이전트의 구조체를 만들고 그에 대응하는adapter와 연결시키고 dev의iocapability를 설정한 것이다.
 
3.2 이벤트LoopMain 분석
이 함수가 바로 이벤트loop의 주 함수입니다. 우리는 그가 계속 운행할 것이라고 추측할 수 있습니다.
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) {
……
}
 
이 함수는 메커니즘과 관련된 문제가 더 많기 때문에 우리는 상세한 해석을 하지 않았다.
 
이로써 이벤트loop의 분석은 모두 완성되었다. 그는 단지 하나의 도구일 뿐이다. 다음 장에서 우리는 이 도구가 우리에게 가져다 준 편리함을 상세하게 분석할 것이다.
4, 기타 일부 작업
위에서 언급한 일련의 조작을 제외하고 블루투스를 여는 과정에서 jni층의 조작도 있다. 첫 번째 함수는 setBluetoothTetheringNative이다. 그의 주요 역할은 바로 팬을 등록하는 것과 관련된 조작이다. 구체적인 분석은 다음과 같다.
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(와이파이를 통해 접속)
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을 지원하는 역할이 없기 때문에 세 번째 장치가 연결된 후에 문제가 발생할 수 있습니다.
만약 이 글이 당신에게 도움이 된다고 생각되면 아래에서 마우스로 가볍게'정'을 눌러주세요. 하하~...

좋은 웹페이지 즐겨찾기