Binder 驅(qū)動(dòng)和 ServiceManager 通信流程

前言

本文基于 linux 3.18 和 Android 9.0 版本源碼,涉及的源碼文件路徑為:

背景

整理 Android Binder IPC 知識(shí)點(diǎn),記錄閱讀 Binder 源碼的理解

是什么

Binder IPC 四大模塊
  • Binder 驅(qū)動(dòng)是 Binder IPC 架構(gòu)中內(nèi)核層程序,負(fù)責(zé)處理應(yīng)用層發(fā)送過來的請(qǐng)求,完成多進(jìn)程間傳輸數(shù)據(jù)功能
  • ServiceManager 是應(yīng)用層程序,本身是一個(gè) Binder Server,負(fù)責(zé)記錄和查找系統(tǒng)中其他 Binder Server,完成 Binder 標(biāo)識(shí)符到 Binder 實(shí)體的轉(zhuǎn)換功能
  • 本文主要記錄這兩者之間的通信流程

時(shí)序圖

Binder 驅(qū)動(dòng)和 ServiceManager 通信時(shí)序圖
  • 系統(tǒng)啟動(dòng)時(shí)執(zhí)行 device_initcall 函數(shù)完成驅(qū)動(dòng)初始化
static int __init binder_init(void)
{
    // 我運(yùn)行在內(nèi)核啟動(dòng)時(shí)加載驅(qū)動(dòng)的線程
    ...
    ret = misc_register(&binder_miscdev);
    ...
}
  • Binder 驅(qū)動(dòng)向系統(tǒng)注冊(cè)名字為 “binder” 的 misc 設(shè)備。注冊(cè)的目的是為了之后系統(tǒng)中可以查找到該驅(qū)動(dòng),否則打開 Binder 驅(qū)動(dòng)失敗
static struct miscdevice binder_miscdev = {
    .minor = MISC_DYNAMIC_MINOR,
    // 注冊(cè)的設(shè)備名稱。接下來通過 open 系統(tǒng)調(diào)用可以查找到是我
    .name = "binder",
    .fops = &binder_fops
};
  • 接下來系統(tǒng)執(zhí)行 ServiceManager 啟動(dòng)的 main 函數(shù)
int main(int argc, char** argv)
{
    ...
    if (argc > 1) {
        driver = argv[1];
    } else {
        // 驅(qū)動(dòng)名稱。對(duì)應(yīng) binder driver 注冊(cè)的名稱
        driver = "/dev/binder";
    }

    // 打開 binder driver,并映射虛擬內(nèi)存 128K
    bs = binder_open(driver, 128*1024);
    ...
}
  • ServiceManager 通過 open 函數(shù)打開 binder 設(shè)備
struct binder_state *binder_open(const char* driver, size_t mapsize)
{
    ...
    //系統(tǒng)調(diào)用 open,跳轉(zhuǎn)到內(nèi)核代碼段執(zhí)行
    bs->fd = open(driver, O_RDWR | O_CLOEXEC);
    ...
}
  • ServiceManager 通過 ioctl 函數(shù)發(fā)送命令 BINDER_VERSION 讀取內(nèi)核 Binder 驅(qū)動(dòng)的版本號(hào)。如果應(yīng)用層的 Binder 版本號(hào)和驅(qū)動(dòng)層的 Binder 版本號(hào)不一致,則無法啟動(dòng) ServiceManager 程序
struct binder_state *binder_open(const char* driver, size_t mapsize)
{
    ...
    if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
        (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
        fprintf(stderr,
                "binder: kernel driver version (%d) differs from user space version (%d)\n",
                vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
        goto fail_open;
    }
    ...
}
  • ServiceManager 通過 mmap 函數(shù)請(qǐng)求映射 128 KB 虛擬內(nèi)存,目的是讓 Binder 驅(qū)動(dòng)和當(dāng)前進(jìn)程的虛擬內(nèi)存映射到共享的物理頁面。這樣其他進(jìn)程向內(nèi)核空間地址寫入數(shù)據(jù)之后,ServiceManger 用戶空間也可以讀取到相應(yīng)的數(shù)據(jù),完成通信
struct binder_state *binder_open(const char* driver, size_t mapsize)
{
    ...
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
    if (bs->mapped == MAP_FAILED) {
        fprintf(stderr,"binder: cannot map device (%s)\n",
                strerror(errno));
        goto fail_map;
    }
    ...
}
  • ServiceManager 通過 ioctl 系統(tǒng)調(diào)用發(fā)送 BINDER_SET_CTX_MANAGER 命令給 Binder 驅(qū)動(dòng),目的是在內(nèi)核地址空間記錄 ServiceManger 這個(gè) Binder Server,這樣接下來各個(gè) Binder Client 可以從 Binder 驅(qū)動(dòng)拿到 ServiceManager 這個(gè) Binder Server
int binder_become_context_manager(struct binder_state *bs)
{
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
  • SM 進(jìn)入循環(huán)之前通知 BD 我要進(jìn)入循環(huán)了
void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    // binder 調(diào)用方和 binder driver 調(diào)用參數(shù)結(jié)構(gòu)體
    struct binder_write_read bwr;
    // 讀取緩沖區(qū)大小 32 * 4 = 128 字節(jié)
    uint32_t readbuf[32];

    // 寫入緩沖區(qū)大小為 0 字節(jié),說明調(diào)用方不需要寫入數(shù)據(jù)
    bwr.write_size = 0;
    // 寫入緩沖區(qū)已經(jīng)消費(fèi)的字節(jié)長度為 0,說明為消費(fèi)數(shù)據(jù)
    bwr.write_consumed = 0;
    // 寫入緩沖區(qū)為空
    bwr.write_buffer = 0;

    // 讀取緩沖區(qū)前 4 個(gè)字節(jié)寫入命令字 BC_ENTER_LOOPER,通知 binder driver 我要進(jìn)入
    // 循環(huán)事件處理了
    readbuf[0] = BC_ENTER_LOOPER;
    // 向 binder driver 寫入命令字
    binder_write(bs, readbuf, sizeof(uint32_t));
    ...
}
  • 最后 ServiceManager 進(jìn)入一個(gè)事件驅(qū)動(dòng)循環(huán),循環(huán)通過 ioctl 系統(tǒng)調(diào)用讀取 Binder Driver 寫入的來自其他 Binder Client 發(fā)送的請(qǐng)求
void binder_loop(struct binder_state *bs, binder_handler func)
{
    ...
    for (;;) {
        // 讀取緩沖區(qū)大小 128 字節(jié)
        bwr.read_size = sizeof(readbuf);
        // 可寫入偏移量為 0
        bwr.read_consumed = 0;
        // 緩沖區(qū)地址/指針
        bwr.read_buffer = (uintptr_t) readbuf;

        // 調(diào)用 ioctl 系統(tǒng)調(diào)用進(jìn)入內(nèi)核代碼讀取內(nèi)核 binder driver 收到的命令
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
        ...

        // 解析讀取到的命令
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        ...
    }
}
  • ServiceManager 讀取請(qǐng)求、解析請(qǐng)求、處理請(qǐng)求
  • ServiceManager 通過 ioctl 系統(tǒng)調(diào)用發(fā)送響應(yīng)給 Binder Driver
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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