Binder设备打开
用户态执行 open("/dev/binder") 后,拿到的不只是一个能传给 ioctl() 的整数。内核会为这次 打开建立 binder_proc,记录打开者的进程身份、凭证、Binder context、工作队列、线程集合和 allocator 元数据,并把它挂到这个 struct file 的 private_data 上。后续 mmap、ioctl、 poll 和关闭都从这里找回同一份状态。
本文面向已经读过 Binder协议状态机 和 Binder线程状态模型 的读者,回答一个 更靠近驱动入口的问题:一次设备打开如何变成可供后续事务使用的进程级内核状态,又如何在关闭时 安全收束。
本文不展开 binder_mmap() 的页分配算法,不讲 BINDER_WRITE_READ 命令分发,也不把 binder_proc 的全部字段做成参考手册。读完后,读者应能从 ProcessState::open_driver() 走到 binder_open(),区分 binder_proc、binder_context 和 binder_alloc 的 owner,并判断 “open 成功”“mmap 完成”“资源已经释放”分别处于哪个阶段。
1. 问题边界
先把三个容易混在一起的动作分开:
| 阶段 | 用户态动作 | 驱动入口 | 主要结果 |
|---|---|---|---|
| 打开设备 | open() | binder_open() | 创建 binder_proc 和 allocator 元数据 |
| 建立映射 | mmap() | binder_mmap() | 建立 transaction address space |
| 发送命令 | ioctl() | binder_ioctl() | 创建线程状态并处理 BC/BR 协议 |
binder_open() 只完成第一行。它没有预先创建 Binder 线程,没有分配事务 buffer 页面,也没有把 当前进程注册成 context manager。把这三个阶段合成“打开 Binder 驱动”会掩盖真正的失败边界: 文件描述符可能已经打开,但版本协商或 mmap() 仍可能失败。
2. 设备入口
2.1 用户态打开
源码文件:frameworks/native/libs/binder/ProcessState.cpp
相关函数:open_driver()
static unique_fd open_driver(
const char* driver,
String8* error) {
auto fd = unique_fd(
open(driver, O_RDWR | O_CLOEXEC));
if (!fd.ok()) {
error->appendFormat(
"%d (%s) Opening '%s' failed",
errno, strerror(errno), driver);
return {};
}
int vers = 0;
int result = ioctl(
fd.get(), BINDER_VERSION, &vers);
if (result == -1) {
error->appendFormat(
"%d (%s) Binder ioctl to obtain "
"version failed",
errno, strerror(errno));
return {};
}
if (result != 0 ||
vers != BINDER_CURRENT_PROTOCOL_VERSION) {
error->appendFormat(
"Binder driver protocol(%d) does not "
"match user space protocol(%d)! "
"ioctl() return value: %d",
vers,
BINDER_CURRENT_PROTOCOL_VERSION,
result);
return {};
}
// 后续还会设置线程数和 oneway 检测。
return fd;
}open_driver() 的第一个系统调用才触发内核 binder_open()。返回以后,libbinder 立即查询协议 版本;因此用户态所说的“驱动可用”比内核 open() 成功更严格。若版本查询失败或不匹配,局部 unique_fd 析构并关闭 fd,刚创建的 binder_proc 随后进入释放路径。
O_CLOEXEC 约束 fd 不跨 exec 泄漏,但不改变 binder_proc 的创建逻辑。O_NONBLOCK 也不是 打开阶段的必要条件:驱动接口测试会使用它,而 ProcessState 的正常入口没有使用它。
2.2 文件操作表
源码文件:kernel/common/drivers/android/binder.c
相关符号:binder_fops
const struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
.unlocked_ioctl = binder_ioctl,
.compat_ioctl = compat_ptr_ioctl,
.mmap = binder_mmap,
.open = binder_open,
.flush = binder_flush,
.release = binder_release,
};Binder 设备注册时把 binder_fops 交给 misc device 或 binderfs device。VFS 打开设备后调用 .open;同一 struct file 以后再通过 .mmap、.unlocked_ioctl 和 .poll 使用 filp->private_data 中的 binder_proc。
这张表也给出了生命周期的两端:binder_open() 创建状态,binder_flush() 促使 looper 返回, binder_release() 安排最终清理。release 没有直接指向 kfree(proc),因为事务、线程和临时引用 可能仍在使用这份状态。
2.3 设备前置
源码文件:kernel/common/drivers/android/binder.c
相关函数:init_binder_device()
static int __init init_binder_device(
const char *name) {
int ret;
struct binder_device *binder_device;
binder_device = kzalloc(
sizeof(*binder_device), GFP_KERNEL);
if (!binder_device)
return -ENOMEM;
binder_device->miscdev.fops = &binder_fops;
binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;
binder_device->miscdev.name = name;
refcount_set(&binder_device->ref, 1);
binder_device->context
.binder_context_mgr_uid = INVALID_UID;
binder_device->context.name = name;
mutex_init(&binder_device->context
.context_mgr_node_lock);
ret = misc_register(&binder_device->miscdev);
if (ret < 0) {
kfree(binder_device);
return ret;
}
binder_add_device(binder_device);
return ret;
}打开之前,设备已经拥有 binder_device 和内嵌的 binder_context。因此 binder_open() 的职责 不是创建一个新的 Binder 世界,而是让本次打开加入某个已经存在的 context。context manager 节点、名称和 manager UID 属于设备 context;线程、node、ref 和工作队列属于本次打开创建的 binder_proc。
3. Proc创建
3.1 内存与身份
源码文件:kernel/common/drivers/android/binder.c
相关函数:binder_open()
static int binder_open(
struct inode *nodp,
struct file *filp) {
struct binder_proc *proc, *itr;
struct binder_device *binder_dev;
struct binderfs_info *info;
struct dentry *proc_log_dir = NULL;
bool existing_pid = false;
proc = kzalloc(sizeof(*proc), GFP_KERNEL);
if (proc == NULL)
return -ENOMEM;
dbitmap_init(&proc->dmap);
spin_lock_init(&proc->inner_lock);
spin_lock_init(&proc->outer_lock);
get_task_struct(current->group_leader);
proc->tsk = current->group_leader;
proc->cred = get_cred(filp->f_cred);
INIT_LIST_HEAD(&proc->todo);
init_waitqueue_head(&proc->freeze_wait);
// 后续继续选择 context、初始化 alloc 并登记。当前实现直接分配 struct binder_proc。这里没有 binder_proc_wrap;若在其他内核分支看到包装 结构,必须回到对应分支重新核对,不能套用到当前源码。
kzalloc 把红黑树根、计数器和布尔状态置零,显式初始化则用于锁、链表、等待队列和 dbitmap。 proc->tsk 持有 group leader 的 task 引用,proc->pid 后面也取 group leader PID;这说明 binder_proc 表示进程级 Binder 状态,而不是触发 open() 的某一个线程。
凭证来自 filp->f_cred,并通过 get_cred() 持有引用。它是打开文件时与 file 绑定的凭证快照, 不是每次 ioctl 都从当前线程重新取一份。最终 binder_free_proc() 会分别 put_task_struct() 和 put_cred(),所有权闭环必须成对阅读。
3.2 默认优先级
源码文件:kernel/common/drivers/android/binder.c
相关函数:binder_open()、binder_supported_policy()
if (binder_supported_policy(current->policy)) {
proc->default_priority.sched_policy =
current->policy;
proc->default_priority.prio =
current->normal_prio;
} else {
proc->default_priority.sched_policy =
SCHED_NORMAL;
proc->default_priority.prio =
NICE_TO_PRIO(0);
}驱动在打开时记录一个进程默认优先级。只有 Binder 支持的调度策略才原样保存,否则回落到 SCHED_NORMAL 和 nice 0 对应的内部优先级。这个值是后续事务优先级选择的输入之一,不等于 此刻创建了线程,也不保证每次事务都使用它。
3.3 初始容器
源码文件:kernel/common/drivers/android/binder.c
相关函数:binder_open()
binder_stats_created(BINDER_STAT_PROC);
proc->pid = current->group_leader->pid;
INIT_LIST_HEAD(&proc->delivered_death);
INIT_LIST_HEAD(&proc->delivered_freeze);
INIT_LIST_HEAD(&proc->waiting_threads);
filp->private_data = proc;这几条链表分别承接已投递死亡通知、已投递冻结通知和可消费进程级工作的等待线程。此时它们都 为空;线程红黑树、node 红黑树和 ref 红黑树也尚未填入元素。第一次相关 ioctl 才会逐步创建 binder_thread、binder_node 或 binder_ref。
最关键的绑定是 filp->private_data = proc。后续驱动回调不需要按 PID 猜测调用者属于哪个打开 实例,而是从当前 file 精确取回 owner。这也是“一个 PID”不能直接等价于“一个 binder_proc” 的原因。
4. Context归属
相关源码:
kernel/common/drivers/android/binder.ckernel/common/drivers/android/binder_internal.h
相关符号:binder_open()、binder_device、binder_context
/* binderfs stashes devices in i_private */
if (is_binderfs_device(nodp)) {
binder_dev = nodp->i_private;
info = nodp->i_sb->s_fs_info;
binder_binderfs_dir_entry_proc =
info->proc_log_dir;
} else {
binder_dev = container_of(
filp->private_data,
struct binder_device,
miscdev);
}
refcount_inc(&binder_dev->ref);
proc->context = &binder_dev->context;驱动支持两种设备来源:
- binderfs 设备从 inode 的
i_private取binder_device; - 传统 misc device 在进入
binder_open()前,filp->private_data仍指向miscdevice,驱动用container_of找回外层binder_device。
找到设备后,binder_open() 增加 device 引用并把 context 地址保存到 proc。关闭 proc 时, binder_free_proc() 再减少引用;如果设备本身已经撤销且最后一个 proc 也消失,device 才能释放。
binder_context 至少拥有 context manager 节点、manager UID、名称和保护 manager 节点的 mutex。 同一个进程若打开不同 Binder 设备,会得到指向不同 context 的 binder_proc。即使打开同一设备 多次,每次成功的 binder_open() 也会分配新的 proc;后面的同 PID 检查只决定调试文件是否重复 创建,并不把两个 proc 合并。
5. Alloc初始化
源码文件:kernel/common/drivers/android/binder_alloc.c
相关函数:binder_alloc_init()、__binder_alloc_init()
VISIBLE_IF_KUNIT void __binder_alloc_init(
struct binder_alloc *alloc,
struct list_lru *freelist) {
alloc->pid = current->group_leader->pid;
alloc->mm = current->mm;
mmgrab(alloc->mm);
mutex_init(&alloc->mutex);
INIT_LIST_HEAD(&alloc->buffers);
alloc->freelist = freelist;
}
void binder_alloc_init(
struct binder_alloc *alloc) {
__binder_alloc_init(
alloc, &binder_freelist);
}binder_alloc 内嵌在 binder_proc 中,owner 仍是这次设备打开。初始化阶段只保存 PID、打开时的 mm_struct、allocator mutex、buffer 链表和全局 LRU;mmgrab() 保证即使进程内存上下文进入 退出流程,allocator 在清理完成前仍能安全引用 mm。
这里没有创建 pages 数组,没有建立初始 free buffer,也没有把 mapped 设为 true。这些状态 属于 binder_alloc_mmap_handler():它根据 VMA 大小建立页指针数组,创建覆盖整段映射的初始空闲 buffer,最后才用 binder_alloc_set_mapped(alloc, true) 发布“映射完成”。
这个拆分形成一个重要不变量:
open 成功
⇒ alloc 拥有 mm、mutex、buffers list 和 freelist
⇏ alloc 已映射
⇏ alloc 已拥有 transaction pages因此只打开再关闭必须安全;驱动不能假定每个 binder_proc 都经过 mmap。
6. 全局登记
源码文件:kernel/common/drivers/android/binder.c
相关函数:binder_open()
mutex_lock(&binder_procs_lock);
hlist_for_each_entry(
itr, &binder_procs, proc_node) {
if (itr->pid == proc->pid) {
existing_pid = true;
break;
}
}
hlist_add_head(&proc->proc_node, &binder_procs);
mutex_unlock(&binder_procs_lock);binder_procs 是驱动全局观察所有打开实例的 hlist,修改由 binder_procs_lock 保护。代码先检查 是否已存在相同 group leader PID,再无条件把新的 proc 加入表头。由此可以直接排除一个常见误读: existing_pid 不是“拒绝重复打开”的条件。
它的消费者位于紧随其后的调试入口创建逻辑:
if (binder_debugfs_dir_entry_proc &&
!existing_pid) {
snprintf(strbuf, sizeof(strbuf),
"%u", proc->pid);
proc->debugfs_entry = debugfs_create_file(
strbuf, 0444,
binder_debugfs_dir_entry_proc,
(void *)(unsigned long)proc->pid,
&proc_fops);
}
if (binder_binderfs_dir_entry_proc &&
!existing_pid) {
binderfs_entry = binderfs_create_file(
binder_binderfs_dir_entry_proc,
strbuf, &proc_fops,
(void *)(unsigned long)proc->pid);
if (!IS_ERR(binderfs_entry))
proc->binderfs_entry = binderfs_entry;
}同 PID 的不同 context 共享按 PID 命名的 debugfs/binderfs 日志入口,打印代码会汇总该 PID 的各个 context。binderfs 日志文件创建失败只记录 warning,binder_open() 仍返回成功;调试能力不是 IPC 可用性的硬前置。
7. 关闭收束
7.1 flush路径
源码文件:kernel/common/drivers/android/binder.c
相关函数:binder_flush()、binder_deferred_flush()
static int binder_flush(
struct file *filp,
fl_owner_t id) {
struct binder_proc *proc =
filp->private_data;
binder_defer_work(
proc, BINDER_DEFERRED_FLUSH);
return 0;
}
static void binder_deferred_flush(
struct binder_proc *proc) {
struct rb_node *n;
binder_inner_proc_lock(proc);
for (n = rb_first(&proc->threads);
n != NULL; n = rb_next(n)) {
struct binder_thread *thread =
rb_entry(n, struct binder_thread,
rb_node);
thread->looper_need_return = true;
if (thread->looper &
BINDER_LOOPER_STATE_WAITING)
wake_up_interruptible(&thread->wait);
}
binder_inner_proc_unlock(proc);
}flush 不释放 proc。它在 worker 中遍历线程,把 looper_need_return 置为 true,并唤醒正在等待的 looper。消费者是 binder_has_work_ilocked() 和读循环:线程醒来后观察该标志,从驱动返回用户态。
这条路径解决的是“不要让关闭中的进程仍永久睡在 Binder wait queue”,而不是“立即销毁全部 对象”。把它和 release 分开,能够避免一边持有 VFS 关闭上下文,一边执行大规模线程、node、ref 和 transaction 清理。
7.2 release路径
源码文件:kernel/common/drivers/android/binder.c
相关函数:binder_release()、binder_defer_work()
static int binder_release(
struct inode *nodp,
struct file *filp) {
struct binder_proc *proc =
filp->private_data;
debugfs_remove(proc->debugfs_entry);
if (proc->binderfs_entry) {
simple_recursive_removal(
proc->binderfs_entry, NULL);
proc->binderfs_entry = NULL;
}
binder_defer_work(
proc, BINDER_DEFERRED_RELEASE);
return 0;
}
static void binder_defer_work(
struct binder_proc *proc,
enum binder_deferred_state defer) {
guard(mutex)(&binder_deferred_lock);
proc->deferred_work |= defer;
if (hlist_unhashed(
&proc->deferred_work_node)) {
hlist_add_head(
&proc->deferred_work_node,
&binder_deferred_list);
schedule_work(&binder_deferred_work);
}
}release 先撤掉这个 proc 自己拥有的调试入口,再把 RELEASE 位合并进 proc->deferred_work。同一个 proc 的 FLUSH 和 RELEASE 可以合并在一项 deferred work 中;worker 按 flush 在前、release 在后的 顺序处理,避免先释放 proc 再访问线程集合。
7.3 延迟释放
相关源码:
kernel/common/drivers/android/binder.ckernel/common/drivers/android/binder_alloc.c
相关函数:binder_deferred_release()、binder_free_proc()、 binder_alloc_deferred_release()
binder_deferred_release() 先把 proc 从全局 binder_procs 删除,再在 context 锁下撤销可能由它 拥有的 context manager 节点。随后它标记 is_dead,逐项收束:
- 从
proc->threads移除线程并处理仍活动的 transaction stack; - 从
proc->nodes移除本地 node,必要时向远端 ref 投递死亡通知; - 清理
refs_by_desc中的远端引用; - 释放 proc todo、已投递死亡通知和冻结通知;
- 通过
tmp_ref判断是否已经无人再使用 proc。
真正释放 proc 的条件位于 binder_proc_dec_tmpref():
static void binder_proc_dec_tmpref(
struct binder_proc *proc) {
binder_inner_proc_lock(proc);
proc->tmp_ref--;
if (proc->is_dead &&
RB_EMPTY_ROOT(&proc->threads) &&
!proc->tmp_ref) {
binder_inner_proc_unlock(proc);
binder_free_proc(proc);
return;
}
binder_inner_proc_unlock(proc);
}所以 fd 关闭不是 binder_proc 立即 kfree 的同义词。只要清理中的线程或事务仍持有临时引用, proc 就继续存活;最后一个临时使用者归还引用时才触发 binder_free_proc()。
源码文件:kernel/common/drivers/android/binder.c
相关函数:binder_free_proc()
static void binder_free_proc(
struct binder_proc *proc) {
struct binder_device *device;
BUG_ON(!list_empty(&proc->todo));
BUG_ON(!list_empty(&proc->delivered_death));
device = container_of(
proc->context,
struct binder_device, context);
if (refcount_dec_and_test(&device->ref)) {
binder_remove_device(device);
kfree(proc->context->name);
kfree(device);
}
binder_alloc_deferred_release(&proc->alloc);
put_task_struct(proc->tsk);
put_cred(proc->cred);
binder_stats_deleted(BINDER_STAT_PROC);
dbitmap_free(&proc->dmap);
kfree(proc);
}最终释放顺序与打开时的所有权一一对应:device ref、allocator、task ref、cred ref、统计、dbitmap 和 proc 本体都在这里归还。BUG_ON 还表达了释放前不变量:proc todo 和已投递死亡通知必须已经 清空,不能靠 kfree 隐式丢弃。
8. 映射边界
源码文件:kernel/common/drivers/android/binder.c
相关函数:binder_mmap()、binder_vma_close()
static int binder_mmap(
struct file *filp,
struct vm_area_struct *vma) {
struct binder_proc *proc =
filp->private_data;
if (proc->tsk != current->group_leader)
return -EINVAL;
vm_flags_mod(vma,
VM_DONTCOPY | VM_MIXEDMAP,
VM_MAYWRITE);
vma->vm_ops = &binder_vm_ops;
vma->vm_private_data = proc;
return binder_alloc_mmap_handler(
&proc->alloc, vma);
}
static void binder_vma_close(
struct vm_area_struct *vma) {
struct binder_proc *proc =
vma->vm_private_data;
binder_alloc_vma_close(&proc->alloc);
}映射只能由打开时记录的同一个 group leader 建立,否则返回 -EINVAL。VMA 再次把 proc 保存到 vm_private_data,关闭映射时把 allocator 的 mapped 状态清掉,阻止新的 incoming transaction 继续分配 buffer。
allocator 最终释放还有一道硬约束:
void binder_alloc_deferred_release(
struct binder_alloc *alloc) {
mutex_lock(&alloc->mutex);
BUG_ON(alloc->mapped);
while ((n = rb_first(
&alloc->allocated_buffers))) {
buffer = rb_entry(
n, struct binder_buffer, rb_node);
BUG_ON(buffer->transaction);
binder_free_buf_locked(alloc, buffer);
}
// 继续释放 buffer 描述、安装页面和 LRU 状态。
mutex_unlock(&alloc->mutex);
kvfree(alloc->pages);
if (alloc->mm)
mmdrop(alloc->mm);
}BUG_ON(alloc->mapped) 要求 VMA 生命周期先收束,BUG_ON(buffer->transaction) 要求活动事务先 解除。完整顺序不是简单的 close(fd) → free pages,而是文件、VMA、事务和临时引用共同满足清理 条件后,allocator 才释放页面数组并归还 mmgrab() 对应的 mm 引用。
9. 测试输入
9.1 OpenNoMmap
源码文件:frameworks/native/libs/binder/tests/binderDriverInterfaceTest.cpp
相关测试:BinderDriverInterfaceTest.OpenNoMmap
TEST_F(BinderDriverInterfaceTest, OpenNoMmap) {
int binderFd = open(
BINDER_DEV_NAME,
O_RDWR | O_NONBLOCK | O_CLOEXEC);
ASSERT_GE(binderFd, 0);
close(binderFd);
}测试输入是一次没有后续 mmap 的独立设备打开。关键断言只有 fd >= 0,随后立即关闭。它验证了 两个边界:binder_open() 不依赖 transaction mapping 才能成功;从未映射的 allocator 也必须能 通过关闭路径安全清理。
它没有查询协议版本,没有发送 ioctl,也没有断言 debugfs 内容,因此不能用来证明完整 libbinder 初始化成功、事务可收发或调试节点一定创建。
9.2 Alloc KUnit
源码文件:kernel/common/drivers/android/tests/binder_alloc_kunit.c
相关测试:binder_alloc_test_init_freelist()、binder_alloc_test_mmap()、 binder_alloc_test_exit()
static void binder_alloc_test_init_freelist(
struct kunit *test) {
struct binder_alloc_test *priv = test->priv;
KUNIT_EXPECT_PTR_EQ(
test, priv->alloc.freelist,
&priv->binder_test_freelist);
}
static void binder_alloc_test_mmap(
struct kunit *test) {
struct binder_alloc_test *priv = test->priv;
struct binder_alloc *alloc =
&priv->alloc;
KUNIT_EXPECT_EQ(test, alloc->mapped, true);
KUNIT_EXPECT_EQ(
test, alloc->buffer_size,
BINDER_MMAP_SIZE);
KUNIT_EXPECT_PTR_EQ(
test,
rb_first(&alloc->allocated_buffers),
NULL);
}fixture 先附着一个 mm,再调用 __binder_alloc_init(),随后通过测试 file 建立映射。第一个测试断言 初始化选择了 fixture 的 LRU;第二个测试断言 mmap 以后 mapped 为 true、映射大小正确、尚无已分配 事务 buffer,并检查整段空间形成一个 free buffer。
teardown 关闭 backing file,调用 binder_alloc_deferred_release(),最后断言测试 LRU 为空。它验证 allocator 的 init、mmap、VMA close 和 deferred release 可以形成闭环,但 fixture 没有创建完整 binder_proc,也没有覆盖 node、ref、死亡通知或活动事务清理。
10. 失败路径
binder_open() 自身的硬失败点很少,但边界非常明确:
| 位置 | 结果 | 已建立状态 | 恢复方式 |
|---|---|---|---|
kzalloc(proc) 失败 | -ENOMEM | 无 proc、无引用 | 用户态收到 open 失败,可在资源恢复后重试 |
| debugfs 不可用 | 不影响返回值 | proc 已登记 | IPC 继续工作,仅缺少该入口 |
| binderfs 日志创建失败 | warning,仍返回 0 | proc 已登记 | IPC 继续工作,可查挂载与权限 |
BINDER_VERSION 失败 | open 已成功,libbinder 判失败 | proc 等待 fd 关闭清理 | 检查驱动/UAPI 匹配 |
mmap 失败 | open 已成功,ProcessState 关闭 fd | proc 和 alloc 元数据已存在 | 检查 VMA 条件与内存失败点 |
binder_alloc_init() 没有错误返回;它只获取 mm 引用和初始化元数据。真正可能返回 -EINVAL、 -EPERM、-EBUSY 或 -ENOMEM 的地址空间条件位于 mmap 阶段,应在映射专题中继续展开。
打开函数本身也没有“取消后恢复”的异步状态机:它在当前系统调用内完成或返回 -ENOMEM。与取消 最接近的动作是上层在版本或 mmap 失败后关闭 fd;恢复不是复用已经 release 的 proc,而是重新执行 一次 open,建立新的 file 和新的 binder_proc。
11. 源码复现
打开到可用
这张图只覆盖设备打开与可用前置;真正的 VMA 映射、页安装和 ioctl 事务分别由 BD014~BD017 负责, 不要在本篇把 fd 返回误读为服务已经能收发事务。
在对应源码 checkout 中,可以用以下只读命令重走本文主线:
rg -n "open_driver|ProcessState::ProcessState" \
frameworks/native/libs/binder/ProcessState.cpp
rg -n "binder_fops|binder_open|binder_flush|binder_release" \
kernel/common/drivers/android/binder.c
rg -n "binder_alloc_init|binder_alloc_deferred_release" \
kernel/common/drivers/android/binder_alloc.c
rg -n "OpenNoMmap|binder_alloc_test_mmap" \
frameworks/native/libs/binder/tests/binderDriverInterfaceTest.cpp \
kernel/common/drivers/android/tests/binder_alloc_kunit.c阅读时尝试回答四个问题:filp->private_data 在何时从 device 信息变成 proc;同 PID 重复打开为何 仍会新增 proc;从未 mmap 的 allocator 为什么可以释放;活动事务为何会推迟最终 kfree(proc)。 如果这四个问题都能从代码指出具体字段和分支,就已经建立了设备打开的完整生命周期模型。
继续阅读 事务数据生命周期,可以把这里创建的 proc/alloc owner 接到真实事务 buffer 的分配、交付和回收;回看 引用计数闭环,可以进一步理解 deferred release 为什么必须先清理 node、ref 和死亡通知,不能在 binder_release() 中直接释放整个 proc。
