AIDL 调用到 Binder 驱动完整链路
本文用一个简单的 AIDL 加法接口说明一次跨进程 Binder 调用是如何从 Java Proxy.add() 走到 native transact()、talkWithDriver()、ioctl(BINDER_WRITE_READ),再到服务端 onTransact() 并返回结果的。
示例接口:
aidl
interface ICalculatorService {
String add(int a, int b);
}
客户端调用:
java
String result = calculatorService.add(1, 2);
最终服务端执行:
java
return String.valueOf(a + b);
1. AIDL 生成的核心结构
AIDL 编译后会生成一个 Java 接口,里面通常包含:
ICalculatorService:业务接口,声明add(int a, int b)。Stub:服务端 Binder,本质继承Binder,重写onTransact()。Proxy:客户端代理,持有远端IBinder,通过transact()发起跨进程调用。
生成代码的大致结构如下:
java
public interface ICalculatorService extends IInterface {
String add(int a, int b) throws RemoteException;
abstract class Stub extends Binder implements ICalculatorService {
static final String DESCRIPTOR = "xxx.ICalculatorService";
static final int TRANSACTION_add = IBinder.FIRST_CALL_TRANSACTION + 0;
public static ICalculatorService asInterface(IBinder obj) {
IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (iin instanceof ICalculatorService) {
return (ICalculatorService) iin;
}
return new Proxy(obj);
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case INTERFACE_TRANSACTION:
reply.writeString(DESCRIPTOR);
return true;
case TRANSACTION_add:
data.enforceInterface(DESCRIPTOR);
int _arg0 = data.readInt();
int _arg1 = data.readInt();
String _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeString(_result);
return true;
}
return super.onTransact(code, data, reply, flags);
}
}
}
服务端真正做加法的是业务实现:
java
public class CalculatorService extends ICalculatorService.Stub {
@Override
public String add(int a, int b) {
return String.valueOf(a + b);
}
}
Binder 本身不负责加法。Binder 只负责把调用请求送到服务端,真正的加法发生在服务端 this.add(_arg0, _arg1)。
2. 客户端 Proxy.add() 做了什么
跨进程调用时,asInterface() 返回的是 Proxy。客户端调用:
java
calculatorService.add(1, 2);
实际进入的是 Proxy.add():
java
@Override
public String add(int a, int b) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(a);
_data.writeInt(b);
mRemote.transact(TRANSACTION_add, _data, _reply, 0);
_reply.readException();
return _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
}
_data 中写入的内容大致是:
text
interface token: "xxx.ICalculatorService"
int: 1
int: 2
然后调用:
java
mRemote.transact(TRANSACTION_add, _data, _reply, 0);
这里:
TRANSACTION_add是方法编号。_data是请求参数。_reply用来接收返回值。flags = 0表示普通同步调用,不是oneway。
3. Java BinderProxy.transact()
跨进程时,mRemote 通常是 BinderProxy。
BinderProxy.transact() 会做一些检查和统计,核心是调用 native 方法:
java
public boolean transact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
// ...
final boolean result = transactNative(code, data, reply, flags);
// ...
return result;
}
源码位置:
text
base/core/java/android/os/BinderProxy.java
4. JNI android_os_BinderProxy_transact()
transactNative() 对应 JNI 层的 android_os_BinderProxy_transact()。
核心逻辑是:
cpp
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) {
Parcel* data = parcelForJavaObject(env, dataObj);
Parcel* reply = parcelForJavaObject(env, replyObj);
IBinder* target = getBPNativeData(env, obj)->mObject.get();
status_t err = target->transact(code, *data, reply, flags);
// ...
}
源码位置:
text
base/core/jni/android_util_Binder.cpp
此处的 target 是 native 层的 IBinder*。如果是跨进程 Binder,它通常是 BpBinder。
5. BpBinder::transact()
BpBinder 是远端 Binder 对象在当前进程中的代理。
BpBinder::transact() 最终调用当前线程的 IPCThreadState::transact():
cpp
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
// ...
status = IPCThreadState::self()->transact(
binderHandle(), code, data, reply, flags);
// ...
}
源码位置:
text
native/libs/binder/BpBinder.cpp
这里的 binderHandle() 是 Binder 驱动分配的远端对象 handle。客户端并不直接持有服务端对象指针,而是持有一个 handle。
6. ProcessState 如何连接 Binder 驱动
libbinder 中每个进程有一个 ProcessState 单例。第一次使用 Binder 时会初始化它。
默认 Binder 驱动路径:
cpp
#ifdef __ANDROID_VNDK__
const char* kDefaultDriver = "/dev/vndbinder";
#else
const char* kDefaultDriver = "/dev/binder";
#endif
源码位置:
text
native/libs/binder/ProcessState.cpp
初始化时会打开 Binder 驱动:
cpp
static unique_fd open_driver(const char* driver, String8* error) {
auto fd = unique_fd(open(driver, O_RDWR | O_CLOEXEC));
if (!fd.ok()) {
return {};
}
int vers = 0;
int result = ioctl(fd.get(), BINDER_VERSION, &vers);
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd.get(), BINDER_SET_MAX_THREADS, &maxThreads);
return fd;
}
ProcessState 构造时还会 mmap 一块空间,用来接收 Binder 驱动传过来的事务数据:
cpp
unique_fd opened = open_driver(driver, &error);
if (opened.ok()) {
mVMStart = mmap(nullptr, BINDER_VM_SIZE,
PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
opened.get(), 0);
}
if (opened.ok()) {
mDriverFD = opened.release();
}
所以"连接 Binder 驱动"的过程可以概括为:
text
open("/dev/binder", O_RDWR | O_CLOEXEC)
ioctl(fd, BINDER_VERSION)
ioctl(fd, BINDER_SET_MAX_THREADS)
mmap(fd)
保存 fd 到 ProcessState::mDriverFD
后续所有 Binder IPC 都通过这个 mDriverFD 和驱动交互。
7. IPCThreadState::transact()
BpBinder::transact() 进入:
cpp
IPCThreadState::self()->transact(handle, code, data, reply, flags);
核心实现:
cpp
status_t IPCThreadState::transact(int32_t handle,
uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags) {
flags |= TF_ACCEPT_FDS;
err = writeTransactionData(
BC_TRANSACTION, flags, handle, code, data, nullptr);
if ((flags & TF_ONE_WAY) == 0) {
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
err = waitForResponse(nullptr, nullptr);
}
return err;
}
源码位置:
text
native/libs/binder/IPCThreadState.cpp
这里做了两件关键的事情:
writeTransactionData():把请求封装成BC_TRANSACTION。waitForResponse():普通同步调用会等待服务端返回。
8. writeTransactionData() 如何封装请求
writeTransactionData() 会构造 binder_transaction_data:
cpp
status_t IPCThreadState::writeTransactionData(int32_t cmd,
uint32_t binderFlags,
int32_t handle,
uint32_t code,
const Parcel& data,
status_t* statusBuffer) {
binder_transaction_data tr;
tr.target.ptr = 0;
tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
tr.data_size = data.ipcDataSize();
tr.data.ptr.buffer = data.ipcData();
tr.offsets_size = data.ipcObjectsCount() * sizeof(binder_size_t);
tr.data.ptr.offsets = data.ipcObjects();
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
对 add(1, 2) 来说:
text
cmd = BC_TRANSACTION
tr.target.handle = 服务端 Binder handle
tr.code = TRANSACTION_add
tr.data.ptr.buffer = Parcel 数据地址
tr.data_size = Parcel 数据大小
此时只是写入用户态线程本地的 mOut 缓冲区,还没有进入 Binder 驱动。
9. waitForResponse()
普通 AIDL 方法不是 oneway,所以客户端线程需要等待返回。
waitForResponse() 会循环调用 talkWithDriver():
cpp
status_t IPCThreadState::waitForResponse(Parcel* reply, status_t* acquireResult) {
while (1) {
if ((err = talkWithDriver()) < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
cmd = (uint32_t)mIn.readInt32();
switch (cmd) {
case BR_REPLY:
// 读取服务端返回
break;
default:
err = executeCommand(cmd);
break;
}
}
}
也就是说:
text
IPCThreadState::transact()
-> writeTransactionData() 把 BC_TRANSACTION 写入 mOut
-> waitForResponse()
-> talkWithDriver()
-> ioctl(BINDER_WRITE_READ)
10. talkWithDriver()
talkWithDriver() 是 libbinder 和 Binder 驱动通信的核心。
它会构造一个 binder_write_read:
cpp
status_t IPCThreadState::talkWithDriver(bool doReceive) {
binder_write_read bwr;
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
bwr.write_consumed = 0;
bwr.read_consumed = 0;
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0) {
err = NO_ERROR;
} else {
err = -errno;
}
}
binder_write_read 的含义:
text
bwr.write_size 要写给驱动的数据大小
bwr.write_buffer 写缓冲地址,也就是 mOut.data()
bwr.read_size 准备接收的数据大小
bwr.read_buffer 接收缓冲地址,也就是 mIn.data()
bwr.write_consumed 驱动实际消费的写数据大小
bwr.read_consumed 驱动实际写回的读数据大小
真正进入内核的系统调用是:
cpp
ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr);
这就是用户态 libbinder 和 Binder 驱动之间的核心通信点。
11. ioctl(BINDER_WRITE_READ) 做了什么
从用户态角度看,一次 ioctl(BINDER_WRITE_READ) 同时承担写和读:
text
写:把 mOut 中的 BC_TRANSACTION 交给驱动
读:从驱动读取 BR_TRANSACTION、BR_REPLY 等命令
客户端发起请求时,mOut 里是:
text
BC_TRANSACTION
binder_transaction_data
驱动读取后,会根据 binder_transaction_data 里的信息找到目标:
text
tr.target.handle
tr.code
tr.data.ptr.buffer
tr.data_size
然后驱动根据 handle 找到服务端 Binder 实体,把事务放到目标进程或目标线程的待处理队列中,并唤醒服务端 Binder 线程。
12. 服务端 Binder 线程如何收到请求
服务端 Binder 线程通常在 joinThreadPool() 中等待命令:
cpp
void IPCThreadState::joinThreadPool(bool isMain) {
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
do {
result = getAndExecuteCommand();
} while (...);
}
getAndExecuteCommand() 会调用 talkWithDriver(),从驱动读取命令。
当客户端事务到来时,服务端读到:
text
BR_TRANSACTION
binder_transaction_data
executeCommand() 中处理 BR_TRANSACTION:
cpp
case BR_TRANSACTION:
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size / sizeof(binder_size_t),
freeBuffer);
Parcel reply;
if (tr.target.ptr) {
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(
tr.code, buffer, &reply, tr.flags);
}
}
这里会把驱动传来的数据包装成服务端可读的 Parcel buffer,然后调用服务端本地 BBinder::transact()。
13. Java 服务端如何进入 onTransact()
如果服务端对象是 Java Binder,native 层会通过 android_util_Binder.cpp 回调 Java:
cpp
status_t onTransact(uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0) override {
JNIEnv* env = javavm_to_jnienv(mVM);
jboolean res = env->CallBooleanMethod(
mObject,
gBinderOffsets.mExecTransact,
code,
reinterpret_cast<jlong>(&data),
reinterpret_cast<jlong>(reply),
flags);
return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}
Java 层 Binder.execTransact() 再调用:
java
res = onTransact(code, data, reply, flags);
这个 onTransact() 就是 AIDL 生成的 Stub.onTransact()。
14. Stub.onTransact() 如何执行 add()
服务端 Stub.onTransact() 根据 code 判断方法:
java
case TRANSACTION_add:
data.enforceInterface(DESCRIPTOR);
int _arg0 = data.readInt();
int _arg1 = data.readInt();
String _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeString(_result);
return true;
如果客户端调用:
java
calculatorService.add(1, 2);
那么服务端读取到:
text
_arg0 = 1
_arg1 = 2
然后执行:
java
String _result = this.add(1, 2);
业务实现:
java
return String.valueOf(1 + 2);
得到:
text
"3"
再写回 reply:
java
reply.writeNoException();
reply.writeString("3");
15. 服务端如何返回结果
服务端 native 层处理完 BR_TRANSACTION 后,如果不是 oneway,会调用 sendReply():
cpp
if ((tr.flags & TF_ONE_WAY) == 0) {
if (error < NO_ERROR) reply.setError(error);
buffer.setDataSize(0);
constexpr uint32_t kForwardReplyFlags = TF_CLEAR_BUF;
sendReply(reply, (tr.flags & kForwardReplyFlags));
}
sendReply() 本质上也是一次 Binder 写操作,只是命令变成 BC_REPLY:
cpp
status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags) {
status_t statusBuffer;
err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
if (err < NO_ERROR) return err;
return waitForResponse(nullptr, nullptr);
}
返回路径:
text
服务端 writeTransactionData(BC_REPLY)
-> talkWithDriver()
-> ioctl(BINDER_WRITE_READ)
-> Binder 驱动
-> 驱动唤醒客户端等待线程
-> 客户端收到 BR_REPLY
16. 客户端如何读取 BR_REPLY
客户端之前阻塞在 waitForResponse(reply) 中。
驱动返回 BR_REPLY 后:
cpp
case BR_REPLY:
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
if (reply) {
if ((tr.flags & TF_STATUS_CODE) == 0) {
reply->ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size / sizeof(binder_size_t),
freeBuffer);
}
}
}
然后 native transact() 返回 Java,Proxy.add() 继续执行:
java
_reply.readException();
String result = _reply.readString();
return result;
最终客户端拿到:
text
"3"
17. 完整调用链总结
一次 calculatorService.add(1, 2) 的完整链路:
text
客户端 Java:
Proxy.add(1, 2)
-> Parcel 写 interface token、1、2
-> BinderProxy.transact(TRANSACTION_add, data, reply, 0)
客户端 JNI/native:
android_os_BinderProxy_transact()
-> BpBinder::transact()
-> IPCThreadState::transact(handle, code, data, reply, flags)
-> writeTransactionData(BC_TRANSACTION, handle, code, data)
-> mOut = [BC_TRANSACTION, binder_transaction_data]
-> waitForResponse()
-> talkWithDriver()
-> ioctl(mDriverFD, BINDER_WRITE_READ, &bwr)
Binder 驱动:
读取 BC_TRANSACTION
-> 根据 handle 找服务端 Binder 实体
-> 传递 Parcel 数据
-> 唤醒服务端 Binder 线程
-> 给服务端返回 BR_TRANSACTION
服务端 native:
talkWithDriver() 返回 BR_TRANSACTION
-> executeCommand(BR_TRANSACTION)
-> BBinder::transact()
-> JavaBBinder::onTransact()
服务端 Java:
Binder.execTransact()
-> Stub.onTransact()
-> data.readInt() 得到 1、2
-> this.add(1, 2)
-> reply.writeString("3")
服务端返回:
sendReply()
-> writeTransactionData(BC_REPLY)
-> talkWithDriver()
-> ioctl(BINDER_WRITE_READ)
客户端接收:
驱动返回 BR_REPLY
-> waitForResponse() 填充 reply Parcel
-> Java Proxy.add()
-> _reply.readString()
-> result = "3"
18. 四个关键 Binder 命令
跨进程同步调用中最关键的是四个命令:
text
客户端发请求:BC_TRANSACTION
服务端收请求:BR_TRANSACTION
服务端回结果:BC_REPLY
客户端收结果:BR_REPLY
其中:
BC_*表示 Binder Command,是用户态写给 Binder 驱动的命令。BR_*表示 Binder Return,是 Binder 驱动返回给用户态的命令。
19. 关键点记忆
transact() 不是直接调用服务端方法,它只是把请求封装成 Binder 事务。
writeTransactionData() 只负责把 BC_TRANSACTION 和 binder_transaction_data 写入 mOut。
talkWithDriver() 才是真正和 Binder 驱动交互的地方。
真正进入内核的是:
cpp
ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr);
服务端执行 add() 的位置是 AIDL 生成的 Stub.onTransact():
java
String _result = this.add(_arg0, _arg1);
Binder 负责跨进程传输,业务方法负责真正计算。