四問binder

如果帶著問題去學(xué)習(xí)binder又是怎樣的呢?

1. 第一個(gè)binder線程 Binder:PID_1是怎樣創(chuàng)建的

在App進(jìn)程創(chuàng)建的時(shí)候

nativeZygoteInit
  -> com_android_internal_os_RuntimeInit_nativeZygoteInit
    -> onZygoteInit
      -> ProcessState 
        -> startThreadPool()
          -> spawnPooledThread(true)

isMain=true

void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        String8 name = makeBinderThreadName(); //這里是第一個(gè)binder 線程,也就是binder主線程
        sp<Thread> t = new PoolThread(isMain);  //生成一個(gè)線程
        t->run(name.string());  //線程運(yùn)行,不停的調(diào)用theadLoop
    }   
}
virtual bool threadLoop()
{
    IPCThreadState* ptr = IPCThreadState::self();
    if (ptr) {
        ptr->joinThreadPool(mIsMain);
    }
    return false; //threadLoop返回false表示會(huì)退出線程,即線程結(jié)束了
}
void IPCThreadState::joinThreadPool(bool isMain)
{
    // mOut是寫入內(nèi)核的數(shù)據(jù),如果是Main Binder線程,則發(fā)送 BC_ENTER_LOOPER
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
       
    status_t result;
    do {
        processPendingDerefs(); //處理引用計(jì)數(shù)
        result = getAndExecuteCommand(); //獲得命令并執(zhí)行

        //異常退出
        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驅(qū)動(dòng) 線程要退出了
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}

binder_thread_write 中會(huì)有對 BC_ENTER_LOOPER的處理, 如下所示,thread是指binder_thread,也就是當(dāng)前線程的描述符, 將BINDER_LOOPER_STATE_ENTERED保存到 binder_thread的looper變量里.

looper變量主要保存的binder線程的一種狀態(tài)如

  • BINDER_LOOPER_STATE_REGISTERED
    標(biāo)記該binder線程是非主binder線程
  • BINDER_LOOPER_STATE_ENTERED
    標(biāo)記該binder線程是主binder線程
  • BINDER_LOOPER_STATE_EXITED
    標(biāo)記該binder線程馬上就要退出了
  • BINDER_LOOPER_STATE_INVALID
    標(biāo)記是無效的,但是這個(gè)并沒有實(shí)際用處,一般是 原來是主線程,然后用戶態(tài)又通過主線程發(fā)送了BC_REGISTER_LOOPER,就會(huì)標(biāo)志 INVALID, 同理與REGISTER一樣
  • BINDER_LOOPER_STATE_WAITING
    標(biāo)記當(dāng)前binder線程正在等著client的請求
  • BINDER_LOOPER_STATE_NEED_RETURN
    這個(gè)標(biāo)志,是當(dāng)前新線程下來在生成binder_thread里置位的,表示該binder線程在處理完transaction后需要返回到用戶態(tài)。
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就是創(chuàng)建APP進(jìn)程的binder線程池模型, 它也會(huì)創(chuàng)建第一個(gè)binder主線程,該線程不會(huì)退出(非 critcal錯(cuò)誤),而spawnPooledThread函數(shù)用于創(chuàng)建一個(gè)普通的binder線程,這些線程都有可能會(huì)退出。

二、 一個(gè)APP里最多能有多少個(gè)binder線程呢? 其它binder線程是怎么創(chuàng)建的,由誰創(chuàng)建的呢?

從第一節(jié)可知,只要調(diào)用 spawnPooledThread()函數(shù)就創(chuàng)建了一個(gè)binder線程,因此從代碼上來看除了第一個(gè)主binder線程由APP用戶態(tài)主動(dòng)創(chuàng)建外,其它的都是由Binder驅(qū)動(dòng)主動(dòng)向APP申請創(chuàng)建,也就是說binder線程的創(chuàng)建是看binder驅(qū)動(dòng)是否很繁忙(這里的繁忙是與本進(jìn)程相關(guān)的),來決定是否需要向APP進(jìn)程申請創(chuàng)建,也就是APP進(jìn)程被動(dòng)創(chuàng)建。

2.1 Server端

其實(shí)也很好理解,binder最終的通信包括client和server雙方。server方并不知道什么時(shí)候會(huì)有client的請求,client的有請求,它就直接丟給binder驅(qū)動(dòng),然后由binder驅(qū)動(dòng)根據(jù)當(dāng)前server的能力(是否有多余線程去處理)去看下是否需要新的線程來處理client的請求。

那試問一個(gè) Server端 App 最多同時(shí)能跑多少個(gè)binder線程呢?

這個(gè)問題,可以簡單的測試一下,寫一個(gè)Service, 然后實(shí)現(xiàn)一個(gè)API里死循環(huán)sleep, 反正就是不返回, 另一個(gè)client在創(chuàng)建多個(gè)非UI線程去請求API, 然后再dump出來,就知道最多支持多少個(gè)binder線程了。

我們從 spawnPooledThread的調(diào)用函數(shù)來看就知道能有多少個(gè)binder線程了。

IPCThreadState::executeCommand(int32_t cmd) {
    case BR_SPAWN_LOOPER:
        mProcess->spawnPooledThread(false); 
        break;
}

executeCommand函數(shù)執(zhí)行從Binder 驅(qū)動(dòng)傳遞到 BR_SPAWN_LOOPER, 這時(shí)就得繼續(xù)從binder驅(qū)動(dòng)中去找 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調(diào)用的最后,就會(huì)有可能去spawn一個(gè)線程, 但是也是有條件的, 且要同時(shí)滿足才行

  1. binder_proc -> ready_threads = 0
    ready_threads表明當(dāng)前進(jìn)程中還沒有準(zhǔn)備好的線程, 換句話說,當(dāng)前binder線程都有各自的任務(wù)在處理, 沒空接受新的任務(wù)了。

  2. binder_proc -> requested_threads = 0
    如果 reqeusted_threads >0 表明 binder_driver已經(jīng)通過其它binder線程請求APP進(jìn)程去創(chuàng)建binder線程來處理任務(wù)的路上了, 所以啊,binder驅(qū)動(dòng)就不會(huì)再通知一次了,因?yàn)槿绻偻ㄖ淮?,那么就?huì)創(chuàng)建兩個(gè)binder線程,資源浪費(fèi)嘛。
    所以如果 requested_threads = 0,如果其它條件滿足,那就由我這個(gè)binder線程就請求APP去創(chuàng)建另一個(gè)binder線程

  3. proc->requested_threads_started < proc->max_threads
    max_threads: 這個(gè)是APP進(jìn)程通知binder驅(qū)動(dòng)我這個(gè)APP進(jìn)程當(dāng)前最多只能創(chuàng)建max_threads個(gè)線程,如果我已經(jīng)創(chuàng)建這么多了,不要再通知我去創(chuàng)建了。至于別人(其它APP)想要獲得我的服務(wù)或其它,別急,取號等著,等著我的binder線程不忙了再去處理。

  4. thread->looper & (BINDER_LOOPER_STATE_REGISTERED |BINDER_LOOPER_STATE_ENTERED
    looper保存著當(dāng)前線程的一些狀態(tài),BINDER_LOOPER_STATE_REGISTERED(非主Binder線程)|BINDER_LOOPER_STATE_ENTERED(主binder線程) 這兩個(gè)是binder線程的標(biāo)志. 即: Binder驅(qū)動(dòng)只有通過我的APP創(chuàng)建的(有效的)binder線程才有資格向我(APP)提出創(chuàng)建其它binder線程.

好了,上面4個(gè)條件同時(shí)滿足了,就通知APP創(chuàng)建一個(gè)新的 binder線程了。

但還有幾個(gè)問題

  1. binder_proc->max_threads最大是多少呢?
    在ProcessState.cpp的 open_driver 函數(shù)中, 會(huì)設(shè)置一個(gè)默認(rèn)的最大binder線程數(shù) DEFAULT_MAX_BINDER_THREADS = 15;
    但是BinderInternal.java也提供了setMaxThreads去修改Binder驅(qū)動(dòng)中的max_threads值. 比如system_server就設(shè)置了max_threads為31
    注意 : BinderInternal是internal的類,APP不能直接調(diào)用。

  2. ready_threads 這個(gè)是什么意思呢?
    binder_thread_read 函數(shù)中

static int binder_thread_read(..) {
    //wait_for_proc_work表示是否需要去等著proc的任務(wù),當(dāng)然前提是這個(gè)binder線程沒有任務(wù)可做了,
    //那這個(gè)binder線程就可以向進(jìn)程申請去處理進(jìn)程的其它任務(wù)了
    wait_for_proc_work = thread->transaction_stack == NULL &&
                list_empty(&thread->todo);
    if (wait_for_proc_work)
        proc->ready_threads++;  //表明當(dāng)前進(jìn)程又多了一個(gè)可用的binder線程去接受任務(wù)了

    if (wait_for_proc_work) {
            //等著整個(gè)進(jìn)程的任務(wù)
            ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
    } else {
            //等著binder線程本身的任務(wù)
            ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
    }
    ...
    //代碼運(yùn)行到這里就表明有任務(wù)了,那么我這個(gè)binder線程就要去接受任務(wù)去做了,
    if (wait_for_proc_work)
        //既然我已經(jīng)開始去處理任務(wù)了,那么整個(gè)進(jìn)程當(dāng)前就少了我一個(gè)可用的線程啦
        proc->ready_threads--;

   ...
done:
    //決定是否再創(chuàng)建一個(gè)新的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++; //請求創(chuàng)建線程+1
        if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
            return -EFAULT;
        binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
    }
}
  1. requested_threads與requested_threads_started
    requested_threads表示要請求創(chuàng)建的線程數(shù),在上面決定創(chuàng)建binder線程后,該值會(huì)+1
    而requested_threads_started表示當(dāng)前進(jìn)程已經(jīng)啟動(dòng)吧這么多個(gè)線程,
    APP接收到創(chuàng)建新的binder線程的請求后就會(huì)調(diào)用 spawnPooledThread(false) 去創(chuàng)建一個(gè)非Main的binder線程, 而最后又會(huì)通過joinThreadPool觸發(fā)binder驅(qū)動(dòng)的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 {
                //正常情況會(huì)進(jìn)入該分支
                proc->requested_threads--;   //要請求創(chuàng)建的binder線程數(shù)減1
                proc->requested_threads_started++; //啟動(dòng)過的線程數(shù)+1
            }
            thread->looper |= BINDER_LOOPER_STATE_REGISTERED;
            break;
binder線程創(chuàng)建

2.2 client

client端作為請求端,是從用戶態(tài)下發(fā)起請求的,所以client一般是自己申請創(chuàng)建線程,然后在線程里去請求 server端的服務(wù),這里不會(huì)涉及到binder線程。

那么client就只有一個(gè)默認(rèn)的主binder線程了么?當(dāng)然不是,從2.1可知,binder驅(qū)動(dòng)會(huì)不管是server,還是client, 都會(huì)默認(rèn)有一個(gè)空閑線程,所以client的主binder線程在binder_thread_read的最后發(fā)現(xiàn)當(dāng)前沒有可ready的線程,這時(shí)就通知client端創(chuàng)建一個(gè)binder線程。所以一般client有兩個(gè)binder線程。

三、Server的binder線程阻塞在哪里了?

人第二節(jié)可知道,Server端的binder線程會(huì)一直等著client的請求,即如果沒有客戶端請求時(shí),binder線程應(yīng)該是一直阻塞著的,那么Server端等在什么地方呢?

來看下binder線程的運(yùn)行過程便可知, 第一小節(jié)已經(jīng)貼出相關(guān)代碼了, 再帖一次,

void IPCThreadState::joinThreadPool(bool isMain)
{
    // mOut是寫入內(nèi)核的數(shù)據(jù),如果是Main Binder線程,則發(fā)送 BC_ENTER_LOOPER
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
       
    status_t result;
    do {
        processPendingDerefs(); //處理引用計(jì)數(shù)
        result = getAndExecuteCommand(); //獲得命令并執(zhí)行

        //異常退出
        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驅(qū)動(dòng) 線程要退出了
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}

從joinThreadPool里,有一個(gè)getAndExecuteCommand, 來看下這個(gè)函數(shù)干了些什么吧

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驅(qū)動(dòng)返回來的BR_ 號
         ...
        result = executeCommand(cmd); //開始執(zhí)行相關(guān)命令
        ...
    }

    return result;
}

該函數(shù)很簡單,從binder驅(qū)動(dòng)里拿到client要操作的CMD, 然后調(diào)用executeCommand執(zhí)行CMD。

在看 talkWithDriver 之前,先來看下 binder_write_read

binder_write_read

binder_write_read是一個(gè)結(jié)構(gòu)體,它主要作用是告訴binder驅(qū)動(dòng)我這次請求的目的是什么,一是read, 另一個(gè)就是write,

  • write_size > 0 表明需要往binder驅(qū)動(dòng)寫write_buffer的數(shù)據(jù)
  • read_size >0 表明需要往binder驅(qū)動(dòng)讀數(shù)據(jù)放到write_buffer的數(shù)據(jù)
  • write_consumed 表明已經(jīng)寫入了多少字節(jié)
  • read_consumed 表明讀入了多少字節(jié)
  • write_buffer 指向用戶態(tài)下的數(shù)據(jù)地址,其實(shí)也就是IPCThreadState里的mOut (Parcel)里的mData地址
  • read_buffer 指向用戶態(tài)下的數(shù)據(jù)地址,其實(shí)也就是IPCThreadState里的mIn (Parcel)里的mData地址
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    binder_write_read bwr; 
    
    //mIn.dataPosition()是當(dāng)前mIn中mData的指針,
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();
    //doReceive默認(rèn)為true, needRead為true表明還需要從Binder驅(qū)動(dòng)中讀取數(shù)據(jù),這時(shí)候就不能往binder驅(qū)動(dòng)中寫數(shù)據(jù)
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0; 
    //填充寫數(shù)據(jù)的相關(guān)字段
    bwr.write_size = outAvail;
    bwr.write_buffer = (uintptr_t)mOut.data();

    // This is what we'll read.
    if (doReceive && needRead) {
        //填充讀數(shù)據(jù)相關(guān)字段
        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__)
        //阻塞式的調(diào)用 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) {
            //根據(jù)寫了多少數(shù)據(jù),來更新mOut的相關(guān)數(shù)據(jù)
            if (bwr.write_consumed < mOut.dataSize())
                mOut.remove(0, bwr.write_consumed);
            else
                mOut.setDataSize(0);
        }
        if (bwr.read_consumed > 0) {
            //根據(jù)讀了多少數(shù)據(jù),來更新mIn的相關(guān)數(shù)據(jù)
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0);
        }
        return NO_ERROR;
    }
        
    return err;
}

3.1 binder線程第一次調(diào)用 binder_ioctl

我們來看下binder線程創(chuàng)建后第一次調(diào)用 binder_ioctl 的情況
從joinThreadPool可以看出, 會(huì)寫入一個(gè) BC_REGISTER_LOOPER

mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);

因此此時(shí)binder_write_read的結(jié)構(gòu)如下所示

binder_write_read

來看下binder驅(qū)動(dòng)是怎么處理的呢

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    // binder_stop_on_user_error默認(rèn)為0,只有條件為false的時(shí)候才會(huì)一直block在這,所以這里并不會(huì)block
    ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
    binder_lock(__func__);
    //創(chuàng)建一個(gè)與binder線程相關(guān)的binder_thread,  第一次創(chuàng)建會(huì)設(shè)置thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN
    thread = binder_get_thread(proc);

    switch (cmd) {
    case BINDER_WRITE_READ: //執(zhí)行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這個(gè)非常重要,就是這個(gè)標(biāo)志,決定了binder線程第一次的走向,如果是第一次進(jìn)來, binder_thread->looper都設(shè)置了該標(biāo)志,而該binder_ioctl返回時(shí),會(huì)將該標(biāo)志取消

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;
    //獲得用戶態(tài)的 binder_write_read
    if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }

    if (bwr.write_size > 0) {
        //有數(shù)據(jù)要寫入,這里就是 BC_REGISTER_LOOPER
        ret = binder_thread_write(proc, thread,  bwr.write_buffer,
                      bwr.write_size, &bwr.write_consumed);
    }
    if (bwr.read_size > 0) {
        //有數(shù)據(jù)要讀取
        ret = binder_thread_read(proc, thread, bwr.read_buffer,
                     bwr.read_size,  &bwr.read_consumed,  filp->f_flags & O_NONBLOCK);
        //如果進(jìn)程描述結(jié)構(gòu)體中有任務(wù)要做時(shí),喚醒等在binder_proc->wait的列表
        if (!list_empty(&proc->todo))
            wake_up_interruptible(&proc->wait);
    }
    //將數(shù)據(jù)拷貝到用戶態(tài)
    if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
    }
out:
    return ret;
}

binder線程第一次調(diào)用binder_ioctl也就是寫入一個(gè)BC_REGISTER_LOOPER, 所以 binder_thread_write只是將binder_thread->looper設(shè)置一個(gè)BINDER_LOOPER_STATE_REGISTERED

現(xiàn)在來看下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;

    //第一次進(jìn)來 consumed為0,所以進(jìn)入該分支, 會(huì)返回一個(gè) BR_NOOP
    if (*consumed == 0) {
        if (put_user(BR_NOOP, (uint32_t __user *)ptr)) return -EFAULT;
        ptr += sizeof(uint32_t);
    }

retry:
    //binder線程第一次進(jìn)來,沒有transaction任務(wù),也沒有其它任務(wù),所以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) { //進(jìn)入該分支
        if (non_block) {
            if (!binder_has_proc_work(proc, thread))
                ret = -EAGAIN;
        } else
            //如果binder_has_proc_work為false,將會(huì)一直等在這里,直到被喚醒
            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--; //線程接收到任務(wù),準(zhǔn)備執(zhí)行了
    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ù)
            w = list_first_entry(&thread->todo, struct binder_work, entry);
        } else if (!list_empty(&proc->todo) && wait_for_proc_work) { //無任務(wù)
            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:
       
    //決定是否要向用戶態(tài)申請創(chuàng)建一個(gè)新的線程
    *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));
現(xiàn)在來看下wait_event_freezable_exclusive, 該函數(shù)的條件如果為true,即表明binder有任務(wù)時(shí),就不會(huì)阻塞,而是直接執(zhí)行,binder線程第一次進(jìn)來的時(shí)候(因?yàn)閎inder線程的創(chuàng)建是防止后續(xù)有請求到來,所以當(dāng)前是沒有任務(wù)的), 當(dāng)前沒有任務(wù)的話,binder線程應(yīng)該一直等著呀,為什么這里沒有阻塞式的等呢?

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會(huì)判斷如果binder線程是第一次進(jìn)來的話,也就是設(shè)置了BINDER_LOOPER_STATE_NEED_RETURN,也就是表明該線程不管你有沒有任務(wù),我都需要返回到用戶態(tài),所以這里為true, 也就不會(huì)等待了。

所以第一次返回給用戶態(tài)時(shí),只返回一個(gè) BR_NOOP, 表示無操作

3.2 binder線程第二次調(diào)用 binder_ioctl

3.1 節(jié),mOut已經(jīng)寫完數(shù)據(jù)了,

binder_write_buf

這里write_size=0, read_size 依然是 256,

只不過第二次進(jìn)入binder_ioctl后, binder_thread->looper已經(jīng)沒有了BINDER_LOOPER_STATE_NEED_RETURN
所以binder_has_proc_work就會(huì)返回false, 然后binder線程就這樣一直阻塞式的阻塞了。

整個(gè)過程如下

binder線程阻塞

四、Server端的binder線程是怎么被喚醒的呢?

由第三節(jié)知道 Server端的binder線程一直阻塞在 binder_thread_read 這個(gè)函數(shù)的中的, 也就是

ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));

注意wait_event_freezable_exclusive是一個(gè)排他的等待隊(duì)列,當(dāng)喚醒該等待隊(duì)列時(shí),只會(huì)喚醒第一個(gè)。

對應(yīng)的binder線程要被喚醒,那么就找下哪里 wake up了 proc->wait就知道了。

下面來看幾種正常的情況

4.1 被其它進(jìn)程(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 { //取得的是進(jìn)程上的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);  
    ...
}

當(dāng)client進(jìn)程需要獲得server端的服務(wù)時(shí),如調(diào)用一個(gè)"server端的API函數(shù)", 最終binder驅(qū)動(dòng)會(huì)找到server的binder_proc,也就是代碼中的target_proc, 接著client將要請求server的相關(guān)數(shù)據(jù)加入到server的等待隊(duì)列中,也就是target_list, 最后通過wake_up_interruptible喚醒server線程來處理client的請求。

binder線程的喚醒

注意,這里只會(huì)喚醒一個(gè)binder線程(因?yàn)樗邥r(shí)是wait_event_freezable_exclusive)

4.2 被自己喚醒

4.1節(jié)會(huì)喚醒一個(gè)binder線程去執(zhí)行客戶端的請求,來看下server端客戶線程會(huì)喚醒后做了什么操作

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);
    }
    ...
}

當(dāng)server有一個(gè)binder線程被喚醒了,這時(shí)binder線程就會(huì)返回到用戶態(tài)去執(zhí)行相關(guān)操作,在返回之前, binder線程又會(huì)檢查是否現(xiàn)在binder驅(qū)動(dòng)比較繁忙,也就是是否還有其它的客戶端請求,如果還有,那么當(dāng)前binder線程觸發(fā)喚醒server進(jìn)程上的等待的其它binder線程。
也就是說,當(dāng)有binder線程被喚醒時(shí),binder線程就可能會(huì)喚醒其它的binder線程盡量將當(dāng)前等待著的請求執(zhí)行完。

4.3 binder死亡通知

如linkToDeath, 這里不討論這種情況。

五、client是怎么找到server端在binder驅(qū)動(dòng)中的binder_proc的呢?

在4.1節(jié)binder_transaction,client通過找到target_proc,然后就喚醒了server端的binder線程,那么這個(gè)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時(shí)為false
    } else { //進(jìn)入else分支
        if (tr->target.handle) { //如果handle不為0,則進(jìn)入下面的分支
            struct binder_ref *ref;
            ref = binder_get_ref(proc, tr->target.handle, true);
            //通過handle在當(dāng)前binder_proc中獲得target的binder_ref, 也就是binder_node的引用
            target_node = ref->node; //通過引用獲得target binder node
        } else { //如果handle為0的話進(jìn)入else分支
            target_node = binder_context_mgr_node; //這個(gè)是固定的ServiceManager
        }
        target_proc = target_node->proc;
    }
    if (target_thread) {
    } else {
        target_list = &target_proc->todo;
        target_wait = &target_proc->wait;
    }
    ...
}

哦,原來是通過 handle 這個(gè)整形數(shù)來獲得的target binder proc. 那這個(gè)handle又是什么呢? 從上面看出是binder_transaction_data里面的handle,

binder_transaction_data

而整個(gè)transact傳遞流程如下

BpBinder 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;
}

這個(gè)handle是BpBinder里的mHandle,

那么問題來了,BpBinder里的mHandle又是怎么初始化的呢

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容