Android Binder

Binder

Binder是什么谋旦?

Binder架構(gòu)

  • Binder通信機制采用C/S架構(gòu)屈尼,這很重要2嶙拧X舶琛儿礼!


    @Binder架構(gòu)|center
  • Binder框架中主要涉及到4個角色ClientServerService ManagerBinder驅(qū)動涨椒,其中ClientServer绽媒、Service Manager運行在用戶空間蚕冬,Binder驅(qū)動運行在內(nèi)核空間
  • Client代表客戶端進程,Server代表客戶端進程提供各種服務(wù)是辕,如音視頻等
  • Service Manager用來管理各種系統(tǒng)服務(wù)
  • Binder驅(qū)動提供進程間通信的能力
  • 用戶空間的Client囤热、ServerServiceManager通過open获三、mmapioctl等標(biāo)準(zhǔn)文件操作(詳見Unix環(huán)境編程)來訪問/dev/binder旁蔼,進而實現(xiàn)進程間通信

基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)

Binder基礎(chǔ)數(shù)據(jù)

關(guān)于Binder基礎(chǔ)數(shù)據(jù),見上圖

Binder驅(qū)動

Binder驅(qū)動工作圖
/kernel/drivers/staging/android/binder.c
device_initcall(binder_init);

設(shè)備初始化時候會調(diào)用binder_init進行binder驅(qū)動初始化

/kernel/drivers/staging/android/binder.c
//綁定binder驅(qū)動操作函數(shù)
static const struct file_operations binder_fops = {
    .owner = THIS_MODULE,
    .poll = binder_poll,
    .unlocked_ioctl = binder_ioctl,
    .compat_ioctl = binder_ioctl,
    .mmap = binder_mmap,
    .open = binder_open,
    .flush = binder_flush,
    .release = binder_release,
};

//創(chuàng)建misc類型的驅(qū)動
static struct miscdevice binder_miscdev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "binder",
    .fops = &binder_fops//綁定binder驅(qū)動操作函數(shù)
};

//binder驅(qū)動初始化
static int __init binder_init(void)
{
    int ret;

    binder_deferred_workqueue = create_singlethread_workqueue("binder");
    if (!binder_deferred_workqueue)
        return -ENOMEM;

    //創(chuàng)建目錄/binder
    binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
    if (binder_debugfs_dir_entry_root)
        //創(chuàng)建目錄/binder/proc
        binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",
                         binder_debugfs_dir_entry_root);
    //注冊binder驅(qū)動
    ret = misc_register(&binder_miscdev);
    //創(chuàng)建其他文件
    if (binder_debugfs_dir_entry_root) {
        //創(chuàng)建文件/binder/proc/state
        debugfs_create_file("state",
                    S_IRUGO,
                    binder_debugfs_dir_entry_root,
                    NULL,
                    &binder_state_fops);
        //創(chuàng)建文件/binder/proc/stats
        debugfs_create_file("stats",
                    S_IRUGO,
                    binder_debugfs_dir_entry_root,
                    NULL,
                    &binder_stats_fops);
        //創(chuàng)建文件/binder/proc/transactions
        debugfs_create_file("transactions",
                    S_IRUGO,
                    binder_debugfs_dir_entry_root,
                    NULL,
                    &binder_transactions_fops);
        //創(chuàng)建文件/binder/proc/transaction_log
        debugfs_create_file("transaction_log",
                    S_IRUGO,
                    binder_debugfs_dir_entry_root,
                    &binder_transaction_log,
                    &binder_transaction_log_fops);
        //創(chuàng)建文件/binder/proc/failed_transaction_log
        debugfs_create_file("failed_transaction_log",
                    S_IRUGO,
                    binder_debugfs_dir_entry_root,
                    &binder_transaction_log_failed,
                    &binder_transaction_log_fops);
    }
    return ret;
}

初始化主要做了兩件事情

  • 初始化存儲binder存儲信息的目錄
  • 創(chuàng)建binder設(shè)備疙教,并綁定操作函數(shù)如binder_open棺聊、binder_mmapbinder_ioctl
  • 設(shè)備啟動時候贞谓,會調(diào)用binder_init限佩,主要做兩件事情
  • 1.創(chuàng)建/binder/proc目錄,之后在這個目錄下創(chuàng)建state裸弦、stats祟同、transactions、transaction_log理疙、failed_transaction_log文件夾晕城,分別存儲進程通信的各種數(shù)據(jù)
  • 2.注冊驅(qū)動,并綁定文件操作函數(shù)binder_open窖贤、binder_mmap砖顷、binder_ioctl等暇矫,之后就可以通過RPC機制去訪問binder驅(qū)動

Native層級的Binder結(jié)構(gòu)

@Server組件類圖|center

@Client組件類圖|center

Binder通信機制

@Binder分層|center

Binder進程與線程

@Binder驅(qū)動中的線程與用戶空間的線程

ServiceManager啟動

@ServiceManager啟動

預(yù)備知識補充

ServiceManager啟動流程主要分為三個流程
1.以系統(tǒng)服務(wù)形式啟動service_manager,之后通過在binder_open函數(shù)打開驅(qū)動設(shè)備,驅(qū)動層相應(yīng)的就會創(chuàng)建service_manager對應(yīng)的binder_proc择吊,并且這是個特殊的service
2.調(diào)用binder_become_context_manager通過ioctl調(diào)用內(nèi)核中的binder_ioctl,經(jīng)過一系列處理后李根,binder驅(qū)動會將這個特殊的binder_node存到靜態(tài)指針binder_context_mgr_node

static struct binder_node *binder_context_mgr_node;
...
static int binder_ioctl_set_ctx_mgr(struct file *filp)
{
    ...
    //注意這里后續(xù)兩個參數(shù)都是0
    binder_context_mgr_node = binder_new_node(proc, 0, 0);
    ...
}
...

3.調(diào)用binder_loop進入循環(huán)解析的過程

int main(int argc, char** argv){
    ...
    //進入循環(huán),等待或處理Client進程的通信請求
    binder_loop(bs, svcmgr_handler);
    ...
}

這里指定循環(huán)處理函數(shù)為svcmgr_handler,后續(xù)再仔細分析這個函數(shù)几睛,先看binder_loop實現(xiàn)

void binder_loop(struct binder_state *bs, binder_handler func)
{
    ...
    //通信數(shù)據(jù)
    struct binder_write_read bwr;
    
     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);
        ...
        //解析
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        ...
    }
    
}

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);
    ...
    return res;
}
  • 首先創(chuàng)建一個binder_write_read結(jié)構(gòu)體房轿,然后通過binder_write向Binder驅(qū)動寫入命令協(xié)議BC_ENTER_LOOPER,注意這個理輸出緩沖區(qū)是沒有數(shù)據(jù)的,binder驅(qū)動經(jīng)過一系列處理進入循環(huán)狀態(tài)所森,之后通過一個死循環(huán)來不斷的從Binder驅(qū)動讀取數(shù)據(jù)囱持,之后交由binder_parse去解析各種協(xié)議數(shù)據(jù),后續(xù)再分析細節(jié)
  • Binder驅(qū)動是如何處理交互細節(jié)的焕济,我們來看下binder_ioctl_write_read的實現(xiàn)
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;
    //命令協(xié)議
    unsigned int size = _IOC_SIZE(cmd);
    ...
    struct binder_write_read bwr;
    //取出bwr進程通信協(xié)議載體
    if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
        ...
    }
    //如果有寫入數(shù)據(jù)纷妆,就交由binder_thread_write去處理,之后
    //通過copy_to_user將數(shù)據(jù)返還給用戶空間
    if (bwr.write_size > 0) {
        ret = binder_thread_write(proc, thread,
                      bwr.write_buffer,
                      bwr.write_size,
                      &bwr.write_consumed);
        ...
        if (ret < 0) {
            bwr.read_consumed = 0;
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                ...
            goto out;
        }
    }
    
    //如果有輸出數(shù)據(jù)晴弃,則調(diào)用binder_thread_read解析掩幢,
    //之后判斷進程的事務(wù)隊里是否為空,如果不為空就等待執(zhí)行
    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) {
            //將寫出數(shù)據(jù)返還給用戶空間
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                ...
            goto out;
        }
    }
    ...
out:
    return ret;
}
  • 至于binder_thread_writebinder_thread_read則是處理命令協(xié)(binder_driver_command_protocol)與返回協(xié)議(binder_driver_return_protocol )詳見/drivers/staging/android/binder.h

ServiceManager注冊服務(wù)

@Service的注冊流程|center
  • service的注冊流程如上圖上鞠,這里以media_server的注冊為例子去看代碼
/frameworks/av/services/mediadrm/mediadrmserver.rc
service mediadrm /system/bin/mediadrmserver
    class main
    user media
    group mediadrm drmrpc
    ioprio rt 4
    writepid /dev/cpuset/foreground/tasks
  • 可以看到以用戶權(quán)限啟動mediadrm服務(wù)际邻,文件位于/system/bin/mediadrmserver
  • 接下來看main_mediadrmserver.cpp
/frameworks/av/services/mediadrm/mediadrmserver.cpp
int main()
{
    ...
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm = defaultServiceManager();
    ...
    MediaDrmService::instantiate();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}
  • main()中主要做了兩件事情:
    1.初始化MediaDrmService
    2.線程池初始化
    先看第一個
/frameworks/av/services/mediadrm/MediaDrmService.cpp
...
void MediaDrmService::instantiate() {
    defaultServiceManager()->addService(
            String16("media.drm"), new MediaDrmService());
}
...
  • 這里面主要通過defaultServiceManager()獲取一個BpServiceManager指針然后調(diào)用addService,注意這里傳入的兩個參數(shù)“media.drm”和一個MediaDrmService對象

ServiceManager代理對象的獲取

  • 先來看defaultServiceManager()調(diào)用
/frameworks/native/libs/binder/Static.cpp
...
sp<IServiceManager> gDefaultServiceManager;
...

/frameworks/native/libs/binder/ISerivceManager.cpp
...
sp<IServiceManager> defaultServiceManager()
{
    if (gDefaultServiceManager != NULL) 
        return gDefaultServiceManager;
    {
        ...
        while (gDefaultServiceManager == NULL) {
            gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(NULL));
                ...
        }
    }

    return gDefaultServiceManager;
}
...
  • gDefaultServiceManager就是一個IServiceManger的指針
  • 首次獲取時候一定是通過interface_cast<IServiceManager>(ProcessState::self()->getContextObject(NULL))這一系列method調(diào)用獲取的芍阎,一步步分析
  • 先看ProcessState::self()
/frameworks/native/libs/binder/ProcessState
...
sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    //注意這里的文件name
    gProcess = new ProcessState("/dev/binder");
    return gProcess;
}
...
  • 我賭半包辣條世曾,這個類構(gòu)造一定持有打開/dev/binder的句柄,不信你看構(gòu)造聲明
//這里是cpp構(gòu)造函數(shù)形式谴咸,就是成員變量賦值
ProcessState::ProcessState(const char *driver)
    : mDriverName(String8(driver))
    , mDriverFD(open_driver(driver))
    , mVMStart(MAP_FAILED)
    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
    , mExecutingThreadsCount(0)
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
    , mStarvationStartTimeMs(0)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{
if (mDriverFD >= 0) {
        // mmap the binder, providing a chunk of virtual address space to receive transactions.
        //注意這里分配的BINDER_VM_SIZE為1016kb轮听,具體見宏定義處
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            ...
            close(mDriverFD);
            mDriverFD = -1;
            mDriverName.clear();
        }
    }
    ...
}
  • 再來看getContextObject
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    //注意這里傳入的值為0
    return getStrongProxyForHandle(0);
}

...
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    ...
    handle_entry* e = lookupHandleLocked(handle);
    if (e != NULL) {
        ...
        b = BpBinder::create(handle);
        e->binder = b;
        if (b) e->refs = b->getWeakRefs();
        result = b;
    }else{
        ...
    }
    return result;
}
  • getContextObject()內(nèi)部是調(diào)用getStrongProxyForHandle(0)來獲取一個IBinder指針(這里0其實就是為了后續(xù)查找之前ServiceManager啟動注冊那個特殊的Service組件),可以看到其實這里創(chuàng)建的是一個BpBinder對象岭佳,并且他的句柄值是0
  • 我們來看BpBinder的相關(guān)調(diào)用
frameworks/native/libs/binder/BpBinder.cpp
//handle句柄值 與binder驅(qū)動中的binder引用對象進行關(guān)聯(lián)
BpBinder::BpBinder(int32_t handle, int32_t trackedUid)
    //注意這里傳入的是0
    : mHandle(handle)
    //注意這個值為1
    , mAlive(1)
    , mObitsSent(0)
    , mObituaries(NULL)
    , mTrackedUid(trackedUid)
{
    ...
    IPCThreadState::self()->incWeakHandle(handle, this);
}

BpBinder* BpBinder::create(int32_t handle) {
    ...
    return new BpBinder(handle, trackedUid);
}
  • 回到defaultServiceManager()血巍,最后interface_cast<IServiceManager>(BpBinder(0))實際上轉(zhuǎn)換成了這個,這個在哪里定義呢驼唱?
/frameworks/native/include/binder/IInterface.h
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}
  • 發(fā)現(xiàn)他是個內(nèi)聯(lián)模板函數(shù)藻茂,實際上調(diào)用的是IServiceManager::asInterface(BpBinder(0)),那么IServiceManager::asInterface在哪里定義呢玫恳?
/frameworks/native/libs/binder/IServiceManager.cpp
IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");

看上面這個宏定義辨赐,實際定義在
/frameworks/native/include/binder/IInterface.h

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       
    const ::android::String16 I##INTERFACE::descriptor(NAME);           
    const ::android::String16&                                          
        I##INTERFACE::getInterfaceDescriptor() const {              
        return I##INTERFACE::descriptor;                                
    }                                                                   
    ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              
            const ::android::sp<::android::IBinder>& obj)               
    {                                                                   
        ::android::sp<I##INTERFACE> intr;                               
        if (obj != NULL) {                                              
            intr = static_cast<I##INTERFACE*>(                          
                obj->queryLocalInterface(                               
                        I##INTERFACE::descriptor).get());               
            if (intr == NULL) {                                         
                intr = new Bp##INTERFACE(obj);                          
            }                                                           
        }                                                               
        return intr;                                                    
    }                                                                   
    I##INTERFACE::I##INTERFACE() { }                                    
    I##INTERFACE::~I##INTERFACE() { }                                   
  • 帶入轉(zhuǎn)換下,發(fā)現(xiàn)我們拿到的其實就是一個BpServiceManager
  • 接下來我們來看后續(xù)的調(diào)用

BpServiceManager#addService

virtual status_t addService(const String16& name, const sp<IBinder>& service,bool allowIsolated, int dumpsysPriority) {
        //這里data表示要寫入的數(shù)據(jù)京办,reply表示返回的數(shù)據(jù)
        Parcel data, reply;
        //存儲描述符"android.os.IServiceManager"    
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        //存儲服務(wù)名字"media.drm"     
        data.writeString16(name);
        //存儲服務(wù)MediaDrmService
        data.writeStrongBinder(service);
        data.writeInt32(allowIsolated ? 1 : 0);
        data.writeInt32(dumpsysPriority);
        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }
  • 這里實際上把上一步傳入的數(shù)據(jù)通過Parcel存起來掀序,然后調(diào)用remote()獲取一個BpBinder然后調(diào)用其transact,傳入的code為ADD_SERVICE_TRANSACTION惭婿,經(jīng)過包裝后data中的數(shù)據(jù)長這樣子
  • @Parcel數(shù)據(jù)封裝|center
  • 記下來我們?nèi)タ碆pBinder#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.
    //構(gòu)造中mAlive=1不恭,所以這里會走進if
    if (mAlive) {
        //這里調(diào)用的是IPCThreadState#transact
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}
  • 前面ServiceManager代理對象獲取BpBinder時候叶雹,mHandle為0,code為ADD_SERVICE_TRANSACTION换吧,data存儲binder信息折晦,reply存儲要返回的信息,flags查看method定義默認參數(shù)為0
  • 接下來分析IPCThreadState#transact
    /frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err;

    //允許返回中攜帶文件描述符
    flags |= TF_ACCEPT_FDS;
    ...
    //封裝BC_TRANSACTION通信請求
    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    ...
    //同步or異步沾瓦,這里是同步調(diào)用
    if ((flags & TF_ONE_WAY) == 0) {
        ...
        if (reply) {
            //向Binder驅(qū)動發(fā)起B(yǎng)C_TRANSACTION
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
            ...
        }
        ...
    }else{
        err = waitForResponse(NULL, NULL);
    }
    return err;
}
  • 上面首先將flags與TF_ACCEPT_FDS做或操作满着,表示接收文件描述符
  • 之后調(diào)用writeTransactionData將數(shù)據(jù)封裝成一個BC_TRANSACTION命令協(xié)議,這里是同步調(diào)用切需要返回,所以執(zhí)行到的是waitForResponse(reply)贯莺,接下來分別來看writeTransactionData风喇、waitForResponse的實現(xiàn)
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
    int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
    {
    //對應(yīng)內(nèi)核中要求io攜帶binder_transaction_data結(jié)構(gòu)體
    binder_transaction_data tr;

    tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
    tr.target.handle = handle;
    tr.code = code;
    tr.flags = binderFlags;
    tr.cookie = 0;
    tr.sender_pid = 0;
    tr.sender_euid = 0;

    const status_t err = data.errorCheck();
    if (err == NO_ERROR) {
        tr.data_size = data.ipcDataSize();
        tr.data.ptr.buffer = data.ipcData();
        tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
        tr.data.ptr.offsets = data.ipcObjects();
    } else if (statusBuffer) {
        tr.flags |= TF_STATUS_CODE;
        *statusBuffer = err;
        tr.data_size = sizeof(status_t);
        tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
        tr.offsets_size = 0;
        tr.data.ptr.offsets = 0;
    } else {
        return (mLastError = err);
    }

    mOut.writeInt32(cmd);
    mOut.write(&tr, sizeof(tr));

    return NO_ERROR;
}
  • 這里主要是創(chuàng)建一個binder_transaction_data,初其始化后將要傳輸?shù)臄?shù)據(jù)寫入到mOut緩沖區(qū)中缕探,最終整個數(shù)據(jù)長這樣子
  • @writeTransactionData|center
  • 數(shù)據(jù)封裝完成以后魂莫,我們來看waitForResponse的實現(xiàn)
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    int32_t err;
    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
        ...
        //從輸出緩沖區(qū)取出返回協(xié)議命令
        cmd = (uint32_t)mIn.readInt32();
        ...
    }
    ...
    return err;
}
  • 這里可以是一個死循環(huán),不斷的通過talkWithDriver去跟binder驅(qū)動通信爹耗,然后從輸出緩沖區(qū)中取出返回協(xié)議然后處理返回協(xié)議耙考,這里先不看具體的協(xié)議處理,先來看talkWithDriver的實現(xiàn)
//默認doReceive = true
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    ...
    binder_write_read bwr;

    // Is the read buffer empty?
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();

    // We don't want to write anything if we are still reading
    // from data left in the input buffer and the caller
    // has requested to read the next data.
    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{
        ...
        //這里通過io想驅(qū)動寫入一個binder_write_read結(jié)構(gòu)體
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;
    } while (err == -EINTR);
    
    if (err >= NO_ERROR) {
        if (bwr.write_consumed > 0) {
            if (bwr.write_consumed < mOut.dataSize())
                mOut.remove(0, bwr.write_consumed);
            else {
                mOut.setDataSize(0);
                processPostWriteDerefs();
            }
        }
        if (bwr.read_consumed > 0) {
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0);
        }
        ...
        return NO_ERROR;
    }

    return err;
}
  • 這里主要通過io控制命令向Binder驅(qū)動寫入一個type為BINDER_WRITE_READ鲸沮,data為binder_write_read琳骡,其輸出緩沖區(qū)為前面mOut中寫入的數(shù)據(jù)
  • 接下來的操作就轉(zhuǎn)到Binder驅(qū)動中進行了锅论,需要記住讼溺,Clinet進程此時執(zhí)行到的位置
/platform/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);
    ...
    //這里根據(jù)進程找到對應(yīng)的thread,如果沒找到就創(chuàng)建一個
    thread = binder_get_thread(proc);
    ...
    switch (cmd) {
    case BINDER_WRITE_READ:
        ret = binder_ioctl_write_read(filp, cmd, arg, thread);
        if (ret)
            goto err;
        break;
    ...
}
  • Binder驅(qū)動中對應(yīng)的binder_ioctl()會調(diào)用最易,之后會處理cmd為BINDER_WRITE_READ的分支怒坯,之后會調(diào)用到binder_ioctl_write_read()
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;
    //cmd信息
    unsigned int size = _IOC_SIZE(cmd);
    void __user *ubuf = (void __user *)arg;
    struct binder_write_read bwr;
    //cmd校驗
    if (size != sizeof(struct binder_write_read)) {
        ret = -EINVAL;
        goto out;
    }
    //從用戶空間中取出binder_write_read結(jié)構(gòu)體
    if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }
    ...
    //輸出緩沖區(qū)有數(shù)據(jù)就處理輸出緩沖區(qū)
    if (bwr.write_size > 0) {
        //這里是真正處理輸出緩沖數(shù)據(jù)的func
        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;
        }
    }
    //輸入緩沖區(qū)有數(shù)據(jù)就處理輸入緩沖區(qū)
    if (bwr.read_size > 0) {
        //這里是真正處理輸出緩沖數(shù)據(jù)的func
        ret = binder_thread_read(proc, thread, bwr.read_buffer,
                     bwr.read_size,
                     &bwr.read_consumed,
                     filp->f_flags & O_NONBLOCK);
        trace_binder_read_done(ret);
        //如果進程todo隊里不為空,說明有事務(wù)正在處理藻懒,需要等待處理
        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;
        }
    }
    ...
    //將數(shù)據(jù)copy回用戶空間
    if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }
out:
    return ret;
}
  • 前面調(diào)用可知剔猿,輸出緩沖區(qū)是有數(shù)據(jù),輸入緩沖區(qū)是沒有數(shù)據(jù)的嬉荆,所以上面方法執(zhí)行流程應(yīng)該是归敬,先調(diào)用binder_thread_write去處理輸出緩沖區(qū)
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) {
        //根據(jù)cmd取出消費的數(shù)據(jù)偏移地址
        if (get_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        ptr += sizeof(uint32_t);
        ...
        switch (cmd) {
            ...
            case BC_TRANSACTION:
            case BC_REPLY: {
                struct binder_transaction_data tr;
    
                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;   
}   
  • 這里是取出cmd,然后處理BC_TRANSACTION時候鄙早,再講binder_transaction_data取出汪茧,之后交由binder_transaction去處理
  • binder_transaction比較長,其實主要分為三個部分
  • 1.初始化目標(biāo)線程進程
  • 2.封裝返回數(shù)據(jù)binder_transaction_data
  • 3.為binder_transaction_data分配合適的線程or進程
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;
    binder_size_t *offp, *off_end;
    binder_size_t off_min;
    struct binder_proc *target_proc;
    struct binder_thread *target_thread = NULL;
    struct binder_node *target_node = NULL;
    struct list_head *target_list;
    wait_queue_head_t *target_wait;
    struct binder_transaction *in_reply_to = NULL;
    ...
    uint32_t return_error;
    ...
    //如果是reply走if分支限番,否則走else分支舱污,這里走else
    if (reply) {
        ...
    }else{
        //根據(jù)句柄找對應(yīng)的binder_ref、binder_node
        if (tr->target.handle) {
            struct binder_ref *ref;
            ref = binder_get_ref(proc, tr->target.handle);
            ...
        else{
            //handle=0弥虐,則需要找指向service_manager的binder_node
            target_node = binder_context_mgr_node;
            ...
        }
        ...
        //根據(jù)binder_node找到對應(yīng)的進程binder_proc扩灯,這里也就是service_manager
        target_proc = target_node->proc;
        ...
        //如果是同步請求媚赖,嘗試尋找一個在等待其他事物執(zhí)行的線程,tips優(yōu)化調(diào)度
        if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
            struct binder_transaction *tmp;
            tmp = thread->transaction_stack;
            ...
            //找到一個等待別的事務(wù)完成的依賴線程
            while (tmp) {
                if (tmp->from && tmp->from->proc == target_proc)
                    target_thread = tmp->from;
                tmp = tmp->from_parent;
            }
        }
    }
    //有空閑線程就是用空閑線程的等待隊列珠插,否則使用進程的事物隊列
    if (target_thread) {
        e->to_thread = target_thread->pid;
        target_list = &target_thread->todo;
        target_wait = &target_thread->wait;
    } else {
        target_list = &target_proc->todo;
        target_wait = &target_proc->wait;
    }
    ...
    //創(chuàng)建binder_transaction結(jié)構(gòu)體惧磺,BINDER_WORK_TRANSACTION
    //用于向目標(biāo)進程發(fā)送數(shù)據(jù)
    t = kzalloc(sizeof(*t), GFP_KERNEL);
    ...
    binder_stats_created(BINDER_STAT_TRANSACTION);
    ...
    //創(chuàng)建binder_work結(jié)構(gòu)體,BINDER_STAT_TRANSACTION_COMPLETE
    //便于向源進程返回數(shù)據(jù)處理結(jié)果
    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
    ...
    binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);
    ...
    //初始化t
    if (!reply && !(tr->flags & TF_ONE_WAY))
        t->from = thread;
    else
        t->from = NULL;
    t->sender_euid = task_euid(proc->tsk);
    //目標(biāo)進程
    t->to_proc = target_proc;
    //目標(biāo)線程
    t->to_thread = target_thread;
    //code ADD_SERVICE_TRANSACTION
    t->code = tr->code;
    //flag = TF_ACCEPT_FLAGS
    t->flags = tr->flags;
    //優(yōu)先級
    t->priority = task_nice(current);
    ...
    //緩沖區(qū)
    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->debug_id = t->debug_id;
    t->buffer->transaction = t;
    t->buffer->target_node = target_node;
    ...
    //為t分配內(nèi)核緩沖區(qū)
    if (target_node)
        binder_inc_node(target_node, 1, 0, NULL);
    
    offp = (binder_size_t *)(t->buffer->data +
                 ALIGN(tr->data_size, sizeof(void *)));
     //數(shù)據(jù)copy
    if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
               tr->data.ptr.buffer, tr->data_size)) {
        ...
        goto err_copy_data_failed;
    }
    if (copy_from_user(offp, (const void __user *)(uintptr_t)
               tr->data.ptr.offsets, tr->offsets_size)) {
        ...
        goto err_copy_data_failed;
    }
    ...
    
    //處理Binder請求,內(nèi)核中很多都是地址起止位置操作
    off_end = (void *)offp + tr->offsets_size;
    off_min = 0;
    for (; offp < off_end; offp++) {
        struct flat_binder_object *fp;
        ...
        //前面存儲的MediaDrmService信息
        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);
                //如果是首次就創(chuàng)建新的binder_node
                if (node == NULL) {
                node = binder_new_node(proc, fp->binder, fp->cookie);
                ...
                //設(shè)定線程優(yōu)先級
                node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
                //設(shè)置是否接收文件描述符
                node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
                }
                ...
                //如果是首次就創(chuàng)建對應(yīng)的binder_ref對象
                ref = binder_get_ref_for_node(target_proc, node);
                if (ref == NULL) {
                    return_error = BR_FAILED_REPLY;
                    goto err_binder_get_ref_for_node_failed;
                }
                //修改flat_binder_objec.type
                if (fp->type == BINDER_TYPE_BINDER)
                    fp->type = BINDER_TYPE_HANDLE;
                else
                    fp->type = BINDER_TYPE_WEAK_HANDLE;
                //設(shè)置句柄
                fp->handle = ref->desc;
                //增加binder_ref的引用計數(shù)
                binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
                           &thread->todo);
               ...
            }break;
            ...
        }
    }
    
    //分配事務(wù)t的要進入那個棧
    if (reply) {
        ...
        binder_pop_transaction(target_thread, in_reply_to);
    } else if (!(t->flags & TF_ONE_WAY)) {
        ...
        t->need_reply = 1;
        t->from_parent = thread->transaction_stack;
        thread->transaction_stack = t;
    } else {
        ...
        if (target_node->has_async_transaction) {
            target_list = &target_node->async_todo;
            target_wait = NULL;
        } else
            target_node->has_async_transaction = 1;
    }
    //將binder_transaction_data指針t的類型修改為BINDER_WORK_TRANSACTION
    t->work.type = BINDER_WORK_TRANSACTION;
    //添加到target_list隊列尾部
    list_add_tail(&t->work.entry, target_list);
    //將binder_work指針tcomplete.type置為BINDER_WORK_TRANSACTION_COMPLETE
    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
    list_add_tail(&tcomplete->entry, &thread->todo);
    //這里有兩個執(zhí)行分支
    //1.處理類型為BINDER_WORK_TRANSACTION的binder_transaction_data
    //2.處理類型為BINDER_WORK_TRANSACTION_COMPLETE的binder_work
    if (target_wait)
        wake_up_interruptible(target_wait);
    return;
    ...
}
  • 經(jīng)過上面func以后捻撑,binder驅(qū)動中就會為MediaDrmService創(chuàng)建對應(yīng)的binder_node并加入到整個Binder實體對象的紅黑樹中豺妓,接著會分別向Client進程、ServiceManager發(fā)送一個BINDER_WORK_TRANSACTION_COMPLETE的binder_work及BINDER_WORK_TRANSACTION的binder_transaction
  • 至此布讹,源線程thread琳拭、target_proc或者target_thread會并發(fā)的去執(zhí)行各自todo隊列中的任務(wù)
  • 先來看源線程,回到binder_ioctl_write_read中,接下來要處理輸入緩沖區(qū)描验,對應(yīng)的調(diào)用binder_thread_read
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;
    ...
    //線程喚醒
    while (1) {
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL;
        //檢查工作隊列白嘁,并將待處理項賦值給w
        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;
        }
        switch (w->type) {
            ...
            case BINDER_WORK_TRANSACTION_COMPLETE: {
                cmd = BR_TRANSACTION_COMPLETE;
                if (put_user(cmd, (uint32_t __user *)ptr))
                    return -EFAULT;
                ptr += sizeof(uint32_t);
    
                binder_stat_br(proc, thread, cmd);
                ...
                //刪除binder_work,并釋放資源
                list_del(&w->entry);
                kfree(w);
                binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
            } break;
        }
done:
    *consumed = ptr - buffer;
    ...
    return 0;
}
  • 這里返回一個BR_TRANSACTION_COMPLETE協(xié)議膘流,之后會經(jīng)過一些列調(diào)用會回到IPCThreadState#waitForResponse中
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    ...
    uint32_t cmd;
    int32_t err;

    while (1) {
        ...
        cmd = (uint32_t)mIn.readInt32();
        ...
        switch (cmd) {
        case BR_TRANSACTION_COMPLETE:
            if (!reply && !acquireResult) goto finish;
            break;
        }
        ...
    }
finish:
    ...
    return error;
}
  • IPCThreadState::waitForResponse對于BR_TRANSACTION_COMPLETE處理比較簡單絮缅,就直接返回了
  • 我們來看下target_proc即ServiceManager是怎么接收處理BINDER_WORK_TRANSACTION類型的binder_transaction的,假設(shè)ServiceManager之前沒有通信呼股,那么他就在Binder驅(qū)動中一直等待事務(wù)的到來耕魄,現(xiàn)在有事務(wù)了那么對應(yīng)的就會調(diào)用binder_read_thread
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;
    ...
    //線程喚醒
    while (1) {
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL;

        //檢查工作隊列,并將待處理項賦值給w
        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;
        }
        ...
        switch (w->type) {
        case BINDER_WORK_TRANSACTION: {
            t = container_of(w, struct binder_transaction, work);
        } break;
        ...
        }
    //返回協(xié)議的處理彭谁,現(xiàn)在target_node指向的是binder_context_mgr_node
        if (t->buffer->target_node) {
            struct binder_node *target_node = t->buffer->target_node;

            tr.target.ptr = target_node->ptr;
            tr.cookie =  target_node->cookie;
            //保存原本的線程優(yōu)先級吸奴,便于后續(xù)恢復(fù)
            t->saved_priority = task_nice(current);
            //修改binder驅(qū)動中對應(yīng)proc的線程優(yōu)先級(模擬Client進程的線程優(yōu)先級)
            if (t->priority < target_node->min_priority &&
                !(t->flags & TF_ONE_WAY))
                binder_set_nice(t->priority);
            else if (!(t->flags & TF_ONE_WAY) ||
                 t->saved_priority > target_node->min_priority)
                binder_set_nice(target_node->min_priority);
            cmd = BR_TRANSACTION;
        } else {
            ...
        }
        //拷貝code與flags,
        //注冊服務(wù)過程中這里是ADD_SERVICE_TRANSACTION缠局、TF_ACCEPT_FDS
        tr.code = t->code;
        tr.flags = t->flags;
        if (t->from) {
            struct task_struct *sender = t->from->proc->tsk;
            tr.sender_pid = task_tgid_nr_ns(sender,
                            task_active_pid_ns(current));
        } else {
            ...
        }
        //Binder驅(qū)動程序分配給進程的內(nèi)核緩沖區(qū)同時则奥,
        //映射了用戶的內(nèi)核地址、用戶空間地址
        tr.data_size = t->buffer->data_size;
        tr.offsets_size = t->buffer->offsets_size;
        tr.data.ptr.buffer = (binder_uintptr_t)(
                    (uintptr_t)t->buffer->data +
                    proc->user_buffer_offset);
        //直接操作offsets
        tr.data.ptr.offsets = tr.data.ptr.buffer +
                    ALIGN(t->buffer->data_size,
                        sizeof(void *));

        //提供一個返回協(xié)議數(shù)據(jù)的緩沖區(qū)
        if (put_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        ptr += sizeof(uint32_t);
        if (copy_to_user(ptr, &tr, sizeof(tr)))
            return -EFAULT;
        ptr += sizeof(tr);
        ...
        list_del(&t->work.entry);
        t->buffer->allow_user_free = 1;
        //cmd = BR_TRANSACTION && 不是正在處理異步通信請求
        //就需要等待該同步進程通信完以后再進行下一步的操作
        if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
            t->to_parent = thread->transaction_stack;
            t->to_thread = thread;
            thread->transaction_stack = t;
        } else {
            t->buffer->transaction = NULL;
            kfree(t);
            binder_stats_deleted(BINDER_STAT_TRANSACTION);
        }
        break;
    }
    ...
    return 0
}       
  • 這里實際上是返回一個BR_TRANSACTION協(xié)議狭园,并且將之前通過binder_transaction傳輸?shù)臄?shù)據(jù)封裝到binder_transaction_data中读处,由于在service_manager啟動中,進入binder_loop時候指定的函數(shù)引用為svcmgr_handler,binder_loop中會循環(huán)通過ioctl控制命令去與內(nèi)核交互數(shù)據(jù)唱矛,binder_parse用于解析數(shù)據(jù)
platform/frameworks/native/cmds/servicemanager/binder.c
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);
        ...
        case BR_TRANSACTION: {
            struct binder_transaction_data *txn = 
                (struct binder_transaction_data *) ptr;
            ...
            if (func) {
                unsigned rdata[256/4];
                struct binder_io msg;
                struct binder_io reply;
                int res;
                bio_init(&reply, rdata, sizeof(rdata), 4);
                bio_init_from_txn(&msg, txn);
                //調(diào)用svcmgr_handler去處理
                res = func(bs, txn, &msg, &reply);
                if (txn->flags & TF_ONE_WAY) {
                    binder_free_buffer(bs, txn->data.ptr.buffer);
                } else {
                    //返回注冊的結(jié)果給binder驅(qū)動
                    binder_send_reply(bs, &reply, 
                            txn->data.ptr.buffer, res);
                }
            }
            break;
        }   
}
  • 這其中有三個結(jié)構(gòu)體binder_io主要存儲數(shù)據(jù)傳輸罚舱,定義如下:
struct binder_io
{
    char *data;            /* pointer to read/write from */
    binder_size_t *offs;   /* array of offsets */
    size_t data_avail;     /* bytes available in data buffer */
    size_t offs_avail;     /* entries available in offsets array */

    char *data0;           /* start of data buffer */
    binder_size_t *offs0;  /* start of offsets buffer */
    uint32_t flags;
    uint32_t unused;
};
  • binder_parse中先通過bio_init去初始化reply,然后通過bio_init_from_txn去初始化msg绎谦,就是數(shù)據(jù)對齊的過程及flag設(shè)置管闷,這里不再細述
  • 我們重點關(guān)注func,也就是svcmgr_handler,先來回顧前面數(shù)據(jù)那張圖


    @writeTransactionData|center
  • 接下來再來看svvmgr_handler的實現(xiàn)
uint16_t svcmgr_id[] = {
    'a','n','d','r','o','i','d','.','o','s','.',
    'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r'
};
...
int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    struct svcinfo *si;
    uint16_t *s;
    size_t len;
    uint32_t handle;
    uint32_t strict_policy;
    int allow_isolated;
    ...
    strict_policy = bio_get_uint32(msg);
    s = bio_get_string16(msg, &len);
    ...
    //svcmgr_id校驗,是否為“android.os.IServiceManager”
    if ((len != (sizeof(svcmgr_id) / 2)) ||
        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
        fprintf(stderr,"invalid id %s\n", str8(s, len));
        return -1;
    }
    ...
    switch(txn->code) {
        ...
        //枚舉值對應(yīng)ADD_SERVICE_TRANSACTION
        case SVC_MGR_ADD_SERVICE:
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        //取出binder_引用對象的句柄值
        handle = bio_get_ref(msg);
        allow_isolated = bio_get_uint32(msg) ? 1 : 0;
        dumpsys_priority = bio_get_uint32(msg);
        if (do_add_service(bs, s, len, handle, 
            txn->sender_euid, allow_isolated, dumpsys_priority,
                           txn->sender_pid))
            return -1;
        break;
   }
   ...
   bio_put_uint32(reply, 0);
   return 0; 
}
  • 從msg中取出對應(yīng)的Service的handle燥滑、name渐北,然后調(diào)用do_add__service去執(zhí)行后續(xù)的操作
  • 看do_add_service之前我們先來看一個結(jié)構(gòu)體svcinfo
struct svcinfo
{
    //指向下一個引用
    struct svcinfo *next;
    //句柄值
    uint32_t handle;
    //死亡代理通知
    struct binder_death death;
    int allow_isolated;
    uint32_t dumpsys_priority;
    size_t len;
    //服務(wù)名稱
    uint16_t name[0];
};
  • 在ServiceManager中每一個服務(wù)對應(yīng)一個svcinfo結(jié)構(gòu)體
  • 接下來我們看do_add_service的實現(xiàn)
int do_add_service(struct binder_state *bs, const uint16_t *s, 
    size_t len, uint32_t handle, uid_t uid, int allow_isolated, 
    uint32_t dumpsys_priority, pid_t spid) {
    //存儲要注冊的服務(wù)信息
    struct svcinfo *si;
    ...
    //檢查權(quán)限
    if (!svc_can_register(s, len, spid, uid)) {
        ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
             str8(s, len), handle, uid);
        return -1;
    }
    /先去找這個服務(wù)
    si = find_svc(s, len);
    if (si) {
        if (si->handle) {
            ...
            svcinfo_death(bs, si);
        }
        si->handle = handle;
    } else {
        //注冊服務(wù)
        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
        ...
        si->handle = handle;
        si->len = len;
        memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
        si->name[len] = '\0';
        si->death.func = (void*) svcinfo_death;
        si->death.ptr = si;
        si->allow_isolated = allow_isolated;
        si->dumpsys_priority = dumpsys_priority;
        //綁定到svclist中
        si->next = svclist;
        svclist = si;
    }

    //增加引用,避免被銷毀
    binder_acquire(bs, handle);
    //綁定死亡通知
    binder_link_to_death(bs, handle, &si->death);
    return 0;
}
  • 這里先檢查Service是否有注冊權(quán)限(不同版本內(nèi)核加固調(diào)用不同铭拧,感興趣可以查看selinux)赃蛛,然后先去嘗試查找這個服務(wù)存在不恃锉,如果不存在就分配一個新的struct svcinfo,并將其掛到svclist中呕臂,由此可見在service_manager中是維護這一個所有Service組件信息的svclist的
  • 回到binder_parse中,接下來會調(diào)用binder_send_reply向Binder驅(qū)動發(fā)送一個BC_REPLY
void binder_send_reply(struct binder_state *bs,
                       struct binder_io *reply,
                       binder_uintptr_t buffer_to_free,
                       int status)
{
    //匿名結(jié)構(gòu)體
    struct {
        uint32_t cmd_free;
        binder_uintptr_t buffer;
        uint32_t cmd_reply;
        struct binder_transaction_data txn;
    } __attribute__((packed)) data;

    data.cmd_free = BC_FREE_BUFFER;
    data.buffer = buffer_to_free;
    data.cmd_reply = BC_REPLY;
    data.txn.target.ptr = 0;
    data.txn.cookie = 0;
    data.txn.code = 0;
    if (status) {
        //通信中產(chǎn)生了錯誤
        data.txn.flags = TF_STATUS_CODE;
        data.txn.data_size = sizeof(int);
        data.txn.offsets_size = 0;
        data.txn.data.ptr.buffer = (uintptr_t)&status;
        data.txn.data.ptr.offsets = 0;
    } else {
        //成功處理的一次通信請求
        data.txn.flags = 0;
        data.txn.data_size = reply->data - reply->data0;
        data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
        data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
        data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
    }
    //向Binder驅(qū)動寫入數(shù)據(jù)
    binder_write(bs, &data, sizeof(data));
}
  • 這里會將進程通信結(jié)果寫入到匿名struct data中破托,然后調(diào)用binder_write去向內(nèi)核寫入BC_FREE_BUFFER\BC_REPLY命令協(xié)議
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實際上還是通過IO控制命令寫入一個binder_write_read結(jié)構(gòu)體,注意這個結(jié)構(gòu)體輸入緩沖區(qū)是沒有數(shù)據(jù)的歧蒋,也就是說不需要處理返回協(xié)議
  • 略過各種調(diào)用我們來看內(nèi)核中binder_thread_write對于BC_FREE_BUFFER\BC_REPLY的處理
platform/drivers/staging/android/binder.c
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);
        ...
        switch (cmd) {
            ...
            case BC_TRANSACTION:
            case BC_REPLY: {
            struct binder_transaction_data tr;

            if (copy_from_user(&tr, ptr, sizeof(tr)))
                return -EFAULT;
            ptr += sizeof(tr);
            binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
            break;
            }
        ...
    }
  • BC_FREE_BUFFER主要是做一些資源釋放的操作土砂,感興趣可以自己看這里不再細看
  • 重點看BC_REPLY,查看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;
    binder_size_t *offp, *off_end;
    binder_size_t off_min;
    struct binder_proc *target_proc;
    struct binder_thread *target_thread = NULL;
    struct binder_node *target_node = NULL;
    struct list_head *target_list;
    wait_queue_head_t *target_wait;
    struct binder_transaction *in_reply_to = NULL;
    struct binder_transaction_log_entry *e;
    uint32_t return_error;
    ...
    if (reply) {
        //尋找請求通信的thread
        //從之前的thread中取出通信的binder_transaction_data
        in_reply_to = thread->transaction_stack;
        if (in_reply_to == NULL) {
            ...
            return_error = BR_FAILED_REPLY;
            goto err_empty_call_stack;
        }
        //恢復(fù)線程優(yōu)先級
        binder_set_nice(in_reply_to->saved_priority);
        if (in_reply_to->to_thread != thread) {
            ...
            return_error = BR_FAILED_REPLY;
            in_reply_to = NULL;
            goto err_bad_call_stack;
        }
        thread->transaction_stack = in_reply_to->to_parent;
        target_thread = in_reply_to->from;
        if (target_thread == NULL) {
            return_error = BR_DEAD_REPLY;
            goto err_dead_binder;
        }
        if (target_thread->transaction_stack != in_reply_to) {
            ...
            return_error = BR_FAILED_REPLY;
            in_reply_to = NULL;
            target_thread = NULL;
            goto err_dead_binder;
        }
        //目標(biāo)進程
        target_proc = target_thread->proc;
    }else{
        ...
    }
    //有空閑線程就是用空間線程的等待隊列,否則使用進程的
    if (target_thread) {
        ...
        target_list = &target_thread->todo;
        target_wait = &target_thread->wait;
    } else {
        ...
    }
    ...
    //創(chuàng)建binder_transaction結(jié)構(gòu)體谜洽,BINDER_WORK_TRANSACTION
    t = kzalloc(sizeof(*t), GFP_KERNEL);
    ...
    //創(chuàng)建binder_work結(jié)構(gòu)體,BINDER_STAT_TRANSACTION_COMPLETE
    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
    ...
    //分配事務(wù)t的要進入那個棧
    if (reply) {
        BUG_ON(t->buffer->async_transaction != 0);
        //將事務(wù)彈出todo棧
        binder_pop_transaction(target_thread, in_reply_to);
    } else if (!(t->flags & TF_ONE_WAY)) {
        ...
    }else{
        ...
    }
    //將binder_transaction_data指針t的類型修改為BINDER_WORK_TRANSACTION
    t->work.type = BINDER_WORK_TRANSACTION;
    //添加到target_list隊列尾部
    list_add_tail(&t->work.entry, target_list);
    //將binder_work指針tcomplete.type置為BINDER_WORK_TRANSACTION_COMPLETE
    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
    list_add_tail(&tcomplete->entry, &thread->todo);
    //這里有兩個執(zhí)行分支
    //1.處理類型為BINDER_WORK_TRANSACTION的binder_transaction_data
    //2.處理類型為BINDER_WORK_TRANSACTION_COMPLETE的binder_work
    if (target_wait)
        wake_up_interruptible(target_wait);
    return;
    ...
}   
  • 這里跟只愛去哪調(diào)用不同的地方在于走的是if分支萝映,需要查找到之前通信的目標(biāo)線程及進程,然后將上次通信的binder_transaction彈棧阐虚,然后回想之前通信的進程發(fā)送一個type為BINDER_WORK_TRANSACTION的binder_work序臂,之前那個進程對應(yīng)的binder_thread_read處理如下:
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;
    ...
    //線程喚醒
    while (1) {
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL;
        //檢查工作隊列,并將待處理項賦值給w
        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 {
            ...
        }
        ...
        switch (w->type) {
            case BINDER_WORK_TRANSACTION: {
                t = container_of(w, struct binder_transaction, work);
            } break;
            ...
        }
        //返回協(xié)議的處理实束,現(xiàn)在target_node指向的是binder_context_mgr_node
        if (t->buffer->target_node) {
            ...
        }else{
            tr.target.ptr = 0;
            tr.cookie = 0;
            cmd = BR_REPLY;
        }
        
        //Binder驅(qū)動程序分配給進程的內(nèi)核緩沖區(qū)同時奥秆,映射了用戶的內(nèi)核地址、用戶空間地址
        tr.data_size = t->buffer->data_size;
        tr.offsets_size = t->buffer->offsets_size;
        tr.data.ptr.buffer = (binder_uintptr_t)(
                    (uintptr_t)t->buffer->data +
                    proc->user_buffer_offset);
        //直接操作offsets
        tr.data.ptr.offsets = tr.data.ptr.buffer +
                    ALIGN(t->buffer->data_size,
                        sizeof(void *));

        //提供一個返回協(xié)議數(shù)據(jù)的緩沖區(qū)
        if (put_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        ptr += sizeof(uint32_t);
        if (copy_to_user(ptr, &tr, sizeof(tr)))
            return -EFAULT;
        ptr += sizeof(tr);
        ...
        //cmd = BR_TRANSACTION && 不是正在處理異步通信請求
        //就需要等待該同步進程通信完以后再進行下一步的操作
        if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
            ...
        } else {
            t->buffer->transaction = NULL;
            kfree(t);
            binder_stats_deleted(BINDER_STAT_TRANSACTION);
        }
        break;
    }
    ...
}
  • 這里就會封裝一個BR_REPLY返回協(xié)議咸灿,然后返回到IPCThreadState::waitForResponse中
  • 接下來看IPCThreadState::waitForResponse對于BR_REPLY的處理
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    ...
    while (1) {
        ...
        cmd = (uint32_t)mIn.readInt32();
        ...
        switch (cmd) {
            case BR_REPLY:
            {
                binder_transaction_data tr;
                err = mIn.read(&tr, sizeof(tr));
                ...
                if (reply) {
                  if ((tr.flags & TF_STATUS_CODE) == 0) {
                     //重置Parcel對象內(nèi)部數(shù)據(jù)緩沖區(qū)构订,并指定釋放函數(shù)為freeBuffer
                     reply->ipcSetDataReference(
                            reinterpret_cast
                            <const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast
                       <const binder_size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(binder_size_t),
                            freeBuffer, this);
                  } else {
                       ...
                } else {
                    ...
                }
            }
            goto finish;
            ...
        }
    }
    ...
}
  • 實際上會調(diào)用reply->ipcSetDataReference去重置數(shù)據(jù)緩沖區(qū),這里不再細述避矢,整個Service注冊就大致完成了悼瘾,后續(xù)還有Binder線程的啟動感興趣可以自行查看

ServiceManager查找服務(wù)

@Service的查找流程|center

完整的通信流程

@完整的通信流程

參考

Binder設(shè)計與實現(xiàn)
Android系統(tǒng)源代碼情景分析
Android - Binder 進程間通訊

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市谷异,隨后出現(xiàn)的幾起案子分尸,更是在濱河造成了極大的恐慌,老刑警劉巖歹嘹,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異孔庭,居然都是意外死亡尺上,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門圆到,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怎抛,“玉大人,你說我怎么就攤上這事芽淡÷砭” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵挣菲,是天一觀的道長富稻。 經(jīng)常有香客問我掷邦,道長,這世上最難降的妖魔是什么椭赋? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任抚岗,我火速辦了婚禮,結(jié)果婚禮上哪怔,老公的妹妹穿的比我還像新娘宣蔚。我一直安慰自己,他們只是感情好认境,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布胚委。 她就那樣靜靜地躺著,像睡著了一般叉信。 火紅的嫁衣襯著肌膚如雪篷扩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天茉盏,我揣著相機與錄音鉴未,去河邊找鬼。 笑死鸠姨,一個胖子當(dāng)著我的面吹牛铜秆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播讶迁,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼连茧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了巍糯?” 一聲冷哼從身側(cè)響起啸驯,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎祟峦,沒想到半個月后罚斗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡宅楞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年针姿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厌衙。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡距淫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出婶希,到底是詐尸還是另有隱情榕暇,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站彤枢,受9級特大地震影響狰晚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜堂污,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一家肯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧盟猖,春花似錦讨衣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至娘汞,卻和暖如春歹茶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背你弦。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工惊豺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人禽作。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓尸昧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親旷偿。 傳聞我的和親對象是個殘疾皇子烹俗,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容