目录
- 引言:Binder 是什么?为什么它如此重要?
- Binder 的核心概念与设计思想
- C/S 架构
- 指针穿越
- Binder 驱动:Binder 的“心脏”
- Binder 在 Android 中的角色与分层
- 四大组件的基石
- Binder IPC 的分层模型
- C 语言 Binder 的核心数据结构
binder_ioctl:用户空间与内核空间的桥梁flat_binder_object:Binder 通信的“信使”Parcel:数据打包的“集装箱”
- 一个完整的 C 语言 Binder 通信流程(以 Service Manager 为例)
- 服务端:如何注册一个服务
- 客户端:如何获取服务并调用方法
- Binder 驱动:如何“牵线搭桥”
- 实战:用 C 语言实现一个简单的 Binder 服务
- 环境准备
- 代码示例与分析
- 总结与展望
引言:Binder 是什么?为什么它如此重要?
在 Android 系统中,Binder 是一种进程间通信 机制,它不是 Linux 原生的,而是 Google 为 Android 专门设计和实现的。

为什么需要 Binder? Android 是一个多操作系统的,一个应用通常运行在自己的独立进程中,你的 App 进程需要和系统服务(如 Activity Manager, Window Manager)通信,或者和另一个 App 进程共享数据,这些进程之间是相互隔离的,不能直接访问对方的内存,这时就需要一个“中间人”来完成数据的传递和方法的调用。
为什么选择 Binder 而不是其他 IPC 方式(如 Socket、管道、共享内存)? | IPC 方式 | 性能 | 数据拷贝次数 | 安全性 | 复杂度 | | :--- | :--- | :--- | :--- | :--- | | Binder | 高 | 1次 | 高 | 中 | | 共享内存 | 最高 | 0次 | 低 | 高 | | Socket | 中 | 2次 | 中 | 高 | | 管道 | 低 | 2次 | 低 | 低 |
- 高性能:通过内核中的 Binder 驱动,数据只需要拷贝一次(用户空间 -> 内核空间 -> 目标用户空间)。
- 高安全性:每个进程都有一个唯一的 UID,Binder 驱动在通信时会进行严格的权限校验,只有通过校验的进程才能通信,这有效防止了恶意进程的攻击。
- 面向对象:Binder 将通信过程抽象为“引用”和“对象”,使得调用远程方法就像调用本地方法一样自然(这被称为“面向对象 IPC”)。
一句话总结:Binder 是 Android 系统的“高速公路”和“安全卫士”,负责高效、安全地连接系统中的所有进程。
核心概念与设计思想
C/S 架构
Binder 通信采用经典的客户端/服务器 架构。

- 服务器:提供服务的进程,它创建一个 Binder 对象,并将其“注册”到 Binder 驱动中。
- 客户端:需要使用服务的进程,它通过 Binder 驱动找到服务器提供的 Binder 对象,然后通过这个对象调用服务端的方法。
指针穿越
这是 Binder 最核心、最巧妙的设计,在传统的 IPC 中,你不能直接传递一个指针,因为不同进程的虚拟地址空间是独立的,Binder 巧妙地绕过了这个问题:
- 服务端在用户空间创建了一个对象。
- 当需要传递这个对象时,Binder 驱动在内核空间中创建了一个和它对应的
binder_node。 - 服务端用户空间的指针和内核空间的
binder_node通过一个句柄(handle,一个整数值)关联起来。 - 客户端收到这个
handle后,Binder 驱动会在内核空间中找到对应的binder_node,然后为客户端在它的用户空间中创建一个新的对象,并将这个新对象与内核的binder_node关联。 - 关键点:虽然客户端和服务端看到的是两个不同的用户空间对象,但它们都指向了内核中同一个
binder_node,当客户端通过它的对象进行操作时,实际上是操作内核的binder_node,而 Binder 驱动会确保这个操作被正确地转发到服务端最初创建的那个对象上。
这个过程就像给了客户端一把“遥控器”(handle),这把遥控器能控制服务端在“另一个房间”(另一个进程)里的那个“设备”(Binder 对象)。
Binder 驱动:Binder 的“心脏”
Binder 驱动是整个机制的核心,它工作在内核空间,主要职责是:
- 管理生命:创建、销毁、维护所有 Binder 实体(
binder_node)和引用(binder_ref)。 - 中转数据:在客户端和服务端之间转发数据包(
Parcel)。 - 身份验证:在通信时,检查进程的 UID 和 PID,确保权限安全。
- 同步屏障:处理异步通信,确保消息的顺序性。
Binder 在 Android 中的角色与分层
四大组件的基石
Activity、Service、Broadcast、ContentProvider 这四大组件的跨进程通信,底层都是通过 Binder 实现的。

- 启动 Activity:你的 App 进程通过 Binder 向
ActivityManagerService(AMS) 请求启动一个新的 Activity。 - 绑定 Service:通过 Binder 与
Service建立连接,调用其onBind()返回的IBinder对象。 - 发送广播:通过 Binder 向
ActivityManagerService注册广播接收器或发送广播。 - 访问 ContentProvider:通过 Binder 调用
ContentProvider的方法(如query,insert)。
Binder IPC 的分层模型
从开发者的角度看,Binder 分为几个层次:
- 应用层:Java/Kotlin 代码,开发者使用的是 AIDL (Android Interface Definition Language) 生成的
Stub和Proxy类,对用户是透明的。 - Framework (JNI) 层:
android.os.Binder.java,这是一个 Java 类,它通过 JNI 调用底层的 C/C++ 实现。 - Native (C/C++) 层:
libbinder.so和libutils.so,这是 Binder 的核心实现,我们接下来要重点分析的 C 语言部分。 - Kernel 层:
Binder Driver,内核模块,负责最底层的调度和数据中转。
C 语言 Binder 的核心数据结构
binder_ioctl:用户空间与内核空间的桥梁
用户空间的进程无法直接操作内核,必须通过系统调用。ioctl (I/O Control) 就是这样一个接口,在 Binder 机制中,所有核心操作都是通过 ioctl 向 Binder 驱动发送命令来完成的。
BINDER_WRITE_READ:最核心的命令,用于读写数据,用户空间将一个binder_write_read结构体传给驱动,告诉驱动要写什么数据,要读什么数据。BINDER_SET_CONTEXT_MGR:将当前进程设置为 Service Manager(系统服务的大管家)。BINDER_THREAD_EXIT:通知驱动线程退出。
flat_binder_object:Binder 通信的“信使”
当需要传递一个 Binder 对象(或文件描述符等)时,用户空间会将它打包成一个 flat_binder_object 结构体,这个结构体包含了对象的所有关键信息,驱动通过它来建立“指针穿越”的映射。
// frameworks/native/libs/binder/ndk/binder_ndk.cpp
struct flat_binder_object {
unsigned long type;
unsigned long flags;
union {
void *binder; // 指向 Binder 对象的指针(服务端)
signed long handle; // 客户端收到的句柄
};
void *cookie; // 用于区分不同对象的 cookie
};
type:对象的类型,如BINDER_TYPE_BINDER(普通 Binder 对象)、BINDER_TYPE_HANDLE(客户端的引用句柄)。bindervshandle:这是“指针穿越”的关键,服务端在发送时用的是binder(真实指针),客户端收到的是handle(整数值)。cookie:一个额外的标识符,用于区分同一个类但不同的实例对象。
Parcel:数据打包的“集装箱”
Parcel 是一个容器,用于在 Binder 通信中序列化和反序列化数据,它可以把基本数据类型
