Android binder(RPC) 通信概念与架构

文章目录

一、preface

1、资料快车

1、Framework篇 - 彻底理解Binder通信架构

https://blog.csdn.net/u014294681/article/details/88094088

2、Framework-进程间通信之Binder机制AIDL

https://blog.csdn.net/blankmargin/article/details/126787525

3、Framework源码(Binder驱动解析)

https://zhuanlan.zhihu.com/p/542058702

4、Framework层的Binder(源码分析篇)

https://www.zhihu.com/tardis/zm/art/554115552?source_id=1005

5、书籍 - Android系统源代码情景分析

6、AIDL的使用详解(APP):https://blog.csdn.net/u014294681/article/details/88126988

2、概述

Binder 是 Android 的核心 IPC/RPC 机制,几乎承载了 Android 所有的跨进程通信:应用与系统服务、系统服务之间、HAL 与框架、甚至 dumpsysservice list 都建立在它之上。理解 Binder 是理解 Android 整个系统框架的前提。

本平台(RK3568 Android 11)的 Binder 实现是纯 AOSP 内核栈drivers/android/binder.c,约 6187 行),RK 没有对其做功能性改动------唯一的平台相关点是 rockchip_defconfig 打开了 CONFIG_ANDROID_BINDERFS=y,三个设备节点(/dev/binder/dev/hwbinder/dev/vndbinder)由 binderfs 创建并通过 init.rc 建立符号链接。

1)binder在哪里使用?发生在用户态的各个层级-- APP/framework/native/JNI/driver

2)使用的形式 -- aidl/hidl,无论是java/c++,都是getserver(client/Stub.proxy) / addserver(server/stub) 形式;

3)我们应该关注最顶层的实现,底层是恒定不变,只要简单识别即可,且工具已经帮我们实现封装(这里为什么不用代码来封装?工具如此不直观,纯写代码仍然有一定工作量并且都是重复代码,工具可以让我们集中精力定义和实现接口)

3)binder系统的复杂之处在于上层的层层复杂封装;

1.1 Binder与其它 IPC 的效率对比

Android 几乎所有跨进程通信都走 Binder,而非 Linux 原生的 pipe/socket/共享内存/消息队列。原因不只是"快",而是效率、安全、易用三者的综合最优。

(1)数据拷贝次数对比(核心)

IPC 方式 内核拷贝次数 说明
共享内存(shm/mmap) 0 零拷贝,但需自加锁、无内核仲裁,安全隐患大
Binder 1 mmap 把接收方地址映射进内核,发送方 copy_from_user 一次即达
pipe / FIFO 2 copy_from_user 发送方 + copy_to_user 接收方
UNIX socket 2 同上
消息队列(msgget) 2 同上
信号 0 只能传一个信号编号,不能传数据

Binder 的关键:接收进程在 open(/dev/binder)mmapPROT_READ)一段空间,内核在该进程页表里建立"内核页 ↔ 用户页"同一物理页映射(vm_insert_page)。一次 transaction 时,内核把发送方数据 copy_from_user 进这个内核页,接收进程用户态直接读到------省掉了传统 IPC 的第二次 copy_to_user

(2)综合能力对比

维度 Binder Socket 共享内存 pipe/FIFO 消息队列 信号 D-Bus
拷贝次数 1 2 0 2 2 --- 2
CS / 面向对象
内核安全仲裁 ✅ SELinux △(用户态)
死亡通知
强/弱引用计数
fd/对象传递
跨域策略(Treble 三域)

(3)为何 Binder "更高效"------不只是少一次拷贝

  1. 一次拷贝(核心):对中小消息(< mmap 上限,单端默认 1MB−2页),相比 socket/pipe 的两次拷贝减少约一半内核态拷贝开销;相比共享内存仅多一次拷贝,却换来内核仲裁与安全。
  2. 面向对象 + 引用计数 :通信单元是"对象引用"(binder node → handle),一次 getService 拿到 handle 后续调用复用,不必每次编解码地址/连接;强/弱引用 + 死亡通知让对象生命周期与进程解耦,无需应用层心跳。
  3. 线程池 + 优先级继承 :服务端单进程多 binder 线程(默认 15),应对高并发场景,驱动按需 BR_SPAWN_LOOPER 扩容;同步调用时发送方优先级继承到服务端线程binder_transaction_priority),保证 UI 线程发起的调用能及时在服务端响应,避免优先级反转。
  4. 内核内同步语义 :同步 transaction 天然阻塞发送方等 BR_REPLY,省去应用层等待/超时协议;oneway 则零等待异步投递(node 级串行化)。
  5. fd/对象直传flat_binder_objectBINDER_TYPE_FD 在内核里直接 binder_alloc_fd 把 fd 转移到目标进程(如 Surface/ashmem 句柄),无需序列化文件路径。
  6. 统一服务管理 + 安全模型 :servicemanager 提供按名字寻址,SELinux 在 security_binder_transaction 处对每次调用做"谁能调谁"判定,集中可控;socket/shm 要应用自行实现鉴权。

一句话 :共享内存最快但不安全也不好用;socket/pipe 通用但慢且无对象语义。Binder 用一次内核拷贝 + 内核仲裁 + 面向对象引用,在"足够快"和"安全/易用"之间取得 Android 需要的平衡------这是它取代传统 IPC 的根本原因。

1.2 区分RPC与IPC
复制代码
1、RPC和IPC
IPC(Inter-process communication 进程间通信)只搬数据;RPC(Remote Procedure call远程过程调用)在 IPC 之上再封装"调用哪个对象、哪个方法、什么参数、什么返回值"。Binder 底层是 IPC(一次 transaction 搬一个 binder_transaction_data),但 libbinder/AIDL 层把它包装成了 RPC------`transact(handle, code, data, reply)

2、RPC四要素
handle : 调用哪个服务
code : 调用哪个接口
data : 入参数据
reply : 出参数据
1.3 三大 binder 域(Treble 后)
设备 context manager 用途
/dev/binder framework libbinder servicemanager 应用/框架进程 ↔ 框架系统服务
/dev/hwbinder hwbinder libhwbinder hwservicemanager HIDL HAL(Treble 前风格)
/dev/vndbinder vendor libbinder(VNDK) vndservicemanager vendor 进程间

三者是三个独立的 binder_device,各持一个独立的 binder_context(独立的 context manager 节点),互不可见。

libbinder 在 VNDK 编译时(__ANDROID_VNDK__)默认打开 /dev/vndbinder

1.4 mmap内存技术

本质上就是 开辟一个特区内容空间 - 不区分用户空间和内核空间,用户态和内核态都可以畅通访问!

3、基础概念

复制代码
1、Bn/Bp
Bn (binder native) - CPP服务端implement
BB (Base binder) - native服务端
Bp (binder proxy) - 客户端

2、RPC/IPC
IPC : Inter-process commuication
RPC : Remote Procedure call - 在IPC基础上再封装一层

3.
AIDL : Android interface Defintion Language ,Android 接口定义语言,用于应用层进程间通信(IPC), Service与客户端跨进程调用(双向通信)
HIDL : HAL interface Definition Language HAL 接口定义语言

4、
defer : 延迟

5、shrinker -Linux内核的内存回收机制
shrinker - 内存收缩器
LRU - last Recently Used 最近最少使用
reclaim - 释放不活跃的内存
kswapd -  内核交换守护进程

二、Binder框架图

1、对等通信

1)

2)

2、binder三大角色

3、Binder各层级关键类

4、AIDL/HIDL binder

1)https://blog.csdn.net/yangwen123/article/details/79836109

2)普通Binder架构在这里插入图片描述

3)HIDL Binder架构

5、通信架构图

1)通信架构图

2)关键代码流程

复制代码
客户端调用 getService:

App 进程
    │
    ▼
BpServiceManager::getService(name)
    │
    ▼
BpRefBase::remote() → BpBinder(handle=0)
    │
    ▼
BpBinder::transact(GET_SERVICE, data, reply)
    │
    ▼
IPCThreadState::transact(handle=0, GET_SERVICE, ...)
    │
    ▼
ioctl(BINDER_WRITE_READ) ──────→ Binder Driver
                                      │
                                      ▼
                              查找 handle=0 对应的进程
                                      │
                                      ▼
System Server 进程
    │
    ▼
BBinder::onTransact(GET_SERVICE, ...)
    │
    ▼
BnServiceManager::onTransact(GET_SERVICE, ...)
    │
    ▼
ServiceManager::getService(name)  // 本地实现
    │
    ▼
返回结果 ←─────── IPCThreadState ──────── Binder Driver
                                      │
                                      ▼
                              客户端收到 reply

三、Binder 基础模型

3.1 Binder 全栈架构图(应用 → framework → native → libbinder → 内核)

自上而下五层,每层标注该层的关键技术;客户端调用沿箭头下沉 到内核,内核一次拷贝 + 跨进程投递到服务端,服务端 onTransact 自下而上执行。右列是各层对应的源码位置。

复制代码
   应用层   App / Java · Kotlin
 ┌───────────────────────────────────────────────────────────────────┐
 │ • AIDL 接口 • Stub.Proxy(客户端 Bp) / Stub(服务端 Bn)                │  app/src/**/aidl
 │ • ServiceConnection.bindService • IBinder / Binder.java           │  android.os.*
 │ • ServiceManager.getService / addService(系统服务)                │
 └───────────────────────────────────────────────────────────────────┘
                       │ JNI:android_util_Binder.cpp(Java ↔ native)
                       ▼
   Framework 层   frameworks/base(Java)
 ┌───────────────────────────────────────────────────────────────────┐
 │ • android.os.Binder(服务端)/ BinderProxy(客户端代理)            │  frameworks/base/core/java/android/os
 │ • android.os.Parcel(Java) • IServiceManager.aidl                  │
 └───────────────────────────────────────────────────────────────────┘
                       │ Parcel 跨 JNI 下沉到 C++
                       ▼
   Native / C++ 层   libbinder
 ┌───────────────────────────────────────────────────────────────────┐
 │ • BpBinder(handle, transact)   ── 客户端代理                        │  libs/binder/BpBinder.cpp
 │ • BBinder(onTransact)          ── 服务端桩                          │  libs/binder/Binder.cpp
 │ • IInterface / asInterface() / DECLARE_META_INTERFACE              │  libs/binder/IInterface.h
 │ • IServiceManager + defaultServiceManager() • Parcel(C++)          │  libs/binder/IServiceManager.cpp
 │ • AIDL 生成的 BnXXX/BpXXX 即此层;HIDL → libhwbinder                │
 └───────────────────────────────────────────────────────────────────┘
                       │ transact → writeTransactionData(BC_TRANSACTION)
                       ▼
   libbinder 运行时   frameworks/native/libs/binder
 ┌───────────────────────────────────────────────────────────────────┐
 │ • ProcessState::self()   open(/dev/binder) + mmap(PROT_READ)       │  libs/binder/ProcessState.cpp
 │                           setThreadPoolMaxThreadCount(默认 15)     │
 │ • IPCThreadState::self() talkWithDriver → ioctl(BINDER_WRITE_READ) │  libs/binder/IPCThreadState.cpp
 │                           BC/BR 主循环 + executeCommand(BR_*)       │
 │                           joinThreadPool(BC_ENTER/REGISTER_LOOPER) │
 └───────────────────────────────────────────────────────────────────┘
                       │ ioctl(/dev/binder, BINDER_WRITE_READ, {BC_TRANSACTION, ...})
                       ▼
   内核 binder 驱动   drivers/android/binder.c(~6200 行)
 ┌───────────────────────────────────────────────────────────────────┐
 │ • 数据结构:binder_proc / thread / node / ref / buffer / txn        │  binder.c / binder_alloc.c
 │ • binder_transaction(): handle → ref → node → target_proc          │
 │     ① security_binder_transaction      SELinux 仲裁                 │
 │     ② binder_alloc_new_buf             在 target mmap 空间分配 buffer│
 │     ③ ★ 一次拷贝 copy_from_user         发送方 → target buffer       │
 │     ④ fixup flat_binder_object          binder↔handle / fd 转移     │
 │     ⑤ 入 target todo + 唤醒线程          → 对端 BR_TRANSACTION       │
 │ • 引用计数(强/弱) • 死亡通知 • 优先级继承 • BR_SPAWN_LOOPER 线程池   │
 ├───────────────────────────────────────────────────────────────────┤
 │ • binderfs: /dev/binder   /dev/hwbinder   /dev/vndbinder           │  binderfs.c
 │   (三域 = 三个独立 binder_context / context manager,Treble 隔离)  │
 └───────────────────────────────────────────────────────────────────┘

读图

  • 五层从上到下封装厚度递减:应用层最厚(AIDL 自动生成 Stub/Proxy,开发者只写接口),libbinder 运行时最薄(直接 ioctl),内核是真正的"搬运工"。
  • 下沉路径(客户端)foo.方法() → Stub.Proxy transact → JNI → BpBinder::transactIPCThreadState::transactBC_TRANSACTIONioctl(BINDER_WRITE_READ)。每一层只做一件事:上层打包参数,下层搬数据。
  • 跨进程在内核发生 :客户端到内核是普通 ioctl,内核 binder_transaction 把数据一次拷贝 进服务端 mmap 空间、唤醒服务端线程------服务端进程这才参与(BR_TRANSACTIONBBinder::onTransact → 业务),全程对应用透明。
  • 三大域 :图中 /dev/binder|hwbinder|vndbinder 是三个独立 binderfs 设备,物理隔离 framework/hw/vendor 三套服务空间(见 1.3)。
  • 本图是"分层栈 "视角;1.3 是同一条链路的"调用时序"视角(Client/Server/Driver 三列),两者互补。

对照显示侧:libbinder 之于 binder ≈ libdrm 之于 DRM;AIDL 之于 libbinder ≈ "驱动自动生成胶水"(详见 Linux DRM 文档)。

3.2 核心概念

概念 说明
binder node 内核中代表"一个可被跨进程调用的对象"。服务端 BBinder 首次传递给驱动时创建,挂在 binder_proc->nodes(按 ptr 排序的红黑树)。
binder ref 客户端对某个 node 的"句柄引用"。binder_ref->data.desc 即用户态看到的 handle(0 表示 context manager)。同一进程对同一 node 只有一个 ref。
handle 用户态的 32 位引用号。handle==0 特指 servicemanager(context manager node)。
binder_buffer 在接收进程 mmap 空间里切出的一段缓冲,承载一次 transaction 的数据。用完由用户态 BC_FREE_BUFFER 归还。
binder_proc / binder_thread 一个打开 /dev/binder 的进程 / 一个 binder 线程。
flat_binder_object Parcel 中"对象的扁平表示"------把一个强/弱 binder、handle、fd 等塞进数据流,驱动在 transaction 时改写它(binder↔handle 翻译、fd 转移)。

3.3 引用计数(强/弱)

binder node 同时被内核(internal_strong_refs)和用户态(local_strong_refs)引用,强弱两套独立计数。用户态通过 BC_ACQUIRE/RELEASE/INCREFS/DECREFS 显式增减;驱动在 transaction 期间临时增持,完成后归还。当强引用归零且无弱引用时,node 被释放;客户端在此之前用 BC_REQUEST_DEATH_NOTIFICATION 注册的死亡通知会以 BR_DEAD_BINDER 投递。

3.4 BC / BR 协议

  • BC_(Binder Command) :用户态→驱动,写在 binder_write_read.write_buffer。如 BC_TRANSACTIONBC_REPLYBC_ACQUIREBC_ENTER_LOOPERBC_FREE_BUFFERBC_REQUEST_DEATH_NOTIFICATION
  • BR_(Binder Return) :驱动→用户态,读自 read_buffer。如 BR_TRANSACTIONBR_REPLYBR_TRANSACTION_COMPLETEBR_DEAD_REPLYBR_SPAWN_LOOPERBR_NOOP

一次 ioctl(BINDER_WRITE_READ) 同时携带一批 BC 与读出一批 BR。


四、源码目录

4.1 内核侧

复制代码
1.源码
kernel/drivers/android/*

2.UAPI
1)kernel/include/uapi/linux/android/binder.h(542 行,所有 ioctl 号、BC/BR、flat_binder_object 等)
2)kernel/include/uapi/linux/android/binderfs.h
文件 行数 角色
binder.c 6187 核心驱动:open/mmap/ioctl、transaction、node/ref/thread 管理、debugfs
binder_alloc.c 1244 每进程 buffer 分配器 + 一次拷贝页管理(LRU/shrinker)
binder_alloc.h 187 struct binder_alloc / binder_buffer / binder_lru_page
binderfs.c ~770 per-namespace 伪文件系统,动态创建 binder 设备节点 + binder-control
binder_internal.h 146 binder_context / binder_device、transaction-log、debug seq_file 声明
binder_trace.h ~415 ftrace binder 类别所有 TRACE_EVENT

4.2 用户态

路径 说明
libbinder frameworks/native/libs/binder/ 通用 Binder IPC:用于应用与系统服务(System Server)、应用之间等的常规进程间通信 关键类:ProcessStateIPCThreadStateBpBinderBBinderIServiceManagerParcel
libhwbinder system/libhwbinder/ 硬件 Binder IPC:专门用于 Android 框架(Framework)与硬件抽象层(HAL) 之间的通信
servicemanager frameworks/native/cmds/servicemanager/ main.cpp / ServiceManager.cpp(BnServiceManager) / Access.cpp(SELinux ACL)
hwservicemanager system/hwservicemanager 硬件 Binder IPC
aidl-gen system/tools/aidl/ .aidl 生成 BnXXX/BpXXX(C++/Java/NDK)
hidl-gen system/tools/hidl/ .hal 生成 HIDL 桩