Android Binder 的原理是什么?为什么用它替代其他 IPC?
Binder 是 Android 进程间通信的核心机制,系统四大组件的跨进程调用全靠它。Android 不用 Linux 原生的管道、Socket 或共享内存,核心原因三个:只拷贝一次、内核级安全校验、自带服务发现。
管道和 Socket 至少两次数据拷贝(用户态→内核态→用户态),Binder 通过 mmap 只拷贝一次。共享内存虽然零拷贝,但进程间没有任何身份验证机制,任何进程都能读写,Android 不敢用。Binder 每次通信都由内核自动附加调用方的 UID/PID,身份无法伪造,这是它最核心的安全优势。再加上 ServiceManager 充当"服务目录",Client 不需要硬编码 Server 地址,查一下就行。
Binder 驱动运行在内核态,暴露 /dev/binder 设备节点。通信流程:Server 向 ServiceManager 注册服务 → Client 查询 ServiceManager 拿到 Binder 代理对象 → Client 通过代理调方法 → Binder 驱动负责数据搬移和线程调度。ServiceManager 本身也是个 Binder 服务,handle 固定为 0。
mmap 的具体过程:binder_open 时调用 mmap,在接收方进程的用户空间和内核空间之间建立一块共享映射区(上限 4MB)。发送方通过 copy_from_user 把数据拷进这块内核映射区,接收方已经映射了同一块物理内存,直接读取——这就是"一次拷贝"的来由。发送方不做映射,因为一次通信只有接收端需要零拷贝读取。
追问
Binder 线程池默认多大?满了怎么办?
默认最大 16 个线程(主线程 + 15 个工作线程)。客户端发起同步 Binder 调用,驱动在服务端线程池取线程执行。16 个都忙,新请求排队。所以主线程上不要做耗时 Binder 调用,否则 ANR——这不是建议,是血泪教训。
Binder 通信数据大小限制是多少?
异步(oneway)事务约 64KB,同步事务整个缓冲区约 1MB(不同 Android 版本略有差异)。Intent 底层走 Binder 传输,塞大数据会炸 TransactionTooLargeException。传大文件走 ContentProvider 或 SharedMemory,别往 Intent 里硬塞。
oneway 和同步调用有什么区别?
oneway 是 AIDL 方法修饰符,客户端调用后不阻塞,直接往下走,底层走异步事务。但注意:同一个 Binder 对象的 oneway 调用串行执行,不是并发。踩坑点——oneway 方法里抛异常,客户端完全无感知,线上排查这种问题特别痛苦。
为什么发送方不做 mmap 映射?
因为一次通信中,数据流是单向的:发送方只需要"写",接收方只需要"读"。给接收方做映射就能省掉第二次拷贝,给发送方做映射没有收益,还浪费内存。如果双向都需要高效传输,那就建立两个 Binder 通道,各自映射各自的。
写段代码
java// AIDL 定义 interface IBookManager { List<Book> getBookList(); void addBook(in Book book); oneway void notifyChange(); // 异步,不阻塞调用方 }