binder mmap 的内存是每个进程独立的吗?会存在拷贝?
是独立的(1MB - 8KB),用于接收数据。发送 BC_TRANSACTION/BC_REPLY (请求/回包)的时候拷贝buffer(参数)和 offsets(参数中binder对象的偏移)到目标进程的 mmap 内存区,只拷贝这一次。
如果所有进程共享这部分内存,要 mmap 更大的用户内存空间满足同等吞吐量,而且非常不安全,因为任意进程都能读并猜测其他进程传输的数据。
说是说一次拷贝,但是读数据时(talkWithDriver)是用 Parcel 承载数据的啊,不用再拷贝一下吗?
那是包头,固定大小的。buffer 和 offsets 是跨进程一次拷贝,这个长度可变的才是最闹心的。
BINDER_SET_MAX_THREADS 限制的是谁的线程数?
ProcessState.cpp : open_driver 将这个值设置为 15
限制的是当前进程的 loop 线程(循环取 binder 请求并执行的线程)个数
这个线程数不包含用户主动启动的loop线程(spawnPooledThread(true)),MediaPlayerService 就主动启动了两个,所以它最多将会有17个 loop 线程。
当 binder_thread_read 发现当前进程的所有的 loop 线程都在干活(没活干的时候会在 binder_thread_read 中 wait,有统计这些"闲人"的个数),会将回包中第一条BR_NOOP(自动插的,上层自动忽略这条命令)换成 BR_SPAWN_LOOPER 命令,调用者读到该指令会启动一个新 loop 线程(spawnPooledThread(false))
service_manager.c
负责注册查询所有命名 binder,是单线程的纯C程序,没有使用 ProcessState IPCThreadState 等 C++ 封装对象,如果要写可执行程序可以 copy 这里的实现。
addService 同名怎么办?
- root 用户随便加
- 其他要判断 allowed 列表(只是系统的一些uid可以重复 add 同名service)
fork 出来的子进程不能进行 binder 通信的原因
- binder_proc 被绑定在 open(/dev/binder) 打开的 struct file 上(private_data成员),fork 后子进程共享父进程的 file 对象,所以子进程调用 ioctl 最终是用父进程的 binder_proc 发包的,回包也会把数据填到父进程 mmap 内存区(这种情况下内核没有崩溃也是奇迹了o(╯□╰)o)。
- binder_mmap 中分配内存时加了 VM_DONTCOPY 标志,fork 时这部分内存页不会拷贝,所以子进程中就没有这块内存了(尝试读取回包数据时会发生缺页异常,因为 data 和 offsets 就在这片地址空间中):
vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE;
总之就是一旦已经打开过 /dev/binder,那 fork 出来的子进程就不能继续用 binder 了,除非用 exec 系列函数重新投胎。
一次 read/write 可以处理几个 binder_transaction_data?
binder_thread_read 读到一个 binder_transaction_data 就会返回。
binder_thread_write 理论上可以写多个 binder_transaction_data,因为不是由它来执行,只管发到目标进程就行,它接下来会 wait 等回包,不知道哪个先到,所以实际上是不可行的。
BC BR 怎么转换的?
BC_XXX 是发送(ioctl)
BR_XXX 是接收(waitForResponse)
在驱动中转换了:
BC_TRANSACTION ->
目标进程 BINDER_WORK_TRANSACTION(binder_work.type) ->
目标进程读 BR_TRANSACTION
BINDER_WORK_TRANSACTION_COMPLETE ->
本线程 BR_TRANSACTION_COMPLETE
文件形式的binder 是什么鬼?
共享 struct file,读写位置也是共享的。
bwr.read_consumed 是驱动读了多少数据到 mIn 吧?
是的。
binder 推荐教程
Android深入浅出之Binder机制 —— 讲的是用户态 binder 的实现,没讲驱动,但是用户态的逻辑更绕,先要理解用户态的需求,才能明白驱动为什么要那么实现,所以应该先看这个。
Android Binder设计与实现 - 设计篇 —— 讲的是 binder 驱动,没有按源码分析,是作者根据源码总结的,把"怎么实现的"和"为什么这么实现"都讲明白了,写得太好了。
Android Binder设计与实现 - 实现篇 —— 对设计篇的补充,关键源码分析,设计篇中一些看后有点模糊的点,这里都讲清楚了。