[Android 소스 분석] jni 레이어에서 Eventloop 분석
이벤트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을 지원하는 역할이 없기 때문에 세 번째 장치가 연결된 후에 문제가 발생할 수 있습니다.만약 이 글이 당신에게 도움이 된다고 생각되면 아래에서 마우스로 가볍게'정'을 눌러주세요. 하하~...
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.