Android 的 Binder 机制是一种独特的跨进程通信(IPC)系统,在整个Android系统中都发挥着至关重要的作用。这种机制在操作系统的内核层、 Android 框架层(Framework)以及应用程序的 Java 层都有其具体实现,从底层到上层,每一层都为 IPC 机制提供了必要的支撑,构成了一个高效且灵活的通信体系。
本系列 Binder 文章,会从内核层到 Framework 层,再到 Java 层,深入浅出,介绍整个 Binder 的设计:
- 图解Binder:初始化
- 图解Binder:系统调用 open
- 图解Binder:事务
- 图解Binder:线程池
- 图解Binder:内存管理
- 图解Binder:ServiceManager
- 图解Binder:AIDL
Binder 内核层
初始化 Binder
Binder 驱动是 Android 系统的一部分,是在编译期编译到内核中的。Binder 驱动利用 initcall 机制,将它的初始化函数 binder_init() 添加到 initcall 队列中。当内核启动时,binder_init() 函数就会被执行,从而完成 Binder 驱动的初始化。
在Binder驱动的初始化过程中, binder_init() 主要工作是:
- 注册 binder 设备:调用 misc_register(),向虚拟文件系统(VFS)注册一个名为 “binder” 的 misc 设备,该设备的设备文件路径是 “/dev/binder”。一旦注册成功,用户空间的进程就可以通过打开 “/dev/binder” 设备文件,对 Binder 驱动进行操作,从而实现跨进程通信。
- 注册 binder 文件系统:调用 register_filesystem(),向 VFS 注册 binder 文件系统。binder 文件系统会在 init 进程启动时进行挂载。当通过系统调用 open() 打开 “/dev/binder” 设备文件时,就会沿着 VFS,最后定位到 binder 文件系统,调用其对应的 binder_open() 实现,完成 binder 驱动的打开。
《图解 Binder:初始化》一文将详细阐述 Binder 的 binder_init(),以及如何通过 initcall 机制进行系统初始化。
Binder 的几个系统调用
每个要使用 Binder 进行通信的进程,都会调用 Framework 层的 ProcessState::initWithDriver() ,打开 Binder 驱动。initWithDriver() 主要涉及了几个系统调用,它们的具体的实现,主要是在内核层。相关调用如下:
ProcessState.cpp
└──init()
└───ProcessState()
└────open_driver()
└─────open()
└─────ioctl() // 发送 ioctl 命令 BINDER_VERSION,检测 Binder 驱动版本号
└─────ioctl() // 发送 ioctl 命令 BINDER_SET_MAX_THREADS,设置 Binder 线程池的最大线程数
└─────ioctl() // 发送 ioctl 命令 BINDER_ENABLE_ONEWAY_SPAM_DETECTION
└────mmap()
上面的调用链路,最关键是几个系统调用:
- open():打开 Binder 驱动设备。最终会调用 Binder 驱动的 binder_open()。
- ioctl():发送各种 ioctl 命令,与 Binder 驱动进行通信。最终会调用 Binder 驱动的 binder_ioctl()。
- mmap():进行 mmap 映射,提供一块虚拟地址空间,用于建立接收其他进程事务消息的缓冲区。最终会调用 Binder 驱动的 binder_mmap()。
这几个系统调用,最终都是通过虚拟文件系统,进入到内核层。
在《图解 Binder:系统调用 open》里,我们会介绍是如何沿着虚拟文件系统,最终定位到 binder 文件系统,调用到 binder_open()。
一旦Binder驱动被成功打开,我们就能发起Binder事务,这是Binder通信的基础。在《图解 Binder:事务》中,我们会介绍 binder 消息、ioctl 命令、binder实体、binder 代理、binder 节点和 binder 引用 以及 它们的工作机制。这一切都是为了能够在进程之间进行高效的通信。
为了处理这些事务,Binder 采用了线程池机制。《图解Binder:线程池》将揭示 Binder 线程池的工作原理,也会介绍 Binder 驱动里的几个工作队列。
此外,Binder 的高效性离不开其独特的内存管理机制。在《图解Binder:内存管理》一文中,我们将深入探讨虚拟内存、mmap 实现进程间通信的一次拷贝、缓冲区分配以及内存缩减器等机制,以及它们是如何共同提升 Binder 通信性能的。
Binder Framework 层
在讲 Binder 内核层的时候,其实就已经涉及了不少 Framework 层的代码。此外,在 Android Framework 层,Binder 的另一个主要组成部分是 ServiceManager。ServiceManager 是 Binder 驱动中的 0 号 Binder 节点,用于管理系统级服务的 Binder 引用。AMS、WMS 这些系统级服务,都会将自己注册到 ServiceManager 中。当其他进程需要使用这些服务的时候,可以通过 ServiceManager 来查找和获取。在《图解Binder:ServiceManager》中,我们介绍 ServiceManager 的工作原理。
Binder Java 层
在应用程序的 Java 层,Binder 提供了 AIDL 便于我们实现跨进程的调用。AIDL(Android Interface Definition Language)是一种支持跨进程通信 (IPC) 的接口定义语言。在《图解Binder:AIDL》一文中,我们将介绍 AIDL 的工作原理。
代码文件目录
Binder 内核层的代码,主要在 common/drivers/android 目录下。
负责与内核通信的 Framework 层的代码,如 Binder 线程池、Binder 事务发送与接收的代码等,主要在 frameworks/native/libs/binder 目录下。
Framework 层的 ServiceManager 相关代码,主要在 frameworks/native/cmds/servicemanager/ServiceManager 目录下。
Binder Java 层的相关代码,主要在 frameworks/base/core/java/android/os 目录下。
源码阅读技巧
本系列文章,都是基于Android platform 分支 android-13.0.0_r1 和内核分支 common-android13-5.15解 析。
一些关键代码的链接,可能会因为源码的变动,发生位置偏移、丢失等现象。可以搜索函数名,重新进行定位:

如果和当前 Android 最新代码相差不大,建议 Framework 层代码直接切换到 master 分支,内核层代码直接切换到 common-android-mainline 分支。这样就可以像 IDEA 一样,点击相关函数进行跳转,或者查看哪些函数调用了该函数(非主分支代码,无法进行跳转)。
Framework 层代码直接切换到 master 分支 :

内核层代码直接切换到 common-android-mainline 分支:
