编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • Android提升进阶

    • 库的解读

    • 专栏博客

      • 系统启动Zygote
      • Binder通信原理
        • 一、引言:为什么Android选择Binder
        • 二、Linux传统IPC机制对比
          • 2.1 传统IPC的数据拷贝次数
          • 2.2 各IPC机制的综合对比
          • 2.3 Binder选择的核心原因
        • 三、Binder的整体架构
          • 3.1 四层架构
          • 3.2 核心组件关系
        • 四、Binder驱动的内核实现
          • 4.1 Binder驱动的核心数据结构
          • 4.2 Binder驱动的核心操作
          • 4.3 binder_ioctl:通信的核心
        • 五、mmap与一次拷贝原理
          • 5.1 Binder的内存映射机制
          • 5.2 binder_mmap的实现
          • 5.3 一次拷贝的数据流
        • 六、Binder通信协议与数据传输
          • 6.1 Binder通信的命令协议
          • 6.2 一次完整的Binder调用过程
          • 6.3 Parcel:Binder的数据载体
        • 七、ServiceManager的角色与实现
          • 7.1 ServiceManager的定位
          • 7.2 服务注册与查找流程
          • 7.3 Binder对象在跨进程传输时的转换
        • 八、AIDL与Proxy-Stub模式
          • 8.1 AIDL的本质
          • 8.2 生成代码的核心结构
          • 8.3 同进程优化
        • 九、Binder线程池管理
          • 9.1 Binder线程池的结构
          • 9.2 线程池的动态管理
          • 9.3 线程池扩容策略
        • 十、Binder中的引用计数与生命周期
          • 10.1 Binder的引用计数机制
          • 10.2 Death Notification(死亡通知)
        • 十一、Binder的安全机制
          • 11.1 调用者身份验证
          • 11.2 SELinux对Binder的保护
        • 十二、Binder在Framework层的应用
          • 12.1 四大组件与Binder
          • 12.2 系统API调用链路分析
        • 十三、Binder的性能分析与优化
          • 13.1 Binder通信的性能瓶颈
          • 13.2 Binder传输大小限制
          • 13.3 Binder优化实践
        • 十四、面试高频问题与深度分析
          • 14.1 Binder为什么是一次拷贝?共享内存不是更快吗?
          • 14.2 AIDL中的in/out/inout修饰符是什么意思?
          • 14.3 Binder调用是同步的还是异步的?
        • 十五、IPC通信方式详解
          • 15.1 Intent通信设计
          • 15.2 文件共享通信设计
          • 15.3 Messenger通信设计
          • 15.4 AIDL跨进程通信
          • 15.5 ContentProvider
          • 15.6 Socket通信设计
          • 15.7 IPC方式对比
        • 十六、总结
      • Handler消息机制
      • Activity启动原理
      • 四大组件原理分析
      • AMS与组件管理
      • View绑制与渲染
      • 事件分发机制
      • Surface渲染原理
      • 自定义View设计
      • WMS窗口管理
      • PMS与APK安装
      • 虚拟机与类加载
      • 内存管理与GC
      • 线程与并发编程
      • 性能优化与监控
      • 序列化与数据存储
      • 组件化与路由设计
      • 插件化与热修复
      • NDK开发实践
      • WebView核心设计
      • ADB常见使用操作
    • 智能硬件

  • iOS开发和进阶

  • Web开发和进阶

  • Linux应用开发

  • Apps
  • Android提升进阶
  • 专栏博客
杨充
2026-04-14
目录

Binder通信原理

# 02.Binder通信原理

# 目录介绍

  • 一、引言:为什么Android选择Binder
  • 二、Linux传统IPC机制对比
    • 2.1 传统IPC的数据拷贝次数
    • 2.2 各IPC机制的综合对比
    • 2.3 Binder选择的核心原因
  • 三、Binder的整体架构
    • 3.1 四层架构
    • 3.2 核心组件关系
  • 四、Binder驱动的内核实现
    • 4.1 Binder驱动的核心数据结构
    • 4.2 Binder驱动的核心操作
    • 4.3 binder_ioctl:通信的核心
  • 五、mmap与一次拷贝原理
    • 5.1 Binder的内存映射机制
    • 5.2 binder_mmap的实现
    • 5.3 一次拷贝的数据流
  • 六、Binder通信协议与数据传输
    • 6.1 Binder通信的命令协议
    • 6.2 一次完整的Binder调用过程
    • 6.3 Parcel:Binder的数据载体
  • 七、ServiceManager的角色与实现
    • 7.1 ServiceManager的定位
    • 7.2 服务注册与查找流程
    • 7.3 Binder对象在跨进程传输时的转换
  • 八、AIDL与Proxy-Stub模式
    • 8.1 AIDL的本质
    • 8.2 生成代码的核心结构
    • 8.3 同进程优化
  • 九、Binder线程池管理
    • 9.1 Binder线程池的结构
    • 9.2 线程池的动态管理
    • 9.3 线程池扩容策略
  • 十、Binder中的引用计数与生命周期
    • 10.1 Binder的引用计数机制
    • 10.2 Death Notification(死亡通知)
  • 十一、Binder的安全机制
    • 11.1 调用者身份验证
    • 11.2 SELinux对Binder的保护
  • 十二、Binder在Framework层的应用
    • 12.1 四大组件与Binder
    • 12.2 系统API调用链路分析
  • 十三、Binder的性能分析与优化
    • 13.1 Binder通信的性能瓶颈
    • 13.2 Binder传输大小限制
    • 13.3 Binder优化实践
  • 十四、面试高频问题与深度分析
    • 14.1 Binder为什么是一次拷贝?共享内存不是更快吗?
    • 14.2 AIDL中的in/out/inout修饰符是什么意思?
    • 14.3 Binder调用是同步的还是异步的?
  • 十五、IPC通信方式详解
    • 15.1 Intent通信设计
    • 15.2 文件共享通信设计
    • 15.3 Messenger通信设计
    • 15.4 AIDL跨进程通信
    • 15.5 ContentProvider
    • 15.6 Socket通信设计
    • 15.7 IPC方式对比
  • 十六、总结

# 一、引言:为什么Android选择Binder

在Linux世界中,进程间通信(IPC)有多种成熟的方案:管道、消息队列、共享内存、Socket等。然而,Android没有采用这些传统方案作为核心IPC机制,而是选择了一个来自OpenBinder项目的方案——Binder。

疑惑:Linux已经有这么多IPC机制,为什么Android还要"重新发明轮子"?

答疑:因为移动设备对IPC有特殊的需求——高性能、安全、易用。传统IPC机制要么性能不够(Socket需要两次拷贝),要么不安全(共享内存无法验证调用者身份),要么使用复杂(消息队列需要手动管理生命周期)。Binder通过内核驱动实现了一次拷贝、调用者身份验证、面向对象的接口设计,完美满足了Android的需求。


# 二、Linux传统IPC机制对比

# 2.1 传统IPC的数据拷贝次数

管道/消息队列/Socket:
发送方用户空间 → [copy_from_user] → 内核缓冲区 → [copy_to_user] → 接收方用户空间
                    第1次拷贝                        第2次拷贝
总计:2次数据拷贝

共享内存:
发送方用户空间 ←→ 共享物理页面 ←→ 接收方用户空间
                    0次拷贝
总计:0次数据拷贝(但需要额外的同步机制)

Binder:
发送方用户空间 → [copy_from_user] → 内核缓冲区/接收方映射区
                    第1次拷贝        ↑ 接收方通过mmap直接读取
总计:1次数据拷贝
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 2.2 各IPC机制的综合对比

┌──────────────┬──────────┬──────────┬──────────┬──────────┐
│    特性       │  Socket  │  共享内存  │  管道     │  Binder  │
├──────────────┼──────────┼──────────┼──────────┼──────────┤
│ 数据拷贝次数  │    2     │    0     │    2     │    1     │
│ 安全性       │ 低       │ 低       │ 低       │ 高       │
│ 身份验证     │ 无内建   │ 无内建   │ 无内建   │ UID/PID  │
│ C/S架构支持  │ 支持     │ 不支持   │ 不支持   │ 天然支持  │
│ 面向对象     │ 否       │ 否       │ 否       │ 是       │
│ 使用复杂度   │ 中       │ 高       │ 低       │ 低(AIDL) │
│ 适用场景     │ 跨网络   │ 高频交互  │ 亲缘进程  │ 系统IPC  │
└──────────────┴──────────┴──────────┴──────────┴──────────┘
1
2
3
4
5
6
7
8
9
10
11

# 2.3 Binder选择的核心原因

1. 性能:一次拷贝,介于共享内存和Socket之间的最佳平衡点
2. 安全:内核级别的UID/PID身份验证,无法伪造
3. 易用:AIDL自动生成代码,开发者只需定义接口
4. 架构:天然支持C/S模型,与Android组件化架构完美匹配
5. 引用计数:自动管理远程对象生命周期,避免内存泄漏
1
2
3
4
5

# 三、Binder的整体架构

# 3.1 四层架构

Binder架构(分层视图):

┌────────────────────────────────────────────────┐
│  应用层(Application Layer)                     │
│  Activity/Service/ContentProvider/BroadcastReceiver│
│  使用AIDL或Messenger进行IPC                      │
├────────────────────────────────────────────────┤
│  Framework层(Java Binder)                      │
│  IBinder / Binder / BinderProxy                  │
│  Parcel(数据序列化)                             │
│  ServiceManager(服务注册与发现)                  │
├────────────────────────────────────────────────┤
│  Native层(C++ Binder)                          │
│  BpBinder / BBinder / ProcessState / IPCThreadState│
│  libbinder.so                                    │
├────────────────────────────────────────────────┤
│  内核层(Binder Driver)                         │
│  /dev/binder                                     │
│  binder_ioctl / binder_mmap / binder_thread_read │
└────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 3.2 核心组件关系

Client进程                          Server进程
┌─────────────────┐                ┌─────────────────┐
│  BinderProxy     │                │  Binder (Stub)   │
│  (Java层代理)    │                │  (Java层实现)    │
│       ↓         │                │       ↑          │
│  BpBinder        │                │  BBinder         │
│  (Native代理)    │                │  (Native实现)    │
│       ↓         │                │       ↑          │
│  IPCThreadState  │                │  IPCThreadState  │
│       ↓         │                │       ↑          │
└────────┼────────┘                └────────┼─────────┘
         │                                  │
         ↓          Binder Driver           ↑
    ┌────────────────────────────────────────────┐
    │  /dev/binder                               │
    │  binder_proc → binder_node → binder_ref    │
    │  binder_transaction → binder_buffer         │
    └────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 四、Binder驱动的内核实现

# 4.1 Binder驱动的核心数据结构

// 每个使用Binder的进程对应一个binder_proc
struct binder_proc {
    struct hlist_node proc_node;    // 挂在全局进程链表中
    struct rb_root threads;         // 红黑树:该进程的所有Binder线程
    struct rb_root nodes;           // 红黑树:该进程提供的所有Binder节点
    struct rb_root refs_by_desc;    // 红黑树:该进程引用的远程Binder(按handle排序)
    struct rb_root refs_by_node;    // 红黑树:按节点指针排序
    struct list_head todo;          // 待处理的工作队列
    struct list_head waiting_threads; // 空闲等待的线程
    int pid;                        // 进程PID
    struct vm_area_struct *vma;     // mmap映射的虚拟地址区域
    void *buffer;                   // 内核缓冲区起始地址
    size_t buffer_size;             // 缓冲区大小(默认1MB-8KB)
};

// 每个Binder实体对应一个binder_node
struct binder_node {
    struct binder_proc *proc;       // 所属进程
    struct hlist_head refs;         // 所有引用此节点的binder_ref列表
    int internal_strong_refs;       // 内部强引用计数
    int local_strong_refs;          // 本地强引用计数
    binder_uintptr_t ptr;           // 指向用户空间Binder对象
    binder_uintptr_t cookie;        // 附加数据
};

// 引用远程Binder的句柄
struct binder_ref {
    struct binder_proc *proc;       // 所属进程
    struct binder_node *node;       // 指向的目标Binder节点
    uint32_t desc;                  // 句柄值(handle)
    int strong;                     // 强引用计数
    int weak;                       // 弱引用计数
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 4.2 Binder驱动的核心操作

// Binder驱动注册
static const struct file_operations binder_fops = {
    .owner = THIS_MODULE,
    .open = binder_open,       // 打开/dev/binder
    .mmap = binder_mmap,       // 内存映射
    .unlocked_ioctl = binder_ioctl,  // 核心通信接口
    .release = binder_release, // 关闭
    .poll = binder_poll,       // 轮询
    .flush = binder_flush,     // 刷新
};

// binder_open:进程首次使用Binder时调用
static int binder_open(struct inode *nodp, struct file *filp) {
    struct binder_proc *proc;
    proc = kzalloc(sizeof(*proc), GFP_KERNEL);  // 分配binder_proc
    proc->pid = current->group_leader->pid;
    INIT_LIST_HEAD(&proc->todo);
    // 将proc加入全局链表
    hlist_add_head(&proc->proc_node, &binder_procs);
    filp->private_data = proc;
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 4.3 binder_ioctl:通信的核心

// 所有Binder通信都通过ioctl系统调用
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {
    switch (cmd) {
    case BINDER_WRITE_READ:
        // 最核心的命令:发送和接收数据
        ret = binder_ioctl_write_read(filp, cmd, arg, thread);
        break;
    case BINDER_SET_MAX_THREADS:
        // 设置最大线程数
        proc->max_threads = *(int *)arg;
        break;
    case BINDER_SET_CONTEXT_MGR:
        // 注册为ServiceManager(全系统只有一个)
        ret = binder_ioctl_set_ctx_mgr(filp, NULL);
        break;
    case BINDER_VERSION:
        // 获取Binder版本
        break;
    }
    return ret;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 五、mmap与一次拷贝原理

# 5.1 Binder的内存映射机制

这是理解Binder高性能的关键。传统IPC需要两次拷贝的原因是:发送方的用户空间→内核空间(第1次),内核空间→接收方用户空间(第2次)。Binder通过mmap将接收方的用户空间和内核空间映射到同一块物理内存,从而省去第2次拷贝。

传统IPC(以Socket为例):
┌───────────────┐                          ┌───────────────┐
│ Client用户空间  │                          │ Server用户空间  │
│  data buffer   │                          │  recv buffer   │
│       │        │                          │       ↑        │
│  copy_from_user│                          │  copy_to_user  │
│       ↓        │                          │       │        │
├───────────────┤  ┌──────────────────┐    ├───────────────┤
│ 内核空间       │  │  内核缓冲区       │    │ 内核空间       │
│               │  │  kernel buffer    │    │               │
└───────────────┘  └──────────────────┘    └───────────────┘
  第1次拷贝 →           中转             ← 第2次拷贝

Binder的mmap优化:
┌───────────────┐                          ┌───────────────┐
│ Client用户空间  │                          │ Server用户空间  │
│  data buffer   │                          │  mmap区域      │
│       │        │                          │     ↑↑↑        │
│  copy_from_user│                          │  (同一物理页)  │
│       ↓        │                          │     ↑↑↑        │
├───────────────┤                          ├───────────────┤
│ 内核空间       │                          │ 内核空间       │
│  binder_buffer │ ←→ 同一物理内存 ←→       │  binder_buffer │
└───────────────┘                          └───────────────┘
  只需1次拷贝         物理内存被同时映射到内核空间和接收方用户空间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 5.2 binder_mmap的实现

// binder_mmap: 为进程分配Binder缓冲区
static int binder_mmap(struct file *filp, struct vm_area_struct *vma) {
    struct binder_proc *proc = filp->private_data;
    
    // 1. 限制映射大小(最大4MB,默认约1MB-8KB)
    if ((vma->vm_end - vma->vm_start) > SZ_4M)
        vma->vm_end = vma->vm_start + SZ_4M;
    
    // 2. 设置为只读映射(用户空间不能直接写)
    vma->vm_flags &= ~VM_WRITE;
    
    // 3. 分配内核虚拟地址空间
    area = get_vm_area(vma->vm_end - vma->vm_start, VM_ALLOC);
    proc->buffer = area->addr;
    proc->buffer_size = vma->vm_end - vma->vm_start;
    
    // 4. 分配物理页面并同时映射到内核空间和用户空间
    page = alloc_page(GFP_KERNEL);
    // 映射到内核空间
    map_kernel_range_noflush(kernel_addr, PAGE_SIZE, PAGE_KERNEL, &page);
    // 映射到用户空间(同一个物理页!)
    vm_insert_page(vma, user_addr, page);
    
    // 此时:kernel_addr和user_addr指向同一物理页面
    // 内核写入kernel_addr的数据,用户空间从user_addr可以直接读到
    
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 5.3 一次拷贝的数据流

Client发送数据到Server的完整过程:

1. Client调用 ioctl(BINDER_WRITE_READ)
   → 将数据从Client用户空间copy_from_user到内核缓冲区
   → 这是唯一的一次数据拷贝

2. 内核在Server的binder_buffer中分配空间
   → 这块内核缓冲区已经通过mmap映射到Server的用户空间
   → 数据写入内核缓冲区 = 数据写入Server的mmap区域

3. Server被唤醒,从mmap区域直接读取数据
   → 无需第二次拷贝!
1
2
3
4
5
6
7
8
9
10
11
12

# 六、Binder通信协议与数据传输

# 6.1 Binder通信的命令协议

Binder使用两组命令:

BC_xxx (Binder Command):用户空间 → 内核(请求)
├── BC_TRANSACTION        → 发起一次RPC调用
├── BC_REPLY              → 回复一次RPC调用
├── BC_ACQUIRE_RESULT     → 获取引用计数操作结果
├── BC_FREE_BUFFER        → 释放通信缓冲区
├── BC_INCREFS            → 弱引用+1
├── BC_ACQUIRE            → 强引用+1
├── BC_RELEASE            → 强引用-1
├── BC_DECREFS            → 弱引用-1
├── BC_ENTER_LOOPER       → 线程进入Looper循环
├── BC_REGISTER_LOOPER    → 注册一个新的Looper线程
└── BC_EXIT_LOOPER        → 线程退出Looper循环

BR_xxx (Binder Return):内核 → 用户空间(响应)
├── BR_TRANSACTION        → 收到一次RPC调用请求
├── BR_REPLY              → 收到一次RPC调用回复
├── BR_ACQUIRE_RESULT     → 引用计数操作结果
├── BR_DEAD_BINDER        → Binder实体死亡通知
├── BR_DEAD_REPLY         → 目标进程已死亡
├── BR_FAILED_REPLY       → 事务失败
├── BR_SPAWN_LOOPER       → 请求创建新的Looper线程
└── BR_OK                 → 操作成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 6.2 一次完整的Binder调用过程

Client                    Binder Driver                  Server
  │                           │                            │
  │ BC_TRANSACTION            │                            │
  │ (code, data, target)      │                            │
  │──────────────────────────→│                            │
  │                           │ 1. copy_from_user          │
  │                           │ 2. 查找target进程          │
  │                           │ 3. 在target的buffer中分配空间│
  │                           │ 4. 拷贝数据到buffer        │
  │                           │ 5. 将事务加入target的todo队列│
  │                           │ 6. 唤醒target的等待线程     │
  │                           │                            │
  │                           │ BR_TRANSACTION             │
  │                           │──────────────────────────→│
  │                           │                            │ 处理请求
  │                           │                            │ 执行对应方法
  │                           │                            │
  │                           │            BC_REPLY        │
  │                           │←──────────────────────────│
  │                           │                            │
  │          BR_REPLY         │                            │
  │←──────────────────────────│                            │
  │                           │                            │
  │ 获得返回结果               │                            │
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 6.3 Parcel:Binder的数据载体

// Parcel是Binder通信的数据序列化容器
// 内存布局:
// ┌──────────────────────────────────────┐
// │  mData(普通数据区)                   │
// │  ┌──────┬──────┬──────┬──────┐      │
// │  │int   │String│float │byte[]│      │
// │  │4bytes│len+data│4bytes│len+data│  │
// │  └──────┴──────┴──────┴──────┘      │
// ├──────────────────────────────────────┤
// │  mObjects(Binder对象偏移量数组)       │
// │  ┌──────┬──────┐                    │
// │  │off1  │off2  │  ← 记录flat_binder_object的位置│
// │  └──────┴──────┘                    │
// └──────────────────────────────────────┘

// 写入数据
parcel.writeInt(42);
parcel.writeString("hello");
parcel.writeStrongBinder(myBinder);  // 写入Binder对象

// Binder对象在Parcel中的表示
struct flat_binder_object {
    __u32 hdr_type;          // BINDER_TYPE_BINDER 或 BINDER_TYPE_HANDLE
    __u32 flags;
    union {
        binder_uintptr_t binder;  // 本地Binder指针(同进程)
        __u32 handle;             // 远程Binder句柄(跨进程)
    };
    binder_uintptr_t cookie;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 七、ServiceManager的角色与实现

# 7.1 ServiceManager的定位

ServiceManager是Binder机制中的"DNS服务器",它是整个系统中第一个启动的Binder服务:

ServiceManager的特殊性:
1. 它的Binder handle固定为0(所有进程都知道如何找到它)
2. 它是通过BINDER_SET_CONTEXT_MGR ioctl注册的
3. 它维护着一个服务名→Binder引用的映射表
4. 所有系统服务都必须通过它注册和查找

类比:
ServiceManager = DNS服务器
服务名(如"activity")= 域名
Binder引用 = IP地址
1
2
3
4
5
6
7
8
9
10

# 7.2 服务注册与查找流程

服务注册流程:
SystemServer进程                    ServiceManager进程
   │                                    │
   │ addService("activity", amsBinder)  │
   │───────── Binder IPC ──────────────→│
   │                                    │ 存入映射表
   │                                    │ "activity" → binder_ref
   │←──────── 返回成功 ─────────────────│
   │                                    │

服务查找流程:
App进程                             ServiceManager进程
   │                                    │
   │ getService("activity")             │
   │───────── Binder IPC ──────────────→│
   │                                    │ 查找映射表
   │                                    │ 找到"activity"对应的binder_ref
   │←──── 返回AMS的BinderProxy ────────│
   │                                    │
   │ 现在可以直接和AMS通信了             │
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 7.3 Binder对象在跨进程传输时的转换

关键概念:Binder实体在不同进程中的表现形式不同

Server进程中:Binder(实体对象)
                ↓ 跨进程传输
Binder驱动中:binder_node(内核数据结构)
                ↓ 传递给Client
Client进程中:BinderProxy(代理对象)

具体转换过程:
1. Server将Binder写入Parcel
   → flat_binder_object.type = BINDER_TYPE_BINDER
   → flat_binder_object.binder = Binder实体的指针

2. Binder驱动处理:
   → 为这个Binder创建/查找binder_node
   → 在Client进程中创建binder_ref
   → 将type改为 BINDER_TYPE_HANDLE
   → 将binder改为 handle值(binder_ref.desc)

3. Client从Parcel读取:
   → 发现是BINDER_TYPE_HANDLE
   → 创建BinderProxy对象
   → 后续调用通过BinderProxy → BpBinder → ioctl → Binder驱动 → Server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 八、AIDL与Proxy-Stub模式

# 8.1 AIDL的本质

AIDL(Android Interface Definition Language)是一个代码生成工具,它自动生成Binder通信所需的Proxy和Stub代码:

开发者编写:
// IMyService.aidl
interface IMyService {
    String getData(int id);
    void setConfig(in Bundle config);
}

AIDL编译器生成:
├── IMyService.java           // 接口定义
│   ├── Stub(抽象类)         // 服务端基类
│   │   └── onTransact()      // 接收并分发请求
│   └── Proxy(内部类)        // 客户端代理
│       └── getData()         // 将调用打包发送
1
2
3
4
5
6
7
8
9
10
11
12
13

# 8.2 生成代码的核心结构

public interface IMyService extends android.os.IInterface {
    
    // Stub:服务端实现的基类
    public static abstract class Stub extends Binder implements IMyService {
        
        private static final String DESCRIPTOR = "com.example.IMyService";
        static final int TRANSACTION_getData = IBinder.FIRST_CALL_TRANSACTION + 0;
        static final int TRANSACTION_setConfig = IBinder.FIRST_CALL_TRANSACTION + 1;
        
        // 客户端获取代理对象
        public static IMyService asInterface(IBinder obj) {
            if (obj == null) return null;
            // 先检查是否同进程
            IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (iin != null && iin instanceof IMyService) {
                return (IMyService) iin;  // 同进程:直接返回本地对象
            }
            return new Proxy(obj);  // 跨进程:返回代理对象
        }
        
        // 接收远程调用并分发
        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
            switch (code) {
            case TRANSACTION_getData: {
                data.enforceInterface(DESCRIPTOR);
                int id = data.readInt();
                String result = this.getData(id);  // 调用实际实现
                reply.writeNoException();
                reply.writeString(result);
                return true;
            }
            case TRANSACTION_setConfig: {
                data.enforceInterface(DESCRIPTOR);
                Bundle config = data.readBundle();
                this.setConfig(config);
                reply.writeNoException();
                return true;
            }
            }
            return super.onTransact(code, data, reply, flags);
        }
    }
    
    // Proxy:客户端使用的代理类
    private static class Proxy implements IMyService {
        private IBinder mRemote;
        
        Proxy(IBinder remote) {
            mRemote = remote;
        }
        
        @Override
        public String getData(int id) throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            try {
                data.writeInterfaceToken(DESCRIPTOR);
                data.writeInt(id);
                // 发起远程调用(同步阻塞)
                mRemote.transact(TRANSACTION_getData, data, reply, 0);
                reply.readException();
                return reply.readString();
            } finally {
                data.recycle();
                reply.recycle();
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

# 8.3 同进程优化

Binder的同进程优化:

跨进程调用链:
Proxy.getData() → Parcel序列化 → ioctl → 内核 → ioctl → Parcel反序列化 → Stub.onTransact()

同进程调用链(asInterface优化):
Stub.asInterface(binder) → 发现是同进程 → 直接返回Stub实例
→ 调用 stub.getData() → 直接方法调用(无IPC开销)

判断依据:
obj.queryLocalInterface(DESCRIPTOR) != null → 同进程
1
2
3
4
5
6
7
8
9
10
11

# 九、Binder线程池管理

# 9.1 Binder线程池的结构

每个使用Binder的进程都有一个Binder线程池:

┌────────────────────────────────────────┐
│  进程的Binder线程池                      │
│  ┌──────────┐                          │
│  │ 主Binder  │ ← 首次调用时创建         │
│  │  线程     │   通过BC_ENTER_LOOPER注册│
│  └──────────┘                          │
│  ┌──────────┐ ┌──────────┐             │
│  │ 工作线程1  │ │ 工作线程2  │ ← 按需创建  │
│  │          │ │          │   通过BR_SPAWN_LOOPER请求│
│  └──────────┘ └──────────┘             │
│                                        │
│  默认最大线程数:15(可配置)              │
│  线程在空闲时阻塞在ioctl(BINDER_WRITE_READ)│
└────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 9.2 线程池的动态管理

// ProcessState.cpp:进程级Binder管理
ProcessState::ProcessState(const char* driver) {
    mDriverFD = open(driver, O_RDWR);  // 打开/dev/binder
    mmap(NULL, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
    // BINDER_VM_SIZE = 1MB - 8KB
    
    mMaxThreads = DEFAULT_MAX_BINDER_THREADS;  // 默认15
    ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &mMaxThreads);
}

// IPCThreadState.cpp:线程级Binder管理
void IPCThreadState::joinThreadPool(bool isMain) {
    // 通知驱动:此线程加入Binder线程池
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
    
    do {
        // 阻塞等待Binder请求
        result = getAndExecuteCommand();
        
        // 驱动可能发送BR_SPAWN_LOOPER:请求创建新线程
        // 当所有线程都在忙时,驱动会发出此请求
    } while (result != -ECONNREFUSED && result != -EBADF);
    
    mOut.writeInt32(BC_EXIT_LOOPER);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 9.3 线程池扩容策略

Binder驱动的线程管理策略:

当收到新的事务请求时:
1. 查找目标进程的空闲Binder线程
2. 如果有空闲线程 → 唤醒并分配任务
3. 如果没有空闲线程:
   a. 当前线程数 < max_threads → 发送BR_SPAWN_LOOPER,请求创建新线程
   b. 当前线程数 >= max_threads → 将事务放入todo队列等待
4. 如果todo队列也满了 → 返回BR_FAILED_REPLY

注意事项:
- 主线程(BC_ENTER_LOOPER)不计入max_threads
- 每个线程同时只处理一个事务(同步模型)
- 如果Server处理慢,Client会一直阻塞在ioctl
- 因此Binder调用不应在主线程做耗时操作(否则ANR)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 十、Binder中的引用计数与生命周期

# 10.1 Binder的引用计数机制

Binder使用两级引用计数管理对象生命周期:

强引用(Strong Reference):
- 只要还有强引用,Binder实体就不会被销毁
- BC_ACQUIRE / BC_RELEASE 增减强引用

弱引用(Weak Reference):
- 弱引用不阻止实体销毁
- BC_INCREFS / BC_DECREFS 增减弱引用
- 用于缓存场景:弱引用可以在强引用归零后"复活"

示意图:
Client进程A  ──strong ref──→  ┌──────────┐
Client进程B  ──strong ref──→  │ Binder   │  Server进程
Client进程C  ──weak ref────→  │ 实体对象  │
                              └──────────┘
                              local_strong_refs = 2
                              local_weak_refs = 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 10.2 Death Notification(死亡通知)

// 当Server进程意外死亡时,Client可以收到通知
IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
    @Override
    public void binderDied() {
        // Server进程死亡了!
        // 需要重新连接或清理资源
        reconnect();
    }
};

// 注册死亡通知
serviceBinder.linkToDeath(deathRecipient, 0);

// 底层实现:
// 1. Client通过Binder驱动注册death notification
// 2. 驱动在Server进程的binder_proc中记录
// 3. 当Server进程退出时,内核调用binder_deferred_release()
// 4. 遍历所有注册了death notification的Client
// 5. 向Client发送BR_DEAD_BINDER消息
// 6. Client的DeathRecipient.binderDied()被调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 十一、Binder的安全机制

# 11.1 调用者身份验证

// Binder的安全核心:服务端可以获取调用者的真实身份
// 这个身份由内核保证,调用者无法伪造

public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
    // 获取调用者的UID和PID(由内核填充,不可伪造)
    int callingUid = Binder.getCallingUid();
    int callingPid = Binder.getCallingPid();
    
    // 权限检查
    if (checkCallingPermission("android.permission.READ_CONTACTS") 
            != PackageManager.PERMISSION_GRANTED) {
        throw new SecurityException("No permission!");
    }
    
    // 内核实现:
    // binder_transaction() {
    //     t->sender_euid = task_euid(current);  // 从进程task_struct获取
    //     // 这个值由内核保证,用户空间无法修改
    // }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 11.2 SELinux对Binder的保护

SELinux Binder策略示例:

# 只允许system_app域的进程调用AMS
allow system_app activity_service:service_manager find;

# 禁止untrusted_app直接调用安装服务
neverallow untrusted_app installd:binder call;

Binder驱动中的SELinux检查点:
1. binder_transaction() → 检查是否允许向目标进程发送事务
2. binder_transfer_binder() → 检查是否允许传递Binder对象
3. binder_transfer_file() → 检查是否允许传递文件描述符
1
2
3
4
5
6
7
8
9
10
11
12

# 十二、Binder在Framework层的应用

# 12.1 四大组件与Binder

Android四大组件的通信全部依赖Binder:

Activity:
App → Binder → AMS.startActivity()      // 启动Activity
AMS → Binder → App.scheduleLaunchActivity()  // 回调创建Activity

Service:
App → Binder → AMS.startService()        // 启动Service
App → Binder → AMS.bindService()         // 绑定Service
Service → Binder → App (onServiceConnected)  // 回调返回IBinder

BroadcastReceiver:
App → Binder → AMS.broadcastIntent()     // 发送广播
AMS → Binder → App.scheduleReceiver()    // 分发广播

ContentProvider:
App → Binder → AMS.getContentProvider()  // 获取Provider
App → Binder → Provider.query/insert/... // 数据操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 12.2 系统API调用链路分析

以getSystemService为例,展示完整的Binder调用链:

// 应用代码
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);

// 调用链:
Context.getSystemService("window")
  → SystemServiceRegistry.getSystemService()
    → new WindowManagerImpl(context)
      → WindowManagerGlobal.getWindowManagerService()
        → ServiceManager.getService("window")
          → BinderProxy  // WMS的代理对象
        → IWindowManager.Stub.asInterface(binder)
          → IWindowManager.Proxy  // WMS的AIDL代理

// 后续调用:
wm.addView(view, params)
  → WindowManagerGlobal.addView()
    → ViewRootImpl.setView()
      → mWindowSession.addToDisplayAsUser(...)
        → Proxy.addToDisplayAsUser(...)  // Binder IPC
          → WMS端 Stub.onTransact()
            → Session.addToDisplayAsUser()
              → WMS.addWindow()  // 真正的窗口添加逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 十三、Binder的性能分析与优化

# 13.1 Binder通信的性能瓶颈

Binder调用的耗时分解:

Client端:
├── Parcel序列化          ~5-50μs(取决于数据量)
├── ioctl系统调用         ~10-20μs
├── 内核调度等待          ~50-500μs(取决于Server负载)
└── Parcel反序列化        ~5-50μs

Server端:
├── 线程唤醒             ~10-50μs
├── Parcel反序列化        ~5-50μs
├── 业务逻辑执行          变化很大
├── Parcel序列化          ~5-50μs
└── ioctl返回            ~10-20μs

典型的空调用(无业务逻辑)延迟:~100-200μs
有数据的调用延迟:~200μs - 数毫秒
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 13.2 Binder传输大小限制

Binder缓冲区限制:
- 普通进程:1MB - 8KB ≈ 1016KB
- ServiceManager:128KB

超出限制会抛出 TransactionTooLargeException

大数据传输方案:
┌──────────────────┬──────────────────────────────┐
│ 数据量            │ 推荐方案                      │
├──────────────────┼──────────────────────────────┤
│ < 100KB          │ 直接通过Binder传输             │
│ 100KB ~ 1MB      │ 使用Bundle传输,注意分块       │
│ > 1MB            │ 使用ContentProvider + Cursor  │
│                  │ 或使用共享内存(Ashmem)        │
│                  │ 或使用文件描述符传递            │
│ 超大文件          │ 传递文件路径或ParcelFileDescriptor │
└──────────────────┴──────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 13.3 Binder优化实践

1. 减少IPC调用次数(批量操作优于多次调用):
   // 差:多次IPC
   for (Item item : items) {
       service.addItem(item);  // 每次都是一次IPC
   }
   // 好:一次IPC
   service.addItems(items);  // 批量传输

2. 使用oneway修饰符(异步调用,不等待返回):
   // AIDL中声明
   oneway interface ICallback {
       void onResult(String result);  // 异步回调,不阻塞调用者
   }

3. 避免在主线程进行Binder调用:
   // 差:主线程阻塞
   String data = service.getData();
   // 好:子线程调用
   executor.execute(() -> {
       String data = service.getData();
       handler.post(() -> updateUI(data));
   });

4. 合理设置Binder线程池大小:
   // 默认15个线程,如果Server并发请求多,可以适当增大
   BinderInternal.setMaxThreads(20);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 十四、面试高频问题与深度分析

# 14.1 Binder为什么是一次拷贝?共享内存不是更快吗?

一次拷贝 vs 零拷贝(共享内存):

Binder(一次拷贝):
优点:安全(数据通过内核中转,可以做权限检查)
缺点:比共享内存多一次拷贝

共享内存(零拷贝):
优点:最快(无任何拷贝)
缺点:
  - 无法验证对方身份(任何映射到共享内存的进程都能读写)
  - 需要额外的同步机制(信号量/互斥锁)
  - 无法做权限控制(内核不参与传输过程)

Android的选择:安全 > 极致性能
对于系统级IPC,安全比多省一次拷贝更重要
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 14.2 AIDL中的in/out/inout修饰符是什么意思?

// in:数据从Client传到Server(默认)
void sendData(in Bundle data);
// Client: 序列化data → Server: 反序列化得到data
// Server修改data不会影响Client的data

// out:数据从Server传回Client
void getData(out Bundle data);
// Client: 发送空Bundle → Server: 填充data → Client: 收到填充后的data

// inout:双向传输
void processData(inout Bundle data);
// Client: 序列化data → Server: 修改data → Client: 收到修改后的data
// 注意:inout需要两次拷贝,性能最差
1
2
3
4
5
6
7
8
9
10
11
12
13

# 14.3 Binder调用是同步的还是异步的?

默认:同步阻塞调用
Client调用 → 阻塞等待 → Server处理 → 返回结果 → Client继续

异步(oneway):
声明:oneway interface ICallback { void onResult(String data); }
Client调用 → 立即返回 → Server在Binder线程中处理
注意:oneway调用没有返回值,且不保证顺序

特殊情况(同进程):
如果Client和Server在同一进程
→ 不经过Binder驱动
→ 直接方法调用(最快)
→ asInterface()中的queryLocalInterface判断
1
2
3
4
5
6
7
8
9
10
11
12
13

# 十五、IPC通信方式详解

除了Binder之外,Android还提供了多种IPC通信方式,开发者可以根据具体需求选择适当的方案。

# 15.1 Intent通信设计

Activity、Service、Receiver都支持在Intent中传递Bundle数据,而Bundle实现了Parcelable接口,可以在不同的进程间进行传输。

使用场景举例:App通过Intent调用打电话;App获取手机存储中图片资源;App监听手机屏幕亮灭屏事件;App分享文件到QQ等,都属于跨进程通信。

# 15.2 文件共享通信设计

Android系统基于Linux,并发读取文件没有限制,甚至允许两个线程同时对一个文件进行读写操作。可以在一个进程中序列化一个对象到文件系统中,在另一个进程中反序列化恢复这个对象(注意并不是同一个对象,只是内容相同)。

注意:SharedPreferences不适合用于IPC,系统对它的读写有一定的缓存策略,在高并发读写场景下有很大几率丢失数据。

# 15.3 Messenger通信设计

Messenger是一种轻量级的IPC方案,底层实现是AIDL,一次只处理一个请求,在服务端不需要考虑线程同步的问题。

Messenger通信流程:

服务端:
Service → Handler → Messenger → onBind返回Binder

客户端:
bindService → 获取IBinder → 创建Messenger → 发送Message
↕ (双向通信时)
客户端创建Handler+Messenger → 通过Message.replyTo传递给服务端
1
2
3
4
5
6
7
8
9

关键点:

  • 客户端通过bindService的onServiceConnected获取服务端Messenger
  • 服务端通过Message.replyTo获取客户端Messenger
  • Messenger中的Handler以串行方式处理队列中的消息,不存在并发执行

# 15.4 AIDL跨进程通信

AIDL可以解决并发和跨进程调用方法的问题,Messenger本质上也是AIDL,只不过系统做了封装方便上层调用。

AIDL通信步骤:

服务端:

  1. 新建定义AIDL文件,声明服务需要向客户端提供的接口
  2. 在Service子类中实现AIDL中定义的接口方法
  3. 在AndroidManifest.xml中注册服务并声明为远程服务

客户端:

  1. 拷贝服务端的AIDL文件到目录下
  2. 使用Stub.asInterface接口获取服务器的Binder,调用服务提供的接口方法
  3. 通过Intent指定服务端的服务名称和所在包,绑定远程Service

注意:客户端调用远程服务的方法运行在服务端的Binder线程池中,同时客户端线程会被挂起,如果服务端方法执行耗时,会导致客户端ANR。

# 15.5 ContentProvider

ContentProvider是Android中用于数据共享的IPC机制。继承ContentProvider类实现6个抽象方法,这六个方法均运行在ContentProvider进程中,除onCreate运行在主线程里,其他五个方法由外界回调运行在Binder线程池中。

底层数据可以是SQLite数据库、文件,也可以是内存中的数据。

ContentProvider的跨进程通信原理:

App进程A                    system_server                 App进程B
    │                           │                          │(ContentProvider所在进程)
    │ getContentResolver()      │                          │
    │   .query(uri, ...)        │                          │
    │ → ContentResolver         │                          │
    │   .acquireProvider(uri)   │                          │
    │ ────Binder──→            │ AMS.getContentProvider() │
    │                           │ → 查找已发布的Provider   │
    │                           │ → 如果Provider进程未启动 │
    │                           │   → 先启动进程           │
    │                           │ ────返回IContentProvider│
    │ ←────Binder──           │   Binder代理对象          │
    │                           │                          │
    │ 后续直接通过IContentProvider的Binder代理通信          │
    │ ───────────── Binder IPC ──────────────────→       │
    │                                                      │ query() 在Binder线程池执行
    │ ←──────────── Cursor(CursorWindow) ────────────     │

关键设计:
1. 首次访问通过AMS获取Provider代理,后续直接P2P通信
2. CursorWindow使用匿名共享内存(ashmem)传输大量数据
   → 突破Binder 1MB限制
   → CursorWindow默认大小2MB
3. ContentProvider支持批量操作applyBatch(),减少IPC次数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 15.6 Socket通信设计

Socket起源于Unix,可以通过本地回环地址(127.0.0.1)进行进程间通信。常用的Socket类型有两种:

  • 流式Socket(SOCK_STREAM):面向连接的,针对TCP服务应用
  • 数据报式Socket(SOCK_DGRAM):无连接的,对应UDP服务应用

一个Socket拥有两个缓冲区(一读一写),一次通信需要经历2次数据复制。

Socket在Android系统中的应用:

1. Zygote通信
   AMS通过LocalSocket与Zygote通信
   → 为什么不用Binder?
   → 因为Binder需要先初始化ServiceManager
   → 而Zygote启动时ServiceManager可能还未就绪
   → Socket是更原始、更可靠的通信方式

2. ADB通信
   adb server ←TCP Socket→ adbd守护进程
   → 支持远程调试(adb connect ip:5555)

3. LocalSocket(Unix Domain Socket)
   不经过网络协议栈,性能优于TCP Socket
   使用文件路径作为地址(如/dev/socket/zygote)
   → 比TCP快约2-3倍(无网络层开销)
   
4. Socket vs Binder对比
   ├── Socket:全双工,支持流式传输,2次拷贝
   ├── Binder:半双工(需等待reply),1次拷贝,支持身份验证
   └── 选择原则:系统底层用Socket,应用层用Binder
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 15.7 IPC方式对比

IPC方式 数据拷贝次数 安全性 特点
共享内存 0次 低 性能最好,但控制复杂
Binder 1次 高 Android推荐,支持身份验证
管道 2次 中 固定读写端,可能阻塞
消息队列 2次 中 克服了管道的缺点
Socket 2次 中 支持C/S模式,适合网络通信

# 十六、总结

Binder是Android系统最核心的基础设施,理解Binder就是理解Android架构的钥匙:

Binder的核心知识图谱:

基础原理
├── mmap + 一次拷贝 → 高性能
├── 内核UID验证 → 高安全
├── 引用计数 → 自动生命周期管理
└── C/S + Proxy-Stub → 面向对象的IPC

系统应用
├── ServiceManager → 服务注册中心
├── AMS/PMS/WMS → 通过Binder提供服务
├── 四大组件 → 通过Binder与AMS交互
└── Intent/ContentProvider → Binder之上的高级抽象

开发实践
├── AIDL → 自动生成Binder代码
├── Messenger → 基于Handler的简单IPC
├── ContentProvider → 数据共享
└── 性能优化 → 减少调用次数、异步化、合理设置线程池
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

从Linux驱动层的binder_ioctl,到Framework层的IBinder接口,再到应用层的AIDL,Binder贯穿了Android系统的每一层。掌握Binder的原理,是成为Android高级开发者的必经之路。

上次更新: 2026/06/10, 11:13:41
系统启动Zygote
Handler消息机制

← 系统启动Zygote Handler消息机制→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式