如果遇到問題請到:http://www.reibang.com/p/2ab3aaf2aeb6
ServiceMananger 的初始化第二步 把進程對象注冊到Binder驅(qū)動中
文件:/frameworks/native/cmds/servicemanager/service_manager.c
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
我們看看這個方法具體做了什么后众。
文件:/drivers/staging/android/binder.c
int binder_become_context_manager(struct binder_state *bs)
{
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
這里又是我們熟悉的ioctl系統(tǒng)調(diào)用。這是初始化之后第一次使用bs對象,binder_state在binder_open中初始化的結(jié)構(gòu)體。此時這個結(jié)構(gòu)體包含著該binder的共享地址。
我們直接看看binder_ioctl中的switch片段
case BINDER_SET_CONTEXT_MGR:
ret = binder_ioctl_set_ctx_mgr(filp);
if (ret)
goto err;
...
break;
static int binder_ioctl_set_ctx_mgr(struct file *filp)
{
int ret = 0;
struct binder_proc *proc = filp->private_data;
...
binder_context_mgr_node = binder_new_node(proc, 0, 0);
if (binder_context_mgr_node == NULL) {
ret = -ENOMEM;
goto out;
}
binder_context_mgr_node->local_weak_refs++;
binder_context_mgr_node->local_strong_refs++;
binder_context_mgr_node->has_strong_ref = 1;
binder_context_mgr_node->has_weak_ref = 1;
out:
return ret;
}
實際上,我們需要關注的只有這么一小段。我們再一次從文件中獲取私密對象,當前的進程對應的binder_proc對象。此時應用剛剛啟動睦授,因此整個binder驅(qū)動下都是空是复。因此此時我們需要新生成一個binder_node結(jié)構(gòu)體加入到binder的紅黑樹中管理。而這個binder_node代表著在binder驅(qū)動中,一個進程啥繁,工作項蜜另,引用列表等關鍵數(shù)據(jù)的集合。
當我們添加并且生成binder一個新的binder _node對象之后,把它賦值給binder_context_mgr_node這個對象。這個對象是為了快速的尋找service_manager而創(chuàng)建的全局對象。這也因為考慮到Android系統(tǒng)處處使用這個對象。
我們來看看binder_new_node方法殉了。
static struct binder_node *binder_new_node(struct binder_proc *proc,
binder_uintptr_t ptr,
binder_uintptr_t cookie)
{
struct rb_node **p = &proc->nodes.rb_node;
struct rb_node *parent = NULL;
struct binder_node *node;
while (*p) {
parent = *p;
node = rb_entry(parent, struct binder_node, rb_node);
if (ptr < node->ptr)
p = &(*p)->rb_left;
else if (ptr > node->ptr)
p = &(*p)->rb_right;
else
return NULL;
}
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (node == NULL)
return NULL;
binder_stats_created(BINDER_STAT_NODE);
rb_link_node(&node->rb_node, parent, p);
rb_insert_color(&node->rb_node, &proc->nodes);
node->debug_id = ++binder_last_id;
node->proc = proc;
node->ptr = ptr;
node->cookie = cookie;
node->work.type = BINDER_WORK_NODE;
INIT_LIST_HEAD(&node->work.entry);
INIT_LIST_HEAD(&node->async_todo);
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"%d:%d node %d u%016llx c%016llx created\n",
proc->pid, current->pid, node->debug_id,
(u64)node->ptr, (u64)node->cookie);
return node;
}
此時谓娃,Binder創(chuàng)建一個新的Binder 實體如果看過我的紅黑樹文章這里也就輕而易舉了。
此時Binder將會從紅黑樹中根據(jù)node的弱引用的地址作為key尋找node。此時肯定是不會找到的,因此會通過kzmalloc生成一個新的node,并且添加到rb_node這個紅黑樹中管理庸推。并且把binder的本地對象設置到cookie中。此時node的work模式是BINDER_WORK_NODE。
這樣Binder驅(qū)動中第一個代表著service manager的binder實體就創(chuàng)建完成了养葵。
此時的生成模式并沒有有頂層的JavaBBinder咳榜,BpBinder,IPCThreadState等核心初始化Binder類參與進來玄捕。是一個極其特殊的服務的初始化馍迄。所以很多地方?jīng)]有把service manager這個作為一個binder 服務,而是說是binder驅(qū)動的守護進程。然而歸根結(jié)底幌缝,也不過只是注冊在Binder驅(qū)動中的binder對象缘厢。
ServiceMananger 的初始化第三步 service_manager啟動消息等待循環(huán)
文件:/frameworks/native/cmds/servicemanager/service_manager.c
binder_loop(bs, svcmgr_handler);
實際上這里就是啟動Android Service體系中的消息等待初始化间护。
文件:/frameworks/native/cmds/servicemanager/binder.c
void binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
struct binder_write_read bwr;
uint32_t readbuf[32];
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER;
binder_write(bs, readbuf, sizeof(uint32_t));
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
...
break;
}
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
if (res == 0) {
...
break;
}
if (res < 0) {
...
break;
}
}
}
依據(jù)之前學習到的東西,我們大致上可以知道拾积,這個looper做了以下幾個事情玲销。
1.service_manager先往binder驅(qū)動中往binder_write_read寫入BC_ENTER_LOOPER 策吠,告訴binder驅(qū)動進入service的循環(huán)命令。
- service_manager 進入阻塞瘩绒,等待binder驅(qū)動往binder_write_read寫入數(shù)據(jù)猴抹。
3.解析從binder驅(qū)動中傳送上來的數(shù)據(jù)。
接下來锁荔,我將分為三點慢慢來聊聊蟀给。
1.binder looper 發(fā)送BC_ENTER_LOOPER 命令
這里有一個很關鍵的結(jié)構(gòu)體 binder_write_read
文件:/bionic/libc/kernel/uapi/linux/android/binder.h
struct binder_write_read {
binder_size_t write_size;//寫入數(shù)據(jù)的大小
binder_size_t write_consumed;//寫入的數(shù)據(jù),已經(jīng)寫過了多少位置
binder_uintptr_t write_buffer;// 寫入數(shù)據(jù)的數(shù)據(jù)緩沖區(qū)
binder_size_t read_size;//讀取數(shù)據(jù)的大小
binder_size_t read_consumed;//讀取的數(shù)據(jù)阳堕,已經(jīng)讀取多少數(shù)據(jù)
binder_uintptr_t read_buffer;//讀取數(shù)據(jù)的數(shù)據(jù)緩沖區(qū)
};
結(jié)構(gòu)體binder_write_read可以分為兩部分跋理,上部分描述了要寫進去的數(shù)據(jù),下部分描述要讀取的數(shù)據(jù)恬总。binder_write_read結(jié)構(gòu)體一般是用來承載framework層數(shù)據(jù)的載體前普,用于傳遞數(shù)據(jù)給binder驅(qū)動。
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER;
binder_write(bs, readbuf, sizeof(uint32_t));
binder一開始對寫入數(shù)據(jù)進行初始化壹堰。接著BC_ENTER_LOOPER放到readbuf屬性中拭卿,通過binder_write往binder驅(qū)動寫入骡湖。
int binder_write(struct binder_state *bs, void *data, size_t len)
{
struct binder_write_read bwr;
int res;
bwr.write_size = len;
bwr.write_consumed = 0;
bwr.write_buffer = (uintptr_t) data;
bwr.read_size = 0;
bwr.read_consumed = 0;
bwr.read_buffer = 0;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
fprintf(stderr,"binder_write: ioctl failed (%s)\n",
strerror(errno));
}
return res;
}
此時我們看到binder_write_read 把讀取相關的數(shù)據(jù)都初始化為0,而寫入數(shù)據(jù)相關的屬性峻厚,write_buffer寫入數(shù)據(jù)响蕴,write_size寫入數(shù)據(jù)長度,write_consumed 為0.這樣就告訴了binder驅(qū)動知道數(shù)據(jù)在哪里惠桃,應該從哪里開始讀取浦夷。
文件:/drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
...
switch (cmd) {
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
此時根據(jù)上面?zhèn)飨聛淼臄?shù)據(jù),將會走binder_ioctl_write_read分支刽射。從這里開始就是binder的核心分支之一,binder驅(qū)動在進程間讀寫數(shù)據(jù)的核心就是這個方法剃执。
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
int ret = 0;
struct binder_proc *proc = filp->private_data;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {
ret = -EINVAL;
goto out;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
...
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
...
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
...
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}
binder分為三個步驟進行解析從ioctl傳送下來的數(shù)據(jù)誓禁。
- 1.把傳遞下來的數(shù)據(jù)轉(zhuǎn)型為內(nèi)核對應的binder_write_read結(jié)構(gòu)體蜘拉。
- 當判斷到binder_write_read中write_size大于0昔驱,說明有數(shù)據(jù)寫入,則執(zhí)行binder_thread_write硼婿。
- 3.當判斷到binder_write_read中read_size大于0怒见,說明有數(shù)據(jù)需要讀取俗慈,則執(zhí)行binder_thread_read。
結(jié)束完之后遣耍,則從內(nèi)核態(tài)的binder_write_read拷貝到用戶態(tài)的binder_write_read數(shù)據(jù)中闺阱。因為此時傳遞下來的ubuf恰好就是用戶空間對應的binder_write_read。因此能夠直接通過copy_to_user把數(shù)據(jù)從內(nèi)核空間拷貝一份到用戶空間舵变。
因此我們可以得出酣溃,binder在處理每個協(xié)議下來的數(shù)據(jù)時候,都是先處理寫的數(shù)據(jù)纪隙,再處理讀的數(shù)據(jù)赊豌。為什么這么做分別看看下面兩個方法就知道了。
binder處理從framework傳下來的寫數(shù)據(jù)
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
uint32_t cmd;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {
if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
trace_binder_command(cmd);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
binder_stats.bc[_IOC_NR(cmd)]++;
proc->stats.bc[_IOC_NR(cmd)]++;
thread->stats.bc[_IOC_NR(cmd)]++;
}
switch (cmd) {
...
case BC_ENTER_LOOPER:
binder_debug(BINDER_DEBUG_THREADS,
"%d:%d BC_ENTER_LOOPER\n",
proc->pid, thread->pid);
if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {
thread->looper |= BINDER_LOOPER_STATE_INVALID;
binder_user_error("%d:%d ERROR: BC_ENTER_LOOPER called after BC_REGISTER_LOOPER\n",
proc->pid, thread->pid);
}
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
break;
case BC_EXIT_LOOPER:
binder_debug(BINDER_DEBUG_THREADS,
"%d:%d BC_EXIT_LOOPER\n",
proc->pid, thread->pid);
thread->looper |= BINDER_LOOPER_STATE_EXITED;
break;
...
default:
pr_err("%d:%d unknown command %d\n",
proc->pid, thread->pid, cmd);
return -EINVAL;
}
*consumed = ptr - buffer;
}
return 0;
}
這里我只挑選出需要關注的分支绵咱。
首先binder在處理寫入數(shù)據(jù)的時候碘饼,由于沒辦法直接通過sizeof直接找到數(shù)據(jù)結(jié)構(gòu)的邊界,因此通過思路上和Parcel相似悲伶,通過下面幾種參數(shù)來控制整個讀寫過程艾恼。
uint32_t cmd;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
- 1.cmd 這個縮寫英文我們可以直接望文生義,就是從framework中寫進來的write_buffer中第一個int型麸锉,這個決定了驅(qū)動怎么解析這次命令數(shù)據(jù)蒂萎。
- 2.buffer 對應這用戶空間的write_buffer 這里面存儲著需要處理的數(shù)據(jù)。
- 3.ptr 對應著此時binder驅(qū)動已經(jīng)處理了多少數(shù)據(jù)淮椰。
- end 確定這一次buffer邊界五慈。
數(shù)據(jù)解析循環(huán)
while (ptr < end && thread->return_error == BR_OK) {
if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
根據(jù)上面的數(shù)據(jù)解析纳寂,因此可以知道此時數(shù)據(jù)解析的循環(huán)結(jié)束條件有兩個,第一 buffer的數(shù)據(jù)區(qū)域循環(huán)到了結(jié)束地址泻拦,第二毙芜,binder_thread 返回BR_OK。
從第一個get_user從用戶空間拷貝方法出來得知争拐,每一次循環(huán)第一個參數(shù)必定是符合條件的cmd腋粥,對應著下面binder分支命令。接著消費指針向前移動一個int的大小架曹,而后面就是我們需要處理的數(shù)據(jù)隘冲。
此時我們從用戶空間下傳下來的命令正是BC_ENTER_LOOPER。
case BC_ENTER_LOOPER:
binder_debug(BINDER_DEBUG_THREADS,
"%d:%d BC_ENTER_LOOPER\n",
proc->pid, thread->pid);
if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {
thread->looper |= BINDER_LOOPER_STATE_INVALID;
binder_user_error("%d:%d ERROR: BC_ENTER_LOOPER called after BC_REGISTER_LOOPER\n",
proc->pid, thread->pid);
}
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
break;
此時命令需要的操作很簡單绑雄,就是修改當前binder_proc對應的binder_thread的狀態(tài)展辞。
這樣就完成了service_manager 從用戶空間的寫入操作。還記得上面的對binder_write_read的結(jié)構(gòu)體處理嗎万牺?此時因為read_size被設置為0.因此走不到binder_thread_read罗珍。接著把內(nèi)核空間對應的binder_write_read拷貝回到用戶空間即可。
service_manager 正式進入到binder looper循環(huán)等待消息脚粟。
文件:/frameworks/native/cmds/servicemanager/binder.c
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
...
break;
}
可以看到這是一個無限的循環(huán)覆旱,等待著binder驅(qū)動信息返回信息。但是做一個google開發(fā)者怎么可能真的讓循環(huán)不斷進行下去呢核无?看過我啟動的zygote一章節(jié)的讀者扣唱,肯定知道一直在跑無限循環(huán)只會不斷的開銷cpu,因此在這個循環(huán)必定會通過阻塞之類的手段來規(guī)避這種looper的開銷团南。
我們看看循環(huán)的第一段画舌。此時,把讀取的數(shù)據(jù)長度設置為readbuf 一個長度為32的int數(shù)組已慢。接著通過ioctl曲聂,通信到binder驅(qū)動。
文件:/drivers/staging/android/binder.c
此時我們根據(jù)service_manager可以得知佑惠,此時write_size為0朋腋,read_size不為0,將會走binder_ioctl_write_read 讀取數(shù)據(jù)的代碼:
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
...
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
...
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
我們看看binder_thread_read內(nèi)部邏輯。
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed, int non_block)
{
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
int ret = 0;
int wait_for_proc_work;
if (*consumed == 0) {
if (put_user(BR_NOOP, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
}
retry:
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo);
if (thread->return_error != BR_OK && ptr < end) {
if (thread->return_error2 != BR_OK) {
if (put_user(thread->return_error2, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, thread->return_error2);
if (ptr == end)
goto done;
thread->return_error2 = BR_OK;
}
if (put_user(thread->return_error, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, thread->return_error);
thread->return_error = BR_OK;
goto done;
}
thread->looper |= BINDER_LOOPER_STATE_WAITING;
if (wait_for_proc_work)
proc->ready_threads++;
binder_unlock(__func__);
trace_binder_wait_for_work(wait_for_proc_work,
!!thread->transaction_stack,
!list_empty(&thread->todo));
if (wait_for_proc_work) {
if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED))) {
binder_user_error("%d:%d ERROR: Thread waiting for process work before calling BC_REGISTER_LOOPER or BC_ENTER_LOOPER (state %x)\n",
proc->pid, thread->pid, thread->looper);
wait_event_interruptible(binder_user_error_wait,
binder_stop_on_user_error < 2);
}
binder_set_nice(proc->default_priority);
if (non_block) {
if (!binder_has_proc_work(proc, thread))
ret = -EAGAIN;
} else
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
} else {
if (non_block) {
if (!binder_has_thread_work(thread))
ret = -EAGAIN;
} else
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
}
binder_lock(__func__);
if (wait_for_proc_work)
proc->ready_threads--;
thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
if (ret)
return ret;
while (1) {
...
}
done:
*consumed = ptr - buffer;
...
return 0;
}
原理和binder_thread_write相似膜楷。binder_thread_read 做了以下幾件事情旭咽。
- 1.首先判斷到此時binder 驅(qū)動沒有讀取任何數(shù)據(jù)時候,則會為用戶空間返回的數(shù)據(jù)中赌厅,第一段數(shù)據(jù)加上BR_NOOP穷绵。
- wait_for_proc_work 判斷當前進程是否需要等待工作。這個標志位的判斷條件為binder _thread的事務處理棧為空同時binder_thread 的todo list沒有任何需要todo的項特愿。
- 設置binder_thread->looper狀態(tài)進入到了BINDER_LOOPER_STATE_WAITING狀態(tài)
- 4.假如需要等待仲墨,則判斷當前binder初始化的時候是可阻塞工作還是不可阻塞工作勾缭。如果是可阻塞,則會取出binder _thread->wait 等待隊列目养,讓本進程進入到等待當中俩由。還記得我之前寫的等待隊列的本質(zhì)吧。實際上就是把這個時候進程會通過進程調(diào)度癌蚁,把當前進程的需要的cpu資源讓渡出去幻梯。如果是非阻塞,則判斷當前binder_thread中是否還有需要的工作努释,沒有則直接返回碘梢。
- 當當前進程的等待隊列被喚醒,則會把 thread->looper 的BINDER_LOOPER_STATE_WAITING關閉伐蒂。
- 6.進入到while循環(huán)解析數(shù)據(jù)煞躬。
而此時的場景,我們并有任何的需要工作的隊列饿自,因此通過wait_event_freezable把service_manager阻塞起來汰翠。
service_manager binder_parse獲取binder驅(qū)動回復的消息消息龄坪。
int binder_parse(struct binder_state *bs, struct binder_io *bio,
uintptr_t ptr, size_t size, binder_handler func)
{
int r = 1;
uintptr_t end = ptr + (uintptr_t) size;
while (ptr < end) {
uint32_t cmd = *(uint32_t *) ptr;
ptr += sizeof(uint32_t);
#if TRACE
fprintf(stderr,"%s:\n", cmd_name(cmd));
#endif
switch(cmd) {
case BR_NOOP:
break;
....
default:
ALOGE("parse: OOPS %d\n", cmd);
return -1;
}
}
return r;
}
這里場景模擬昭雌,假如有某個線程喚醒了service_manager,此時ptr實際上就是readbuf這個緩沖區(qū)。我們不管這個數(shù)據(jù)如何健田,第一個返回的參數(shù)必定是BR_NOOP烛卧,告訴著service_manager開始讀取數(shù)據(jù)的開頭標志位。接著不斷的移動指針妓局,讀取處理每一段信息总放。
因此我們可以模擬tcp封包一樣模擬出binder驅(qū)動在通信時候,數(shù)據(jù)是如何封包的好爬。
特殊的當讀取通信信息的時候局雄,封包格式將如下:
這里就是binder驅(qū)動在Android 系統(tǒng)中service_manager 體系的初始化。當然還有一種aidl的binder初始化存炮,我將會在后面和大家揭曉炬搭。
總結(jié)
這里總結(jié)一副時序圖,為了便于理解穆桂,我省略掉通過軟中斷到內(nèi)核空間的過程宫盔。
從上圖我們大致上可以總結(jié)出Binder驅(qū)動在系統(tǒng)初始化的時候大致上分為以下三步:
- binder_open 打開binder驅(qū)動文件,確認版本號享完,并把該進程以及相關信息映射到內(nèi)核中
- 2.mmap 確認能夠打開binder驅(qū)動之后灼芭,再把當前進程的地址和內(nèi)核映射到一起。
- 3.把當前的service_manager作為一個binder實體注冊到binder驅(qū)動中般又,作為第一個binder服務彼绷。
- 4.進入binder_loop巍佑。先通過ioctl 通知binder驅(qū)動此時service_manager進入到了循環(huán)模式。接著調(diào)用讀取數(shù)據(jù)函數(shù)苛预,進入阻塞狀態(tài)句狼。當service_manager被喚醒,則開始解析從binder傳上來的數(shù)據(jù)热某。
到目前位置腻菇,我如下圖已經(jīng)將描紅的部分在Android 服務系統(tǒng)中初始化的闡述完畢。
能夠注意到的是昔馋,此時我們還沒有添加任何的binder 的服務進來筹吐。但是基礎的dns(service_manager)和路由分發(fā)器(Binder驅(qū)動)已經(jīng)準備好了,接下來秘遏,讓我們聊聊client 和 server的初始化丘薛。