IPC機制(五)——Binder原理分析(一)

跟著《Android藝術(shù)開發(fā)探索》一書學(xué)習(xí)了android中的進(jìn)程間通信,剛好和最近學(xué)習(xí)操作系統(tǒng)的進(jìn)程間通信做了比較。

android的IPC主要就是基于Binder,Messenger、ContentProvider的底層都是基于Binder。所以這篇文章主要分析一下Binder的底層實現(xiàn)。

Binder

Linux下的進(jìn)程間通信

Linux跨進(jìn)程通信涉及到一些基本概念:

  • 進(jìn)程間隔離

進(jìn)程與進(jìn)程間內(nèi)存是不共享的。兩個進(jìn)程就像兩個平行的世界,A進(jìn)程無法訪問B進(jìn)程的數(shù)據(jù),B也無法訪問A。兩個進(jìn)程間要進(jìn)行數(shù)據(jù)交互需采用特殊的通信機制:進(jìn)程間通信(IPC)。

  • 進(jìn)程空間劃分:用戶空間(User Space)/內(nèi)核空間(Kernel Space)

現(xiàn)在的操作系統(tǒng)采用的都是虛擬存儲技術(shù)。對32位系統(tǒng)而言,它的虛擬存儲空間是2^32,就是4GB。操作系統(tǒng)的核心是內(nèi)核,獨立于普通的應(yīng)用程序,可以訪問受保護(hù)的內(nèi)存空間,也可以訪問底層硬件設(shè)備的權(quán)限。為保護(hù)用戶進(jìn)程不能直接操作內(nèi)核,保證內(nèi)核的安全,操作系統(tǒng)從邏輯上將虛擬空間劃分為用戶空間和內(nèi)核空間。

  • 系統(tǒng)調(diào)用:用戶態(tài)/內(nèi)核態(tài)
    雖然劃分了用戶空間和內(nèi)核空間,但是用戶在某些情況下需要訪問內(nèi)核資源(文件操作等)。這時候就需要借助系統(tǒng)調(diào)用。

當(dāng)一個進(jìn)程執(zhí)行系統(tǒng)調(diào)用而陷入內(nèi)核代碼中執(zhí)行時,稱此進(jìn)程處于內(nèi)核態(tài);當(dāng)進(jìn)程在執(zhí)行用戶自己的代碼的時候,稱進(jìn)程處于用戶態(tài)

系統(tǒng)調(diào)用主要下面兩個函數(shù)實現(xiàn):

copy_from_user()//將數(shù)據(jù)從用戶空間拷貝到內(nèi)核空間
copy_to_user()//將數(shù)據(jù)從內(nèi)核空間拷貝到用戶空間
image

從上圖可以看到傳統(tǒng)的IPC通信存在兩個問題

  1. 一次數(shù)據(jù)傳遞需要經(jīng)過兩次拷貝:內(nèi)存緩存區(qū)-->內(nèi)核緩存區(qū)-->內(nèi)存緩存區(qū)
  2. 浪費空間和時間:接收區(qū)的緩存區(qū)由數(shù)據(jù)接收進(jìn)程提供,但接收進(jìn)程并不知道要多大的空間來存放傳遞過來的數(shù)據(jù)。

Binder下的進(jìn)程間通信

Binder通信采用C/S架構(gòu),包含Client、Server、ServiceManager以及Binder驅(qū)動。其中ServiceManager用于管理系統(tǒng)中的各種服務(wù)。架構(gòu)圖如下:


image

從圖中可以看到注冊服務(wù)和獲取服務(wù)都需要ServiceManager,這里的ServiceManager是Native層的(C++),不是framework層的ServiceManager(java)。SericeManager是Binder機制中的大管家,是android進(jìn)程間通信的守護(hù)進(jìn)程??聪聢D中標(biāo)出的三大步驟:

  1. 注冊服務(wù)(addService):Server進(jìn)程要先注冊服務(wù)到ServiceManager。該過程:Server是客戶端,ServiceManager是服務(wù)端。
  2. 獲取服務(wù)(getService):Client進(jìn)程使用某個Service之前,必須向ServiceManager中獲取相應(yīng)的Service。該過程:Client是客戶端,ServiceManager是服務(wù)端。
  3. 使用服務(wù):Client根據(jù)得到的Service信息建立與Service所在的Server進(jìn)程的通路,之后就可以與Service進(jìn)行交互。該過程:Client是客戶端,Server是服務(wù)端。
  4. 最重要的一點是,三者的交互都是基于Binder通信的,通過任意兩者的關(guān)系都可以揭示Binder的奧秘。

圖中Client、Server、ServiceManager彼此之間不是直接交互,而是通過Binder驅(qū)動進(jìn)行交互,實現(xiàn)IPC方式。Binder驅(qū)動位于內(nèi)核空間,它們都位于用戶空間。

Binder Driver

注冊服務(wù)和獲取服務(wù)都基于ServiceManager,也就是需要獲取ServiceManager,獲取之前需要啟動ServiceManager,最終會調(diào)用底層Binder驅(qū)動。所以先從Binder的底層驅(qū)動看起。

Binder驅(qū)動底層的驅(qū)動架構(gòu)和Linux驅(qū)動一樣,Binder驅(qū)動在以misc設(shè)備(Linux的一種雜項特殊字符設(shè)備),作為虛擬字符設(shè)備,沒有直接操作硬件,只是對設(shè)備內(nèi)存的處理。Binder驅(qū)動設(shè)備的初始化(binder_init),打開(binder_open),映射(binder_mmap),數(shù)據(jù)操作(binder_ioctl)。

用戶態(tài)程序調(diào)用內(nèi)核層程序需要陷入內(nèi)核態(tài),會進(jìn)行系統(tǒng)調(diào)用(syscall),例如:打開Binder驅(qū)動方法的調(diào)用鏈為open()-->_open()-->binder_open()。open()為用戶態(tài)方法,_open()是系統(tǒng)調(diào)用,通過查找對應(yīng)調(diào)用到內(nèi)核binder驅(qū)動的binder_open()方法。下面從四個方法來看binder驅(qū)動:

binder_init

注冊字符驅(qū)動設(shè)備misc

binder_open

打開binder驅(qū)動設(shè)備。這里會創(chuàng)建binder_proc對象,也就是binder進(jìn)程,為binder初始化一些信息,并把每次都創(chuàng)建的binder_proc對象加入binder_procs鏈表中。

binder_mmap

我覺得這是binder驅(qū)動的核心點,binder之所以優(yōu)于傳統(tǒng)IPC就是因為binder有內(nèi)存映射。

主要功能(分三步):

  1. 首先在內(nèi)核虛擬地址空間申請一塊和用戶虛擬內(nèi)存大小相同的內(nèi)存;
  2. 再申請1個page(頁)大小的物理內(nèi)存;
  3. 再將同一塊物理內(nèi)存分別映射到內(nèi)核虛擬地址空間和用戶虛擬內(nèi)存空間。

這樣就實現(xiàn)了用戶空間的Buffer和內(nèi)核空間的Buffer同步操作的功能。

映射的這個想的很巧妙,這使得Binder通信只需要從用戶空間復(fù)制一次信息到內(nèi)核空間就可以了。但是用戶空間怎么就通過映射讀到了數(shù)據(jù),是向HashMap那樣有一個key對應(yīng)這么,通過下面這張圖可以看到:

image

虛擬進(jìn)程地址空間和虛擬內(nèi)核地址空間都映射到同一塊物理內(nèi)存。當(dāng)client端向server端發(fā)送數(shù)據(jù)時,client把自己進(jìn)程空間的通信數(shù)據(jù)拷貝(copy_from_user)到內(nèi)核空間,server端和內(nèi)核共享數(shù)據(jù),不需要再拷貝數(shù)據(jù)。通過內(nèi)存地址的偏移量獲得內(nèi)存地址(這里有點像今天剛上課聽的微機原理里的尋址方法,感覺很有意思),只發(fā)生了一次拷貝。

binder_ioctl

從上面的ServiceManager交互的圖中我們可以看到Client和Server實際上是通過ioctl和driver交互的。

binder_ioctl()函數(shù)負(fù)責(zé)在兩個進(jìn)程間收發(fā)IPC數(shù)據(jù)。這就可以對應(yīng)到之前寫過的Binder通信的文件。我們將數(shù)據(jù)放入輸入型Parcel _data,用輸出型Parcel _reply接收服務(wù)端返回的數(shù)據(jù)。執(zhí)行ioctl操作時,read_buffer需要持有binder_main_lock同步鎖,并處于wait_event_freezable過程,等有數(shù)據(jù)到來是則喚醒并嘗試持有同步鎖。

ServiceManager

分析完了驅(qū)動層知道了驅(qū)動層是怎么被初始化 打開 被分配內(nèi)存。就需要再進(jìn)一步了解ServiceManager,ServiceManager作為大管家這里主要分析它的啟動以及注冊、查詢服務(wù),如何和binder驅(qū)動建立聯(lián)系。

ServiceManager自行編寫了binder.c直接和binder驅(qū)動進(jìn)行通信,并且只有一個循環(huán)binder_lopp來進(jìn)行讀取和處理事務(wù)。其本身工作相對簡單,主要功能就是查詢和注冊服務(wù)。Binder IPC通信過程中,其實是BpBinder和BBinder之間的通信,后面會介紹到。

這里有一張別人畫的ServiceManager從創(chuàng)建到實現(xiàn)自己功能的時序圖,我覺得對從整體來把握ServiceManager有一定的幫助和統(tǒng)領(lǐng)的作用。

image

ServiceManager啟動過程

參照時序圖,啟動過程主要分為以下幾個階段:

  1. 打開binder驅(qū)動:binder_open;
  2. 注冊成為binder服務(wù)的大管家:binder_become_context_manager;
  3. 進(jìn)入無線循環(huán),處理client端發(fā)來的請求:binder_loop。

ServiceManager是由init進(jìn)程通過解析init.rc文件而創(chuàng)建的。啟動ServiceManager的入口函數(shù)是service_manager.c中的main()方法,代碼如下:

main

int main(int argc, char **argv) {
    struct binder_state *bs;
    //BINDER_SERVICE_MANAGER值為null,用來標(biāo)志文件的格式
    void *svcmgr = BINDER_SERVICE_MANAGER;
    //打開binder驅(qū)動,申請大小為128KB字節(jié)大小的內(nèi)存空間
    bs = binder_open(128*1024);
    //成為manager(上下文管理者)
    if (binder_become_context_manager(bs)) {
        return -1;
    }
    //進(jìn)入無限循環(huán)狀態(tài),處理client端發(fā)來的請求
    binder_loop(bs, svcmgr_handler);
    return 0;
}

binder_open

struct binder_state *binder_open(size_t mapsize)
{
    struct binder_state *bs;【見小節(jié)2.2.1】
    struct binder_version vers;

    bs = malloc(sizeof(*bs));
    if (!bs) {
        errno = ENOMEM;
        return NULL;
    }

    ````

    bs->mapsize = mapsize;
    //通過系統(tǒng)調(diào)用,mmap內(nèi)存映射,mmap必須是page的整數(shù)倍
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
    if (bs->mapped == MAP_FAILED) {
        goto fail_map; // binder設(shè)備內(nèi)存無法映射
    }

    return bs;
    `````
}

binder_open主要就是打開驅(qū)動設(shè)備,系統(tǒng)調(diào)用mmap內(nèi)存映射。

binder_become_context_manager

int binder_become_context_manager(struct binder_state *bs)
{
    //0是設(shè)置的handle,BINDER_SET_CONTEXT_MGR設(shè)置ServiceManager結(jié)點
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}

binder_ioctl

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {
    binder_lock(__func__);
    switch (cmd) {
      case BINDER_SET_CONTEXT_MGR:
          ret = binder_ioctl_set_ctx_mgr(filp);
          break;
      }
      case :...
    }
    binder_unlock(__func__);
}

根據(jù)參數(shù)BINDER_SET_CONTEXT_MGR,最終調(diào)用binder_ioctl_set_ctx_mgr()方法,這個過程會持有binder_main_lock。

binder_ioctl_set_ctx_mgr

static int binder_ioctl_set_ctx_mgr(struct file *filp)
{
    int ret = 0;
    struct binder_proc *proc = filp->private_data;
    kuid_t curr_euid = current_euid();
    
    //保證只創(chuàng)建一次mgr_node對象
    if (binder_context_mgr_node != NULL) {
        ret = -EBUSY; 
        goto out;
    }

    if (uid_valid(binder_context_mgr_uid)) {
        ...
    } else {
        //設(shè)置當(dāng)前線程euid作為Service Manager的uid
        binder_context_mgr_uid = curr_euid;
    }

    //創(chuàng)建ServiceManager實體
    binder_context_mgr_node = binder_new_node(proc, 0, 0);
    ````
}

在這里創(chuàng)建了ServiceManager實體binder_new_node()方法中創(chuàng)建了binder_node結(jié)構(gòu)體,也就是binder實體。

binder_loop

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;
    
    //將BC_ENTER_LOOPER命令發(fā)送給binder驅(qū)動,讓Service Manager進(jìn)入循環(huán)
    //binder_write方法中調(diào)用ioctl方法,將bwr數(shù)據(jù)發(fā)送給binder驅(qū)動,調(diào)用binder_ioctl方法,獲取binder_thread,進(jìn)行binder的讀寫操作。
    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); //進(jìn)入循環(huán),不斷地binder讀寫過程
        if (res < 0) {
            break;
        }

        // 接收到請求,交給binder_parse處理
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        if (res == 0) {
            break;
        }
        if (res < 0) {
            break;
        }
    }
}

binder_parse

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){
        switch(cmd) {
        case BR_NOOP:  //無操作,退出循環(huán)
            break;
        case BR_TRANSACTION_COMPLETE:
            break;
        case BR_INCREFS:
        case BR_ACQUIRE:
        case BR_RELEASE:
        case BR_DECREFS:
            ptr += sizeof(struct binder_ptr_cookie);
            break;
        case BR_TRANSACTION: {
             `````
             //初始化reply
            bio_init(&reply, rdata, sizeof(rdata), 4);
            //從txn解析出binder_io信息
            bio_init_from_txn(&msg, txn);
            //func指向svcmgr_handler,調(diào)用svcmgr_handler
            res = func(bs, txn, &msg, &reply);
            binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
                `````
        }
        break;
        case BR_REPLY: {
             break;
        }
        case BR_DEAD_BINDER: {
            break;
        }
        case BR_FAILED_REPLY:
            r = -1;
            break;
        case BR_DEAD_REPLY:
            r = -1;
            break;
        default:
            return -1;
    }
}

這個方法在binder_loop中,用于接收請求,根據(jù)請求的類別執(zhí)行對應(yīng)的方法。

svcmgr_handler

binder_loop中傳遞的函數(shù)指針是svcmgr_handler

int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    `````
    switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE: 
        //獲取服務(wù)名
        s = bio_get_string16(msg, &len);
        //根據(jù)名稱查找相應(yīng)服務(wù),返回服務(wù)所對應(yīng)的handle
        handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
        //將handle封裝到reply
        bio_put_ref(reply, handle);
        return 0;
    case SVC_MGR_ADD_SERVICE: 
        //獲取服務(wù)名
        s = bio_get_string16(msg, &len);
        handle = bio_get_ref(msg);
        allow_isolated = bio_get_uint32(msg) ? 1 : 0;
         //注冊指定服務(wù)(檢查權(quán)限、根據(jù)名稱檢索服務(wù)、查詢到同名的釋放后保存當(dāng)前服務(wù))
        if (do_add_service(bs, s, len, handle, txn->sender_euid,allow_isolated, txn->sender_pid))
            return -1;
        break;
    //得到當(dāng)前系統(tǒng)中已經(jīng)注冊的所有的名字
    case SVC_MGR_LIST_SERVICES:
        `````
}

可以看到這個方法中:查詢服務(wù)、注冊服務(wù),以及列舉所有服務(wù)

總結(jié)

  • ServiceManager啟動流程
  1. 打開binder驅(qū)動(binder_open),調(diào)用mmap()方法分配128KB的內(nèi)存映空間;
  2. 調(diào)用binder_become_context_manager(),參數(shù)BINDER_SET_CONTEXT_MGR信號傳入ioctl()方法,調(diào)用binder_ioctl創(chuàng)建出ServiceManager實體;
  3. 調(diào)用binder_loop()方法,循環(huán)接收客戶端傳來的信息,循環(huán)讀寫操作。通過iotcl將數(shù)據(jù)發(fā)送給binder驅(qū)動(binder_loop()-->binder_write()-->iotcl()-->binder_ioctl()-->binder_iotcl_write_read()進(jìn)行數(shù)據(jù)的讀寫和將數(shù)據(jù)拷貝到用戶buf)
  4. 注冊服務(wù)、查詢服務(wù)。

獲取服務(wù)

在進(jìn)程注冊服務(wù)和獲取服務(wù)的過程之前,都需要先調(diào)用defaultServiceManager()方法來獲取getDefaultServiceManager對象。

defaultServiceManager

sp<IServiceManager> defaultServiceManager()
{
    if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
    {
        AutoMutex _l(gDefaultServiceManagerLock); //加鎖
        while (gDefaultServiceManager == NULL) {
            //創(chuàng)建真正的gDefaultServiceManager
            gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(NULL));
            if (gDefaultServiceManager == NULL)
                sleep(1);
        }
    }
    return gDefaultServiceManager;
}

獲取ServiceManager對象采用了單例模式。很有意思的一點的事,ggDefaultServiceManager是在一個循環(huán)中被創(chuàng)建的。這是因為當(dāng)獲取ServiceManager時,ServiceManager可能還未準(zhǔn)備就緒,因此通過sleep 1s,通過循環(huán)嘗試直到成功。

getDefaultServiceManager分為下面三個步驟:

  1. ProcessState::self():用于獲取ProcessState對象;
  2. getContextObject():用于獲取BpBinder對象;
  3. interface_cast<IServiceManager>:用于獲取BpServiceManager對象。

獨一無二的ProcessState

每個進(jìn)程只有一個ProcessState。

ProcessState::self

sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }

    //實例化ProcessState
    gProcess = new ProcessState;
    return gProcess;
}

獲取ProcessState對象也采用單例模式,保證了每個進(jìn)程只有一個ProcessState對象。其中g(shù)Process和gProcessMuted保存在static.c類的全局變量。

構(gòu)造ProcessState

ProcessState::ProcessState()
    : mDriverFD(open_driver())//打開binder驅(qū)動
    , mVMStart(MAP_FAILED)//映射內(nèi)存的起始地址
    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
    , mExecutingThreadsCount(0)
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{   
    //mDriverFD記錄binder驅(qū)動的fd,用于訪問binder設(shè)備
    if (mDriverFD >= 0) {
        //采用內(nèi)存映射函數(shù)mmap,給binder分配一塊虛擬地址空間,用來接收事務(wù)
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            close(mDriverFD); //沒有足夠空間分配給/dev/binder,則關(guān)閉驅(qū)動
            mDriverFD = -1;
        }
    }
}
  • 因為ProcessState單例模式的唯一性,一個進(jìn)程只能打開一個binder設(shè)備。
  • BINDER_VM_SIZE:(102410241)-(4096*2) = 1M-8K 。
  • DEFAULT_ MAX_BINDER_THREADS:binder默認(rèn)的最大可并發(fā)訪問線程數(shù)。

打開binder設(shè)備

static int open_driver(){
    int fd = open("/dev/binder",O_RDWR);
    if(fd > 0){
        `````
        size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;

        // 通過ioctl設(shè)置binder驅(qū)動,能支持的最大線程數(shù)
        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
    }
}

從這里可以從binder驅(qū)動層打開binder驅(qū)動的方式聯(lián)系起來open_driver()-->open-->binder_open()。

Process::self函數(shù)功能:

  • 打開dev/binder設(shè)備,相當(dāng)于和內(nèi)核的Binder驅(qū)動有了交互。
  • 對返回的fd使用mmap,這樣Binder驅(qū)動會分配一塊內(nèi)訓(xùn)來接收數(shù)據(jù)。
  • ProcessState具有唯一性,因此一個進(jìn)程只打開設(shè)備一次。

獲取BpBinder對象

getContextObject

繼續(xù)defaultServiceManager()中的方法

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller){
    if(supportProcess()){
        return getStrongProxyForHandle(0);
    }else{
        return getContextObject(String16("default"),caller);
    }
}
  • 該方法返回IBinder對象。
  • supportProcess():根據(jù)open_driver()函數(shù)是否可以打開來判斷設(shè)備是否支持進(jìn)程,真實設(shè)備肯定支持process,所以調(diào)用getStrongProxyForHandle函數(shù)。
  • getStrongProxyForHandle(0):它傳入的參數(shù)名叫handle,是對資源的一種標(biāo)識。也就是一個資源項放在了一個資源數(shù)組中,handle的值是該資源項在數(shù)組中的索引。

getStrongProxyForHandle

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);
    //查找handle對應(yīng)的資源項【見小節(jié)3.3】
    handle_entry* e = lookupHandleLocked(handle);

    if (e != NULL) {
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            if (handle == 0) {
                Parcel data;
                //通過ping操作測試binder是否準(zhǔn)備就緒
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }
            //當(dāng)handle值所對應(yīng)的IBinder不存在或弱引用無效時,則創(chuàng)建BpBinder對象【見小節(jié)3.4】
            b = new BpBinder(handle);
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }
    return result;
}

這個方法主要創(chuàng)建BpBinder對象。

  • lookipHandleLocked(handle):根據(jù)索引查找對應(yīng)的資源項。如果沒有,會創(chuàng)建新的資源項。
  • 對于新的資源項,其binder為空(b==null),創(chuàng)建一個BpBinder。

看到這里就會好奇到底BpBinder是干什么的。BpBinder和BBinder都是android中和Binder通信相關(guān)的代表,它們都從IBinder類中派生而來。和ServieManager交互獲取服務(wù)和注冊服務(wù)的其實是這兩個類,不是我們俗稱的客戶端和服務(wù)端。


image

從上面的圖可以看到;

  • BpBinder是客戶端用來和Server交互的代理類。
  • BBinder則是和proxy相對應(yīng)的,它是和proxy交互的對端。可以說proxy代表客戶端,BBinder代表服務(wù)端
  • BpBinder和BBinder必須是一一對應(yīng)的。Binder系統(tǒng)通過handle值來標(biāo)識對應(yīng)BBinder。在new BpBinder(handle)時傳入了0,0代表的就是ServiceManager所對應(yīng)的BBinder。

創(chuàng)建BpBinder

BpBinder::BpBinder(int32_t handle)
    : mHandle(handle)
    , mAlive(1)
    , mObitsSent(0)
    , mObituaries(NULL)
{
    extendObjectLifetime(OBJECT_LIFETIME_WEAK); 
    IPCThreadState::self()->incWeakHandle(handle); 
}

通過源碼,BpBinder、BBinder這兩個類并沒有對ProcessState打開的/dev/binder設(shè)備進(jìn)行操作,也就是他們之間沒有交互。

BpServiceManager

通過下面來看到底BpBinder為什么與通信相關(guān)。

interface_cast

依舊從defaultServiceManager方法中入手:

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}

這是一個模板函數(shù),等價于:

inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj)
{
    return IServiceManager::asInterface(obj);
}

這里又轉(zhuǎn)移到了IServiceManager中

IServiceManager

class IServiceManager : public IInterface{
public:
    //很重要的宏定義
    DECLARE_META_INTERFACE(ServiceManager);
    
    ``````
    //這里是ServiceManager提供的業(yè)務(wù)函數(shù)
    virtual sp<IBinder> getService();
    virtual sp<IBinder> checkService();
    virtual status_t addService();
    virtual Vector<String16> listServices() = 0;
    ``````
}

IServiceManager定義了ServiceManager所提供的服務(wù),這是如何和IBinder通信家族聯(lián)系在一起的。就需要宏定義。宏定義將業(yè)務(wù)和通信掛鉤,展開后的代碼如下:

const android::String16 IServiceManager::descriptor(“android.os.IServiceManager”);

//實現(xiàn)了getInterfaceDescriptor函數(shù)
const android::String16& IServiceManager::getInterfaceDescriptor() const
{
    //返回android.os.IServiceManager
     return IServiceManager::descriptor;
}

 android::sp<IServiceManager> IServiceManager::asInterface(const android::sp<android::IBinder>& obj)
{
       android::sp<IServiceManager> intr;
        if(obj != NULL) {
           intr = static_cast<IServiceManager *>(
               obj->queryLocalInterface(IServiceManager::descriptor).get());
           if (intr == NULL) {
               intr = new BpServiceManager(obj);
            }
        }
       return intr;
}

IServiceManager::IServiceManager () { }
IServiceManager::~ IServiceManager() { }
  • 實現(xiàn)了asInterface():new BpServiceManager(obj),obj是剛才創(chuàng)建出的BpBinder(0)。追溯回去,發(fā)現(xiàn)interface_cast利用BpBinder對象為參數(shù)新建了BpServiceManager對象。
gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0));

BpServiceManager實例化

創(chuàng)建BpServiceManager對象的過程,會先初始化父類對象

BpServiceManager初始化

//impl是IBinder類型
BpServiceManager(const sp<IBinder>& impl)
    : BpInterface<IServiceManager>(impl)
{    }

BpInterface初始化

inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
    :BpRefBase(remote)
{    }

BpRefBase初始化

BpRefBase::BpRefBase(const sp<IBinder>& o)
    : mRemote(o.get()), mRefs(NULL), mState(0)
{
    extendObjectLifetime(OBJECT_LIFETIME_WEAK);

    if (mRemote) {
        mRemote->incStrong(this);
        mRefs = mRemote->createWeak(this);
    }
}
  • 最終mRemote = new BpBinder(0)
  • BpBinder對象的handle值為0,和它對應(yīng)的BBinder建立一一對應(yīng);BpServiceManager對象,它的mRemote值是BpBinder。

BpServiceManager不僅實現(xiàn)了IServiceManager的業(yè)務(wù)函數(shù),還有BpBinder作為通信代表。

總結(jié)

defaultServiceManager等價于new BpServiceManager(new BpBinder(0))

ProcessState::self()主要工作:

  • 打開/dev/binder驅(qū)動設(shè)備
  • 調(diào)用mmap(),創(chuàng)建大小為1M - 8k的內(nèi)存地址空間
  • 設(shè)定當(dāng)前進(jìn)程的最大并發(fā)binder線程個數(shù)為15

ServiceManager可直接與binder驅(qū)動進(jìn)行交互。重要的還有IBinder的通信族。

BpServiceManager將通信層與業(yè)務(wù)層邏輯合為一體:

  • 通過繼承IServiceManager接口,實現(xiàn)接口中的業(yè)務(wù)邏輯函數(shù)(添加service等)
  • 通過成員變量mRemote = new BpBinder(0)進(jìn)行Binder通信工作
  • BpBinder通過handle來指向所對應(yīng)的BBinder

注冊服務(wù)

注冊服務(wù)我們通過MediaService的具體注冊過程來看

media服務(wù)注冊

int main(int argc __unused, char** argv)
{
    ...
    InitializeIcuOrDie();
    //獲得ProcessState實例對象
    sp<ProcessState> proc(ProcessState::self());
    //獲取BpServiceManager對象
    sp<IServiceManager> sm = defaultServiceManager();
    AudioFlinger::instantiate();
    //注冊多媒體服務(wù)
    MediaPlayerService::instantiate();
    ResourceManagerService::instantiate();
    CameraService::instantiate();
    AudioPolicyService::instantiate();
    SoundTriggerHwService::instantiate();
    RadioService::instantiate();
    registerExtensions();
    //啟動Binder線程池
    ProcessState::self()->startThreadPool();
    //當(dāng)前線程加入到線程池
    IPCThreadState::self()->joinThreadPool();
 }

上面是native層中media服務(wù)注冊的過程。
分別為下面幾個過程:

  • 獲取ProcessState對象
  • 獲取ServiceManager對象,也就是BpManagerService
  • 注冊服務(wù)
  • 啟動binder線程池
  • 將當(dāng)前線程加入到線程池

獲取取ProcessState對象和ServiceManager對象在上節(jié)已經(jīng)分析過,這里主要看注冊服務(wù)的過程。

業(yè)務(wù)層的工作

instantiate()

void MediaPlayerService::instantiate() {
    //注冊服務(wù)
    defaultServiceManager()->addService(String16("media.player"), new MediaPlayerService());
}

注冊服務(wù)MediaPlayerService:

  • defaultServiceManager返回BpManagerService,同時會創(chuàng)建ProcessState和BpBinder對象
  • 等價于調(diào)用BpServiceManager-->addService

BpSM.addService()

virtual status_t addService(const String16& name, const sp<IBinder>& service, bool allowIsolated) {
    Parcel data, reply; 
    //Parcel相當(dāng)于數(shù)據(jù)包,在aidl生成的文件中就出現(xiàn)過
    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());   
    data.writeString16(name);        
    data.writeStrongBinder(service); 
    data.writeInt32(allowIsolated ? 1 : 0); 
    //remote返回的就是mRemote,也就是BpBinder對象
    status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
    return err == NO_ERROR ? reply.readExceptionCode() : err;
}

可以看到,addService作為BpManagerService的業(yè)務(wù)函數(shù),把請求數(shù)據(jù)包打包成data后傳給了BpBinder的transact函數(shù)。也就是把通信的工作交給了BpBinder。

業(yè)務(wù)層的功能就是將請求數(shù)據(jù)打包,交給通信層去處理。

通信層的工作

之前在初始化BpBinder的函數(shù)中我們沒有發(fā)現(xiàn)BpBinder與binder驅(qū)動設(shè)備有任何的交互,但是在binder的體系架構(gòu)圖中客戶端確實是通過ioctl和binder驅(qū)動進(jìn)行了通信。再繼續(xù)往下看:

BpBinder::transact

status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    if (mAlive) {
        //把工作交給了IPCTHreadState
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }
    return DEAD_OBJECT;
}

BpBinder調(diào)用transact,但是真正執(zhí)行的IPCTHreadState,BpBinder相當(dāng)于一個工具,讓別人去工作,啊哈哈哈。。。

IPCTHreadState::self()

看樣子是個通信線程?

IPCThreadState* IPCThreadState::self()
{
    //第一次進(jìn)來為false
    if (gHaveTLS) {
restart:
        const pthread_key_t k = gTLS;
        //獲取TLS空間中的內(nèi)容
        IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
        if (st) return st;
        //new一個對象 構(gòu)造函數(shù)中會調(diào)用pthread_serspecific
        return new IPCThreadState;
    }

    if (gShutdown) return NULL;

    pthread_mutex_lock(&gTLSMutex);
    if (!gHaveTLS) {
        //創(chuàng)建線程的TLS
        if (pthread_key_create(&gTLS, threadDestructor) != 0) {
            pthread_mutex_unlock(&gTLSMutex);
            return NULL;
        }
        gHaveTLS = true;
    }
    pthread_mutex_unlock(&gTLSMutex);
    goto restart;
}

這個方法中:

  • gHavaTLS == true:使用pthread_getspecific獲取IPCTHreadState對象,并返回這個對象
  • gHaveTLS == false:便會創(chuàng)建線程的TLS
    TLS是Thread Local Storge(線程本地存儲空間)的簡稱。學(xué)過操作系統(tǒng)可知,這種空間每個線程都有,而且線程不共享這些空間。通過pthread_setspecific/pthread_getspecific函數(shù)可以設(shè)置/獲取這些空間中的內(nèi)容。**從線程本地存儲空間中獲得保存在其中的IPCTHreadState對象。

之前在操作系統(tǒng)課上還做過創(chuàng)建線程的實驗,pthread_create()感覺很有意思,要好好學(xué)操作系統(tǒng)呀!

IPCTHreadState::IPCTHreadState()

從上面的情況來看,我們是很有必要了解IPCTHreadState的,下面看下它的構(gòu)造函數(shù)

IPCThreadState::IPCThreadState()
    : mProcess(ProcessState::self()),
      mMyThreadId(gettid()),
      mStrictModePolicy(0),
      mLastTransactionBinderFlags(0)
{
    //在構(gòu)造函數(shù)中,把自己保存到了線程本地存儲中
    pthread_setspecific(gTLS, this);
    clearCaller();
    mIn.setDataCapacity(256);
    mOut.setDataCapacity(256);
}

可以看到:

  • 成員變量mProcess保存了ProcessState變量(每個進(jìn)程只有一個)
  • 每個線程都有一個IPCTHreadState
  • 每個IPCTHreadState都有一個mIn,mOut
    • mIn:接收來自Binder設(shè)備的數(shù)據(jù)
    • mOut:存儲發(fā)往Binder設(shè)備的數(shù)據(jù)

IPCTHreadState::transact

transact這個方法是用來提交事務(wù)的,在學(xué)習(xí)binder通信的時候,學(xué)著寫aidl文件對應(yīng)的binder通信模板代碼中就有,看看它在native層是怎么一會事。

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err = data.errorCheck(); //數(shù)據(jù)錯誤檢查
    flags |= TF_ACCEPT_FDS;
    ....
    if (err == NO_ERROR) { // 傳輸數(shù)據(jù)
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }
    ...

    if ((flags & TF_ONE_WAY) == 0) {
        if (reply) {
            //等待響應(yīng)
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }

    } else {
        //oneway,則不需要等待reply的場景
        err = waitForResponse(NULL, NULL);
    }
    return err;
}

transact事務(wù)處理三大流程:

  • errorCheck() 數(shù)據(jù)錯誤檢查
  • writeTransactionData() 傳輸數(shù)據(jù)

其中的參數(shù)BC_TRANSACTION,是應(yīng)用程序向binder設(shè)備發(fā)送消息的消息碼。binder設(shè)備向應(yīng)用程序恢復(fù)消息的消息碼以BR_開頭。

  • waitForResponse()

IPCTHreadState::writeTransactionData()

作為通信,最重要的就是傳輸數(shù)據(jù)的這一方法

status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
    int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
    //是和binder設(shè)備通信的數(shù)據(jù)結(jié)構(gòu)
    binder_transaction_data tr;
    tr.target.ptr = 0;
    tr.target.handle = handle; // handle = 0
    tr.code = code;            // code = ADD_SERVICE_TRANSACTION
    tr.flags = binderFlags;    // binderFlags = 0
    tr.cookie = 0;
    tr.sender_pid = 0;
    tr.sender_euid = 0;

    // data為記錄Media服務(wù)信息的Parcel對象
    const status_t err = data.errorCheck();
    if (err == NO_ERROR) {
        tr.data_size = data.ipcDataSize();  // mDataSize
        tr.data.ptr.buffer = data.ipcData(); //mData
        tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t); //mObjectsSize
        tr.data.ptr.offsets = data.ipcObjects(); //mObjects
    } else if (statusBuffer) {
        ...
    } else {
        return (mLastError = err);
    }

    mOut.writeInt32(cmd);         //cmd = BC_TRANSACTION
    mOut.write(&tr, sizeof(tr));  //寫入binder_transaction_data數(shù)據(jù)
    return NO_ERROR;
}

這個方法中主要就是為binder_transaction_data這個數(shù)據(jù)結(jié)構(gòu)中的內(nèi)容賦值,并將BC_TRANSACTIN命令和這個數(shù)據(jù)結(jié)構(gòu)寫入到mOut中。

  • handle值用來標(biāo)識目的端,注冊服務(wù)的目的端就是ServiceManager。在創(chuàng)建ServiceManager的方法binder_become_context_manager方法一步步往下調(diào)用的時候,有一個方法binder_ioctl_set_ctx_mgr方法創(chuàng)建了ServiceManager實體。這個實體是binder_context_mgr_node。
  • Parcel data中的重要成員變量:
    • mDataSize:binder_transaction_data的數(shù)據(jù)大小
    • mData:binder_transaction_data數(shù)據(jù)的起始地址
    • mObjectsSize:記錄flat_binder_object結(jié)構(gòu)體個數(shù)
    • mObjects:記錄flat_binder_object結(jié)構(gòu)體的數(shù)據(jù)偏移量

ICPTHreadState::waitForResponse

上面的方法是把addService的請求信息寫到mOut中,下面是發(fā)送請求的部分實現(xiàn):

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    int32_t cmd;
    int32_t err;
    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
        ...
        if (mIn.dataAvail() == 0) continue;

        cmd = mIn.readInt32();
        switch (cmd) {
            case BR_TRANSACTION_COMPLETE: ...
            case BR_DEAD_REPLY: ...
            case BR_FAILED_REPLY: ...
            case BR_ACQUIRE_RESULT: ...
            case BR_REPLY: ...
                goto finish;

            default:
                err = executeCommand(cmd);  //【見小節(jié)3.x】
                if (err != NO_ERROR) goto finish;
                break;
        }
    }
    ...
    return err;
}

這個方法主要就是在發(fā)送請求,可以看到可根據(jù)命令去執(zhí)行相應(yīng)的內(nèi)容。這里的發(fā)送請求有沒有和binder設(shè)備進(jìn)行交互呢?有一個方法talkWithDriver()意面意思就是和driver通信,還有一個方法executeCommand()。下面來看看這個方法。

ICPTHreadState::talkWithDivier

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    ...
    binder_write_read bwr;
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

    bwr.write_size = outAvail;
    bwr.write_buffer = (uintptr_t)mOut.data();

    if (doReceive && needRead) {
        //接收數(shù)據(jù)緩沖區(qū)信息的填充。如果以后收到數(shù)據(jù),就直接填在mIn中了。
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }
    //當(dāng)讀緩沖和寫緩沖都為空,則直接返回
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    do {
        //通過ioctl不停的讀寫操作,跟Binder Driver進(jìn)行通信
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        ...
    } while (err == -EINTR); //當(dāng)被中斷,則繼續(xù)執(zhí)行
    ...
    return err;
}

看到這個方法我發(fā)現(xiàn)了三個很重要的信息,能夠幫助我們梳理和divier交互的中間過程:

  • binder_write_read

這是用來和binder設(shè)備交換數(shù)據(jù)的結(jié)構(gòu)。這個結(jié)構(gòu)在看binder驅(qū)動底層讀寫數(shù)據(jù)的時候就出現(xiàn)過,當(dāng)時以為這個結(jié)構(gòu)是屬于內(nèi)核空間的。在這里發(fā)現(xiàn)這個數(shù)據(jù)結(jié)構(gòu)中有兩塊區(qū)域,一個是read_buffer,一個是write_buffer。BpBinder將從客戶端拿來的數(shù)據(jù)寫到這里。

  • ioctl()

調(diào)用這個方法進(jìn)行讀寫操作,和binder driver通信。

總結(jié)

這里注冊服務(wù)主要分析的MediaService的服務(wù)注冊,主要流程是:

  • 首先初始化ProcessState對象和BpServiceManager對象。同時也會獲得通信的BpBinder。
  • 初始化MediaServicePlayer對象,并將這個服務(wù)通過BpServiceManager的業(yè)務(wù)層函數(shù)addService將要注冊的服務(wù)加入進(jìn)去。
  • 此后BpServiceManager將請求的數(shù)據(jù)交給BpBinder處理。BpBinder調(diào)用transact方法,實則是交給了IPCTHreadState處理,也就是創(chuàng)建出了線程,線程也會創(chuàng)建自己本地存儲空間去完成Parcel數(shù)據(jù)包mOut和mIn的數(shù)據(jù)交換工作。
  • IPCTHreadState調(diào)用transact方法處理事務(wù)。將數(shù)據(jù)存入binder_transaction_data結(jié)構(gòu)中,寫入到mOut中。
  • 調(diào)用talkWidthDriver()方法,和Binder Driver通信,用binder_write_read結(jié)構(gòu)體和binder設(shè)備交換數(shù)據(jù)。

Binder Driver中的ServiceManager

從上面可以看到talkWithDriver開始和driver開始通信,調(diào)用了ioctl方法。

ioctl-->binder ioctl-->binder_ioctl_write_read

binder_ioctl_write_read

static int binder_ioctl_write_read(struct file *filp,
                unsigned int cmd, unsigned long arg,
                struct binder_thread *thread)
{
    struct binder_proc *proc = filp->private_data;
    void __user *ubuf = (void __user *)arg;
    struct binder_write_read bwr;

    //將用戶空間bwr結(jié)構(gòu)體拷貝到內(nèi)核空間
    copy_from_user(&bwr, ubuf, sizeof(bwr));
    ...

    if (bwr.write_size > 0) {
        //將數(shù)據(jù)放入目標(biāo)進(jìn)程
        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);
        if (!list_empty(&proc->todo))
            wake_up_interruptible(&proc->wait);
        ...
    }

    //將內(nèi)核空間bwr結(jié)構(gòu)體拷貝到用戶空間
    copy_to_user(ubuf, &bwr, sizeof(bwr));
    ...
}   

這個方法很經(jīng)典,在注釋中已經(jīng)把它分為了三大塊。

  • copy_from_user

將binder_write_read結(jié)構(gòu)體拷貝到用戶空間,這里面包含的是用戶地址空間的數(shù)據(jù),在我們最開始分析的時候就可以對接起來了。

  • 兩個if

write_size中存在數(shù)據(jù)就寫入目標(biāo)進(jìn)程;read_size存在數(shù)據(jù)就從隊列中讀取進(jìn)程。

  • copy_to_user

若處理失敗則需要將數(shù)據(jù)還原,在重新寫回到用戶地址空間。

binder_thread_write

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) {
        //拷貝用戶空間的cmd命令,此時為BC_TRANSACTION
        if (get_user(cmd, (uint32_t __user *)ptr)) -EFAULT;
        ptr += sizeof(uint32_t);
        switch (cmd) {
        case BC_TRANSACTION:
        case BC_REPLY: {
            struct binder_transaction_data tr;
            //拷貝用戶空間的binder_transaction_data
            if (copy_from_user(&tr, ptr, sizeof(tr)))   return -EFAULT;
            ptr += sizeof(tr);
            binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
            break;
        }
        ...
    }
    *consumed = ptr - buffer;
  }
  return 0;
}

可以看到BC_TRANSACT命令和BC_REPLY命令執(zhí)行的方法是一樣的。調(diào)用binder_transaction方法。

binder_transaction

static void binder_transaction(struct binder_proc *proc,
               struct binder_thread *thread,
               struct binder_transaction_data *tr, int reply){
    struct binder_transaction *t;
    struct binder_work *tcomplete;
    ...

    if (reply) {
        ...
    }else {
        if (tr->target.handle) {
            ...
        } else {
            // handle=0則找到servicemanager實體
            target_node = binder_context_mgr_node;
        }
        //target_proc為servicemanager進(jìn)程
        target_proc = target_node->proc;
    }

    if (target_thread) {
        ...
    } else {
        //找到servicemanager進(jìn)程的todo隊列
        target_list = &target_proc->todo;
        target_wait = &target_proc->wait;
    }

    t = kzalloc(sizeof(*t), GFP_KERNEL);
    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);

    //非oneway的通信方式,把當(dāng)前thread保存到transaction的from字段
    if (!reply && !(tr->flags & TF_ONE_WAY))
        t->from = thread;
    else
        t->from = NULL;

    t->sender_euid = task_euid(proc->tsk);
    t->to_proc = target_proc; //此次通信目標(biāo)進(jìn)程為servicemanager進(jìn)程
    t->to_thread = target_thread;
    t->code = tr->code;  //此次通信code = ADD_SERVICE_TRANSACTION
    t->flags = tr->flags;  // 此次通信flags = 0
    t->priority = task_nice(current);

    //從servicemanager進(jìn)程中分配buffer
    t->buffer = binder_alloc_buf(target_proc, tr->data_size,
        tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));

    t->buffer->allow_user_free = 0;
    t->buffer->transaction = t;
    t->buffer->target_node = target_node;

    if (target_node)
        binder_inc_node(target_node, 1, 0, NULL); //引用計數(shù)加1
    offp = (binder_size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));

    //分別拷貝用戶空間的binder_transaction_data中ptr.buffer和ptr.offsets到內(nèi)核
    copy_from_user(t->buffer->data,
        (const void __user *)(uintptr_t)tr->data.ptr.buffer, tr->data_size);
    copy_from_user(offp,
        (const void __user *)(uintptr_t)tr->data.ptr.offsets, tr->offsets_size);

    off_end = (void *)offp + tr->offsets_size;

    for (; offp < off_end; offp++) {
        struct flat_binder_object *fp;
        fp = (struct flat_binder_object *)(t->buffer->data + *offp);
        off_min = *offp + sizeof(struct flat_binder_object);
        switch (fp->type) {
            case BINDER_TYPE_BINDER:
            case BINDER_TYPE_WEAK_BINDER: {
              struct binder_ref *ref;
              struct binder_node *node = binder_get_node(proc, fp->binder);
              if (node == NULL) {
                //服務(wù)所在進(jìn)程 創(chuàng)建binder_node實體【見4.3.2】
                node = binder_new_node(proc, fp->binder, fp->cookie);
                ...
              }
              //servicemanager進(jìn)程binder_ref
              ref = binder_get_ref_for_node(target_proc, node);
              ...
              //調(diào)整type為HANDLE類型
              if (fp->type == BINDER_TYPE_BINDER)
                fp->type = BINDER_TYPE_HANDLE;
              else
                fp->type = BINDER_TYPE_WEAK_HANDLE;
              fp->binder = 0;
              fp->handle = ref->desc; //設(shè)置handle值
              fp->cookie = 0;
              binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
                       &thread->todo);
            } break;
            case :...
    }

    if (reply) {
        ..
    } else if (!(t->flags & TF_ONE_WAY)) {
        //BC_TRANSACTION 且 非oneway,則設(shè)置事務(wù)棧信息
        t->need_reply = 1;
        t->from_parent = thread->transaction_stack;
        thread->transaction_stack = t;
    } else {
        ...
    }

    //將BINDER_WORK_TRANSACTION添加到目標(biāo)隊列,本次通信的目標(biāo)隊列為target_proc->todo
    t->work.type = BINDER_WORK_TRANSACTION;
    list_add_tail(&t->work.entry, target_list);

    //將BINDER_WORK_TRANSACTION_COMPLETE添加到當(dāng)前線程的todo隊列
    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
    list_add_tail(&tcomplete->entry, &thread->todo);

    //喚醒等待隊列,本次通信的目標(biāo)隊列為target_proc->wait
    if (target_wait)
        wake_up_interruptible(target_wait);
    return;
}

這個方法主要就是在binder驅(qū)動中執(zhí)行任務(wù)。它有兩個參數(shù)我們應(yīng)該都比較熟悉。

  1. binder_proc:這是在binder_open的時候創(chuàng)建的binder的一個數(shù)據(jù)類型,里面存放著binder的一些信息
  2. binder_transaction_data:這個在IPCthreadState的方法中見過,也是一種數(shù)據(jù)類型,存放了客戶端傳來的數(shù)據(jù)信息。

再梳理下這個方法的主要流程:

  • target_node = binder_context_mgr_data找到ServiceManager實體
  • 設(shè)置ServiceManager進(jìn)程:target_proc
  • 找到ServiceManager進(jìn)程的todo隊列和等待隊列
  • 為binder_transaction結(jié)構(gòu)賦值:
    • t->from = thread(傳進(jìn)來的binder_thread)
    • t->to_proc = target_proc(通信目標(biāo)進(jìn)程為ServiceManager進(jìn)程)
    • t->buffer = binder_alloc_buf()(ServiceManager進(jìn)程中分配buffer)
  • 拷貝用戶空間binder_transaction_data中的buffer和offsets到內(nèi)核
  • 在服務(wù)所在進(jìn)程創(chuàng)建binder_node實體,ServiceManager進(jìn)程創(chuàng)建binder_ref
  • 向ServiceManager的binder_proc->todo添加BINDER_WORK_TRANSACTION事務(wù)

這是binder底層驅(qū)動執(zhí)行事務(wù)的一系列過程

do_add_service

看完底層servicemanager進(jìn)程是如何與binder driver進(jìn)行通信的,再看看注冊服務(wù)時的方法。這個方法是在分析ServiceManager啟動的時候見過的。binder_loop-->binder_parse-->svcmgr_handler。

int do_add_service(struct binder_state *bs,
                   const uint16_t *s, size_t len,
                   uint32_t handle, uid_t uid, int allow_isolated,
                   pid_t spid)
{
    struct svcinfo *si;

    if (!handle || (len == 0) || (len > 127))
        return -1;

    //權(quán)限檢查
    if (!svc_can_register(s, len, spid)) {
        return -1;
    }

    //服務(wù)檢索
    si = find_svc(s, len);
    if (si) {
        if (si->handle) {
            svcinfo_death(bs, si); //服務(wù)已注冊時,釋放相應(yīng)的服務(wù)
        }
        si->handle = handle;
    } else {
        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
        if (!si) {  //內(nèi)存不足,無法分配足夠內(nèi)存
            return -1;
        }
        si->handle = handle;
        si->len = len;
        memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); //內(nèi)存拷貝服務(wù)信息
        si->name[len] = '\0';
        si->death.func = (void*) svcinfo_death;
        si->death.ptr = si;
        si->allow_isolated = allow_isolated;
        si->next = svclist; // svclist保存所有已注冊的服務(wù)
        svclist = si;
    }

    //以BC_ACQUIRE命令,handle為目標(biāo)的信息,通過ioctl發(fā)送給binder驅(qū)動
    binder_acquire(bs, handle);
    //以BC_REQUEST_DEATH_NOTIFICATION命令的信息,通過ioctl發(fā)送給binder驅(qū)動,主要用于清理內(nèi)存等收尾工作。
    binder_link_to_death(bs, handle, &si->death);
    return 0;
}

這里先做權(quán)限檢查,再進(jìn)行服務(wù)檢索,如果服務(wù)的名稱有一樣的就釋放源服務(wù)添加新服務(wù)。將服務(wù)保存到svclist中。服務(wù)注冊成功會調(diào)用binder_send_reply方法通過binder_write向binder驅(qū)動通信。

總結(jié)

在看這注冊服務(wù)的時候我有點懵,原因在于native層注冊服務(wù)后又跑到了binder驅(qū)動層。其實這是一個連帶的過程,主要就是要將ServiceManager所在進(jìn)程和binder進(jìn)程聯(lián)系在一起。

這里在梳理下全部流程:

  1. MediaPlayerService進(jìn)程調(diào)用ioctl向binder發(fā)送數(shù)據(jù)。該過程為一個事務(wù)binder_transaction,執(zhí)行當(dāng)前操作的線程為binder_thread(thread1)。IPC數(shù)據(jù)內(nèi)容包括:
  • binder協(xié)議BC_TRANSACTION
  • handle為0
  • RPC代碼為ADD_SERVICE
  • RPC數(shù)據(jù)為”nedia.player“
  1. binder驅(qū)動收到該請求,生成BR_TRANSACTION命令,選擇目標(biāo)處理該請求的線程,即ServiceManager的binder_thread(thread2)。將整個binder_transaction數(shù)據(jù)插入到目標(biāo)線程的TODO隊列
  2. thread2線程收到任務(wù)后,將服務(wù)“media player”注冊到服務(wù)目錄中。注冊完成后,生成IPC應(yīng)答數(shù)據(jù)BC_REPLY
  3. binder驅(qū)動收到該binder應(yīng)答請求,生成BR_REPLY命令。在MediaPlayerService接收到命令后,知道服務(wù)注冊完成就可以正常使用了。

獲取服務(wù)

獲取服務(wù)還是從MediaServicePlayer的獲取服務(wù)方法來看。

getMediaPlayerService

sp<IMediaPlayerService>&
IMediaDeathNotifier::getMediaPlayerService()
{
    Mutex::Autolock _l(sServiceLock);
    if (sMediaPlayerService == 0) {
        sp<IServiceManager> sm = defaultServiceManager(); //獲取ServiceManager
        sp<IBinder> binder;
        do {
            //獲取名為"media.player"的服務(wù)
            binder = sm->getService(String16("media.player"));
            if (binder != 0) {
                break;
            }
            usleep(500000); // 0.5s
        } while (true);

        if (sDeathNotifier == NULL) {
            sDeathNotifier = new DeathNotifier(); //創(chuàng)建死亡通知對象
        }

        //將死亡通知連接到binder
        binder->linkToDeath(sDeathNotifier);
        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
    }
    return sMediaPlayerService;
}

這里在獲取服務(wù)的過程中,仍采用不斷循環(huán)的方法。

BpSM.getService

virtual sp<IBinder> getService(const String16& name) const
    {
        unsigned n;
        //循環(huán)5次,大概和android ANR時間為5s相關(guān)
        for (n = 0; n < 5; n++){
            sp<IBinder> svc = checkService(name); //【見2.3】
            if (svc != NULL) return svc;
            sleep(1);
        }
        return NULL;
}

BpSM.checkService

virtual sp<IBinder> checkService( const String16& name) const
{
    Parcel data, reply;
    //寫入RPC頭
    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
    //寫入服務(wù)名
    data.writeString16(name);
    remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
    return reply.readStrongBinder(); 
}

檢索指定服務(wù)是否存在

在這之后又調(diào)用了和請求服務(wù)一樣的程序。

總結(jié)

獲取服務(wù)過程,就是向ServiceManager進(jìn)行查詢指定服務(wù),當(dāng)執(zhí)行binder_transaction()時,會區(qū)分獲取服務(wù)所屬進(jìn)程的情況。

參考文章

Binder源碼分析系列

寫給 Android 應(yīng)用工程師的 Binder 原理剖析

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

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

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