/dev/binder 是 Android 系统中的一个字符设备驱动 ,是 Binder IPC 机制的核心。
🔧 什么是 Binder?
Binder 是 Android 中的进程间通信 (IPC) 机制,类似于 Linux 中的 socket、管道等,但专门为 Android 设计。
📍 /dev/binder 的作用
scss
进程 A 进程 B
│ │
├─ 打开 /dev/binder ├─ 打开 /dev/binder
│ (获得文件描述符) │ (获得文件描述符)
│ │
├─ mmap() 内存映射 ├─ mmap() 内存映射
│ (共享内存缓冲区) │ (共享内存缓冲区)
│ │
└─ ioctl() 系统调用 └─ ioctl() 系统调用
(发送 Binder 事务) (接收 Binder 事务)
↓ Binder 驱动核心 (/dev/binder) ↓
进程间通信 (IPC)
🔄 Binder 通信流程
markdown
发送方进程:
1. 创建 Parcel 对象(序列化数据)
2. 通过 ioctl() 调用 Binder 驱动
3. Binder 驱动:
├─ 验证权限
├─ 进行数据转换
├─ 添加到接收方的待处理队列
└─ 唤醒接收方进程
接收方进程:
1. 从 ioctl() 阻塞中唤醒
2. 从 Binder 缓冲区读取数据
3. 反序列化 Parcel 对象
4. 执行对应的方法
5. 准备返回值
6. 发送回复给发送方
🏗️ /dev/binder 的结构
scss
/dev/binder (字符设备)
│
├─ 主要功能:
│ ├─ open() - 打开设备,获得 Binder 上下文
│ ├─ mmap() - 创建共享内存区域
│ ├─ ioctl() - 发送/接收 Binder 事务
│ └─ close() - 关闭连接
│
├─ 内部数据结构:
│ ├─ binder_proc (每个进程)
│ ├─ binder_thread (每个线程)
│ ├─ binder_node (每个对象)
│ ├─ binder_ref (对象引用)
│ └─ binder_transaction (事务)
│
└─ 驱动特性:
├─ 自动垃圾回收 (引用计数)
├─ 死亡通知 (Binder Notification)
├─ 权限控制
└─ 性能优化 (零拷贝)
📝 在 Telephony 中的具体使用
让我查看代码中 Binder 的实际使用:
让我查看 IPhoneSubInfo AIDL 文件:
让我查看一个 AIDL 文件来展示 Binder 的使用:
完美!现在我可以详细解释 /dev/binder 在 Telephony 中的实际使用:
📞 Telephony 中 /dev/binder 的实际使用例子
场景:应用调用 TelephonyManager.getDeviceId()
scss
应用进程 (uid: 10001):
┌───────────────────────────────────┐
│ val tm = context.getSystemService │
│ (Context.TELEPHONY_SERVICE)│
│ tm.getDeviceId() │
└────────────┬──────────────────────┘
│
├─ 通过 Binder 获取 IPhoneSubInfo 代理
│ (asInterface())
│
├─ 调用代理的 getDeviceId(callingPackage)
│
└─ 发送 Binder 事务到 /dev/binder
↓ /dev/binder (Binder 驱动)
├─ 检查权限
├─ 检查调用者 UID
├─ 序列化数据
└─ 转发到目标进程
system_server 进程 (uid: 1000):
┌───────────────────────────────────┐
│ PhoneSubInfoController │
│ (IPhoneSubInfo 的实现) │
│ │
│ onTransact(): │
│ case GET_DEVICE_ID: │
│ ├─ 获取 callingPackage │
│ ├─ 权限检查 │
│ ├─ 调用 Phone.getDeviceId() │
│ └─ 返回结果 │
└────────┬───────────────────────────┘
│
├─ 序列化返回值
└─ 发送回复到 /dev/binder
↓ /dev/binder (返回事务)
转发回应用进程
应用进程:
┌───────────────────────────────────┐
│ 从 Binder 缓冲区读取返回值 │
│ deviceId = "123456789ABCDEF" │
└───────────────────────────────────┘
🔍 AIDL 文件如何变成 Binder 调用
java
// IPhoneSubInfo.aidl
interface IPhoneSubInfo {
String getDeviceIdWithFeature(String callingPackage, String callingFeatureId);
}
// 编译后生成的 Java 代码(简化版):
public class IPhoneSubInfo {
// 服务端(PhoneSubInfoController)
public abstract class Stub extends Binder implements IPhoneSubInfo {
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
// 接收 Binder 事务
switch (code) {
case TRANSACTION_getDeviceIdWithFeature: {
String callingPackage = data.readString();
String callingFeatureId = data.readString();
String result = this.getDeviceIdWithFeature(callingPackage, callingFeatureId);
reply.writeString(result); // 序列化返回值
return true;
}
}
return false;
}
}
// 客户端(应用进程)
public static class Proxy implements IPhoneSubInfo {
private IBinder mRemote;
@Override
public String getDeviceIdWithFeature(String callingPackage, String callingFeatureId) {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeString(callingPackage);
_data.writeString(callingFeatureId);
// 发送 Binder 事务
mRemote.transact(TRANSACTION_getDeviceIdWithFeature, _data, _reply, 0);
// 接收返回值
String _result = _reply.readString();
return _result;
} finally {
_reply.recycle();
_data.recycle();
}
}
}
}
🎯 /dev/binder 中的关键概念
1. 文件描述符 (FD)
bash
# 在进程中查看 Binder 连接
$ adb shell "cat /proc/[pid]/fd" | grep binder
# 输出示例:
# lrwx------ root root 11 /dev/binder
2. mmap() - 内存映射
java
// 每个进程通过 mmap 获得共享缓冲区
private class BinderConnection {
private static final int BINDER_VM_SIZE = (1 * 1024 * 1024) - PAGE_SIZE;
// 驱动程序会创建一块共享内存
// 用于 Binder 数据交换
void setupBinderBuffer() {
// 大约 1MB 的缓冲区用于 Binder 通信
mmap(0, BINDER_VM_SIZE,
PROT_READ, MAP_PRIVATE,
mBinderFd, 0);
}
}
3. ioctl() - 系统调用
c
// Binder 驱动支持的主要 ioctl 命令
#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32)
#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
#define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
🔐 /dev/binder 的权限和安全
bash
# /dev/binder 的权限
$ ls -la /dev/binder
crw-rw-rw- 1 root root 10, 48 11-15 10:30 /dev/binder
# 所有进程都可以打开,但 Binder 驱动会检查:
# 1. 调用者的 UID/GID
# 2. 权限声明(manifest 权限)
# 3. AppOps 设置
# 4. SELinux 策略
📊 Binder 与其他 IPC 的对比
| 特性 | Binder | Socket | Pipe | Shared Memory |
|---|---|---|---|---|
| 效率 | 很高 | 高 | 中 | 很高 |
| 易用性 | 很高 | 中 | 低 | 低 |
| 权限检查 | ✅ 内置 | ❌ 无 | ❌ 无 | ❌ 无 |
| 同步支持 | ✅ 是 | ✅ 是 | ❌ 否 | ❌ 否 |
| 垃圾回收 | ✅ 自动 | ❌ 手动 | ❌ 手动 | ❌ 手动 |
| Android专用 | ✅ 是 | ❌ 否 | ❌ 否 | ❌ 否 |
📌 总结
/dev/binder 是:
- 字符设备驱动 - Linux 内核模块
- IPC 机制 - 进程间通信的核心
- AIDL 基础 - AIDL 编译后的代码使用 Binder
- 权限检查点 - 系统安全的重要组成部分
- 高效通信 - 零拷贝技术,性能优化
在 Telephony 中,所有的 AIDL 接口(如 IPhoneSubInfo、ITelephony 等)都是通过 /dev/binder 进行通信的。