如果帶著問題去學習binder又是怎樣的呢?
1. 第一個binder線程 Binder:PID_1是怎樣創建的
在App進程創建的時候
nativeZygoteInit
-> com_android_internal_os_RuntimeInit_nativeZygoteInit
-> onZygoteInit
-> ProcessState
-> startThreadPool()
-> spawnPooledThread(true)
isMain=true
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName(); //這里是第一個binder 線程,也就是binder主線程
sp<Thread> t = new PoolThread(isMain); //生成一個線程
t->run(name.string()); //線程運行,不停的調用theadLoop
}
}
virtual bool threadLoop()
{
IPCThreadState* ptr = IPCThreadState::self();
if (ptr) {
ptr->joinThreadPool(mIsMain);
}
return false; //threadLoop返回false表示會退出線程,即線程結束了
}
void IPCThreadState::joinThreadPool(bool isMain)
{
// mOut是寫入內核的數據,如果是Main Binder線程,則發送 BC_ENTER_LOOPER
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
status_t result;
do {
processPendingDerefs(); //處理引用計數
result = getAndExecuteCommand(); //獲得命令并執行
//異常退出
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
abort();
}
//如果timeout了,但如果不是 Main Binder線程也就是非 Binder:xxx_1線程就直接退出
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
//通知binder驅動 線程要退出了
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
在 binder_thread_write
中會有對 BC_ENTER_LOOPER的處理, 如下所示,thread是指binder_thread,也就是當前線程的描述符, 將BINDER_LOOPER_STATE_ENTERED保存到 binder_thread的looper變量里.
looper變量主要保存的binder線程的一種狀態如
- BINDER_LOOPER_STATE_REGISTERED
標記該binder線程是非主binder線程 - BINDER_LOOPER_STATE_ENTERED
標記該binder線程是主binder線程 - BINDER_LOOPER_STATE_EXITED
標記該binder線程馬上就要退出了 - BINDER_LOOPER_STATE_INVALID
標記是無效的,但是這個并沒有實際用處,一般是 原來是主線程,然后用戶態又通過主線程發送了BC_REGISTER_LOOPER,就會標志 INVALID, 同理與REGISTER一樣 - BINDER_LOOPER_STATE_WAITING
標記當前binder線程正在等著client的請求 - BINDER_LOOPER_STATE_NEED_RETURN
這個標志,是當前新線程下來在生成binder_thread里置位的,表示該binder線程在處理完transaction后需要返回到用戶態。
case BC_ENTER_LOOPER:
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;
從上面可知,startThreadPool就是創建APP進程的binder線程池模型, 它也會創建第一個binder主線程,該線程不會退出(非 critcal錯誤),而spawnPooledThread函數用于創建一個普通的binder線程,這些線程都有可能會退出。
二、 一個APP里最多能有多少個binder線程呢? 其它binder線程是怎么創建的,由誰創建的呢?
從第一節可知,只要調用 spawnPooledThread()函數就創建了一個binder線程,因此從代碼上來看除了第一個主binder線程由APP用戶態主動創建外,其它的都是由Binder驅動主動向APP申請創建,也就是說binder線程的創建是看binder驅動是否很繁忙(這里的繁忙是與本進程相關的),來決定是否需要向APP進程申請創建,也就是APP進程被動創建。
2.1 Server端
其實也很好理解,binder最終的通信包括client和server雙方。server方并不知道什么時候會有client的請求,client的有請求,它就直接丟給binder驅動,然后由binder驅動根據當前server的能力(是否有多余線程去處理)去看下是否需要新的線程來處理client的請求。
那試問一個 Server端 App 最多同時能跑多少個binder線程呢?
這個問題,可以簡單的測試一下,寫一個Service, 然后實現一個API里死循環sleep, 反正就是不返回, 另一個client在創建多個非UI線程去請求API, 然后再dump出來,就知道最多支持多少個binder線程了。
我們從 spawnPooledThread的調用函數來看就知道能有多少個binder線程了。
IPCThreadState::executeCommand(int32_t cmd) {
case BR_SPAWN_LOOPER:
mProcess->spawnPooledThread(false);
break;
}
executeCommand函數執行從Binder 驅動傳遞到 BR_SPAWN_LOOPER, 這時就得繼續從binder驅動中去找 BR_SPAWN_LOOPER了。
static int binder_thread_read(...)
...
if (proc->requested_threads + proc->ready_threads == 0 &&
proc->requested_threads_started < proc->max_threads &&
(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */
/*spawn a new thread if we leave this out */) {
proc->requested_threads++;
if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
return -EFAULT;
binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
}
}
在binder_thread_read調用的最后,就會有可能去spawn一個線程, 但是也是有條件的, 且要同時滿足才行
binder_proc -> ready_threads = 0
ready_threads表明當前進程中還沒有準備好的線程, 換句話說,當前binder線程都有各自的任務在處理, 沒空接受新的任務了。binder_proc -> requested_threads = 0
如果 reqeusted_threads >0 表明 binder_driver已經通過其它binder線程請求APP進程去創建binder線程來處理任務的路上了, 所以啊,binder驅動就不會再通知一次了,因為如果再通知一次,那么就會創建兩個binder線程,資源浪費嘛。
所以如果 requested_threads = 0,如果其它條件滿足,那就由我這個binder線程就請求APP去創建另一個binder線程proc->requested_threads_started < proc->max_threads
max_threads: 這個是APP進程通知binder驅動我這個APP進程當前最多只能創建max_threads個線程,如果我已經創建這么多了,不要再通知我去創建了。至于別人(其它APP)想要獲得我的服務或其它,別急,取號等著,等著我的binder線程不忙了再去處理。thread->looper & (BINDER_LOOPER_STATE_REGISTERED |BINDER_LOOPER_STATE_ENTERED
looper保存著當前線程的一些狀態,BINDER_LOOPER_STATE_REGISTERED(非主Binder線程)|BINDER_LOOPER_STATE_ENTERED(主binder線程) 這兩個是binder線程的標志. 即: Binder驅動只有通過我的APP創建的(有效的)binder線程才有資格向我(APP)提出創建其它binder線程.
好了,上面4個條件同時滿足了,就通知APP創建一個新的 binder線程了。
但還有幾個問題
binder_proc->max_threads最大是多少呢?
在ProcessState.cpp的 open_driver 函數中, 會設置一個默認的最大binder線程數 DEFAULT_MAX_BINDER_THREADS = 15;
但是BinderInternal.java也提供了setMaxThreads去修改Binder驅動中的max_threads值. 比如system_server就設置了max_threads為31
注意 : BinderInternal是internal的類,APP不能直接調用。ready_threads 這個是什么意思呢?
在binder_thread_read
函數中
static int binder_thread_read(..) {
//wait_for_proc_work表示是否需要去等著proc的任務,當然前提是這個binder線程沒有任務可做了,
//那這個binder線程就可以向進程申請去處理進程的其它任務了
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo);
if (wait_for_proc_work)
proc->ready_threads++; //表明當前進程又多了一個可用的binder線程去接受任務了
if (wait_for_proc_work) {
//等著整個進程的任務
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
} else {
//等著binder線程本身的任務
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
}
...
//代碼運行到這里就表明有任務了,那么我這個binder線程就要去接受任務去做了,
if (wait_for_proc_work)
//既然我已經開始去處理任務了,那么整個進程當前就少了我一個可用的線程啦
proc->ready_threads--;
...
done:
//決定是否再創建一個新的binder線程
*consumed = ptr - buffer;
if (proc->requested_threads + proc->ready_threads == 0 &&
proc->requested_threads_started < proc->max_threads &&
(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */
proc->requested_threads++; //請求創建線程+1
if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
return -EFAULT;
binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
}
}
- requested_threads與requested_threads_started
requested_threads表示要請求創建的線程數,在上面決定創建binder線程后,該值會+1
而requested_threads_started表示當前進程已經啟動吧這么多個線程,
APP接收到創建新的binder線程的請求后就會調用spawnPooledThread(false)
去創建一個非Main的binder線程, 而最后又會通過joinThreadPool觸發binder驅動的BC_REGISTER_LOOPER
static int binder_thread_write(...) {
case BC_REGISTER_LOOPER:
if (thread->looper & BINDER_LOOPER_STATE_ENTERED) {
thread->looper |= BINDER_LOOPER_STATE_INVALID;
} else if (proc->requested_threads == 0) {
thread->looper |= BINDER_LOOPER_STATE_INVALID;
} else {
//正常情況會進入該分支
proc->requested_threads--; //要請求創建的binder線程數減1
proc->requested_threads_started++; //啟動過的線程數+1
}
thread->looper |= BINDER_LOOPER_STATE_REGISTERED;
break;
2.2 client
client端作為請求端,是從用戶態下發起請求的,所以client一般是自己申請創建線程,然后在線程里去請求 server端的服務,這里不會涉及到binder線程。
那么client就只有一個默認的主binder線程了么?當然不是,從2.1可知,binder驅動會不管是server,還是client, 都會默認有一個空閑線程,所以client的主binder線程在binder_thread_read的最后發現當前沒有可ready的線程,這時就通知client端創建一個binder線程。所以一般client有兩個binder線程。
三、Server的binder線程阻塞在哪里了?
人第二節可知道,Server端的binder線程會一直等著client的請求,即如果沒有客戶端請求時,binder線程應該是一直阻塞著的,那么Server端等在什么地方呢?
來看下binder線程的運行過程便可知, 第一小節已經貼出相關代碼了, 再帖一次,
void IPCThreadState::joinThreadPool(bool isMain)
{
// mOut是寫入內核的數據,如果是Main Binder線程,則發送 BC_ENTER_LOOPER
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
status_t result;
do {
processPendingDerefs(); //處理引用計數
result = getAndExecuteCommand(); //獲得命令并執行
//異常退出
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
abort();
}
//如果timeout了,但如果不是 Main Binder線程也就是非 Binder:xxx_1線程就直接退出
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
//通知binder驅動 線程要退出了
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
從joinThreadPool里,有一個getAndExecuteCommand, 來看下這個函數干了些什么吧
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result; //異常處理
cmd = mIn.readInt32(); //獲得從Binder驅動返回來的BR_ 號
...
result = executeCommand(cmd); //開始執行相關命令
...
}
return result;
}
該函數很簡單,從binder驅動里拿到client要操作的CMD, 然后調用executeCommand執行CMD。
在看 talkWithDriver
之前,先來看下 binder_write_read
binder_write_read是一個結構體,它主要作用是告訴binder驅動我這次請求的目的是什么,一是read, 另一個就是write,
- write_size > 0 表明需要往binder驅動寫write_buffer的數據
- read_size >0 表明需要往binder驅動讀數據放到write_buffer的數據
- write_consumed 表明已經寫入了多少字節
- read_consumed 表明讀入了多少字節
- write_buffer 指向用戶態下的數據地址,其實也就是IPCThreadState里的mOut (Parcel)里的mData地址
- read_buffer 指向用戶態下的數據地址,其實也就是IPCThreadState里的mIn (Parcel)里的mData地址
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
binder_write_read bwr;
//mIn.dataPosition()是當前mIn中mData的指針,
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
//doReceive默認為true, needRead為true表明還需要從Binder驅動中讀取數據,這時候就不能往binder驅動中寫數據
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
//填充寫數據的相關字段
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
// This is what we'll read.
if (doReceive && needRead) {
//填充讀數據相關字段
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
// Return immediately if there is nothing to do.
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
#if defined(__ANDROID__)
//阻塞式的調用 binder_ioctl
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
} while (err == -EINTR);
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
//根據寫了多少數據,來更新mOut的相關數據
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else
mOut.setDataSize(0);
}
if (bwr.read_consumed > 0) {
//根據讀了多少數據,來更新mIn的相關數據
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
return NO_ERROR;
}
return err;
}
3.1 binder線程第一次調用 binder_ioctl
我們來看下binder線程創建后第一次調用 binder_ioctl 的情況
從joinThreadPool可以看出, 會寫入一個 BC_REGISTER_LOOPER
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
因此此時binder_write_read的結構如下所示
來看下binder驅動是怎么處理的呢
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
// binder_stop_on_user_error默認為0,只有條件為false的時候才會一直block在這,所以這里并不會block
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
binder_lock(__func__);
//創建一個與binder線程相關的binder_thread, 第一次創建會設置thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN
thread = binder_get_thread(proc);
switch (cmd) {
case BINDER_WRITE_READ: //執行BINDER_WRITE_READ命令
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
break;
...
}
ret = 0;
err:
if (thread) //這里取消BINDER_LOOPER_STATE_NEED_RETURN
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
err_unlocked:
return ret;
}
其中BINDER_LOOPER_STATE_NEED_RETURN
這個非常重要,就是這個標志,決定了binder線程第一次的走向,如果是第一次進來, binder_thread->looper都設置了該標志,而該binder_ioctl返回時,會將該標志取消
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;
//獲得用戶態的 binder_write_read
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
if (bwr.write_size > 0) {
//有數據要寫入,這里就是 BC_REGISTER_LOOPER
ret = binder_thread_write(proc, thread, bwr.write_buffer,
bwr.write_size, &bwr.write_consumed);
}
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);
//如果進程描述結構體中有任務要做時,喚醒等在binder_proc->wait的列表
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
}
//將數據拷貝到用戶態
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
}
out:
return ret;
}
binder線程第一次調用binder_ioctl也就是寫入一個BC_REGISTER_LOOPER, 所以 binder_thread_write只是將binder_thread->looper設置一個BINDER_LOOPER_STATE_REGISTERED
現在來看下binder_thread_read
static int binder_thread_read(...)
{
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;
//第一次進來 consumed為0,所以進入該分支, 會返回一個 BR_NOOP
if (*consumed == 0) {
if (put_user(BR_NOOP, (uint32_t __user *)ptr)) return -EFAULT;
ptr += sizeof(uint32_t);
}
retry:
//binder線程第一次進來,沒有transaction任務,也沒有其它任務,所以waite_for_proc_work為true
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo);
thread->looper |= BINDER_LOOPER_STATE_WAITING;
if (wait_for_proc_work)
proc->ready_threads++; //線程可用
binder_unlock(__func__);
if (wait_for_proc_work) { //進入該分支
if (non_block) {
if (!binder_has_proc_work(proc, thread))
ret = -EAGAIN;
} else
//如果binder_has_proc_work為false,將會一直等在這里,直到被喚醒
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) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
if (!list_empty(&thread->todo)) { //無任務
w = list_first_entry(&thread->todo, struct binder_work, entry);
} else if (!list_empty(&proc->todo) && wait_for_proc_work) { //無任務
w = list_first_entry(&proc->todo, struct binder_work, entry);
} else {
/* no data added */
if (ptr - buffer == 4 &&
!(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
goto retry;
break; //直接break到
}
if (end - ptr < sizeof(tr) + 4)
break;
switch(...) {}
}
done:
//決定是否要向用戶態申請創建一個新的線程
*consumed = ptr - buffer;
if (proc->requested_threads + proc->ready_threads == 0 &&
proc->requested_threads_started < proc->max_threads &&
(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */
/*spawn a new thread if we leave this out */) {
proc->requested_threads++;
if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
return -EFAULT;
binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
}
return 0;
}
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
現在來看下wait_event_freezable_exclusive, 該函數的條件如果為true,即表明binder有任務時,就不會阻塞,而是直接執行,binder線程第一次進來的時候(因為binder線程的創建是防止后續有請求到來,所以當前是沒有任務的), 當前沒有任務的話,binder線程應該一直等著呀,為什么這里沒有阻塞式的等呢?
static int binder_has_proc_work(struct binder_proc *proc, struct binder_thread *thread)
{
return !list_empty(&proc->todo) ||
(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN);
}
哦,原來binder_has_proc_work會判斷如果binder線程是第一次進來的話,也就是設置了BINDER_LOOPER_STATE_NEED_RETURN,也就是表明該線程不管你有沒有任務,我都需要返回到用戶態,所以這里為true, 也就不會等待了。
所以第一次返回給用戶態時,只返回一個 BR_NOOP, 表示無操作
3.2 binder線程第二次調用 binder_ioctl
3.1 節,mOut已經寫完數據了,
這里write_size=0, read_size 依然是 256,
只不過第二次進入binder_ioctl后, binder_thread->looper已經沒有了BINDER_LOOPER_STATE_NEED_RETURN
所以binder_has_proc_work就會返回false, 然后binder線程就這樣一直阻塞式的阻塞了。
整個過程如下
四、Server端的binder線程是怎么被喚醒的呢?
由第三節知道 Server端的binder線程一直阻塞在 binder_thread_read 這個函數的中的, 也就是
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
注意wait_event_freezable_exclusive
是一個排他的等待隊列,當喚醒該等待隊列時,只會喚醒第一個。
對應的binder線程要被喚醒,那么就找下哪里 wake up了 proc->wait就知道了。
下面來看幾種正常的情況
4.1 被其它進程(binder_proc)喚醒
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
...
if (target_thread) { //一般這里為false
e->to_thread = target_thread->pid;
target_list = &target_thread->todo;
target_wait = &target_thread->wait;
} else { //取得的是進程上的todo等待列表
target_list = &target_proc->todo;
target_wait = &target_proc->wait;
}
...
list_add_tail(&t->work.entry, target_list);
if (target_wait) //喚醒
wake_up_interruptible(target_wait);
...
}
當client進程需要獲得server端的服務時,如調用一個"server端的API函數", 最終binder驅動會找到server的binder_proc,也就是代碼中的target_proc, 接著client將要請求server的相關數據加入到server的等待隊列中,也就是target_list, 最后通過wake_up_interruptible喚醒server線程來處理client的請求。
注意,這里只會喚醒一個binder線程(因為睡眠時是wait_event_freezable_exclusive)
4.2 被自己喚醒
4.1節會喚醒一個binder線程去執行客戶端的請求,來看下server端客戶線程會喚醒后做了什么操作
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg, struct binder_thread *thread)
{
...
if (bwr.write_size > 0) {
...
}
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);
}
...
}
當server有一個binder線程被喚醒了,這時binder線程就會返回到用戶態去執行相關操作,在返回之前, binder線程又會檢查是否現在binder驅動比較繁忙,也就是是否還有其它的客戶端請求,如果還有,那么當前binder線程觸發喚醒server進程上的等待的其它binder線程。
也就是說,當有binder線程被喚醒時,binder線程就可能會喚醒其它的binder線程盡量將當前等待著的請求執行完。
4.3 binder死亡通知
如linkToDeath, 這里不討論這種情況。
五、client是怎么找到server端在binder驅動中的binder_proc的呢?
在4.1節binder_transaction,client通過找到target_proc,然后就喚醒了server端的binder線程,那么這個target_proc是怎么來的呢?
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
struct binder_proc *target_proc;
if (reply) { //reply在 BC_TRANACTION時為false
} else { //進入else分支
if (tr->target.handle) { //如果handle不為0,則進入下面的分支
struct binder_ref *ref;
ref = binder_get_ref(proc, tr->target.handle, true);
//通過handle在當前binder_proc中獲得target的binder_ref, 也就是binder_node的引用
target_node = ref->node; //通過引用獲得target binder node
} else { //如果handle為0的話進入else分支
target_node = binder_context_mgr_node; //這個是固定的ServiceManager
}
target_proc = target_node->proc;
}
if (target_thread) {
} else {
target_list = &target_proc->todo;
target_wait = &target_proc->wait;
}
...
}
哦,原來是通過 handle 這個整形數來獲得的target binder proc. 那這個handle又是什么呢? 從上面看出是binder_transaction_data里面的handle,
而整個transact傳遞流程如下
從代碼上來看
status_t BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
這個handle是BpBinder里的mHandle,
那么問題來了,BpBinder里的mHandle又是怎么初始化的呢