前言
本文基于 linux 3.18 和 Android 9.0 版本源碼,涉及的源碼文件路徑為:
- Binder 驅(qū)動(dòng)
http://androidxref.com/kernel_3.18/xref/drivers/staging/android/binder.c - ServiceManager
背景
整理 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