Android源码分析-从AIDL了解Binder机制

从AIDL了解Binder

前面简单学习了一下AIDL的用法,接下来就从AIDL入手,探究一下Binder机制。
在学习的过程中,看了以下几篇文章,觉得很有价值:
彻底理解Android Binder通信架构
Binder学习指南
Android Bander设计与实现 - 设计篇

背景知识

首先要知道的是,在Linux系统中,存在很多进程,不同进程之间,数据是不会共享的,他们各自有自己的空间。因此两个进程之间要想交换数据,需要一种机制来做一条数据通路。

还有一点,在Linux系统中,存在内核空间和用户空间两个概念。Linux内核是需要高度安全机制保护起来的,而我们的应用程序则只能运行在开放的用户空间中。如果应用程序需要访问内核空间,需要通过系统调用来实现。

因此,要想实现进程间的通信,我们可以通过在内核空间做一个“枢纽”,不同的进程虽然互相没法访问各自的内存,但是他们都可以用过系统调用来访问我们创建的“枢纽”。Binder机制就是这样的一个“枢纽系统”。

既然Android系统基于Linux系统,那么为什么要自创一套Bidner机制,而不用Linux现成的呢?在知乎上有篇回答很好:为什么Android系统要采用Binder机制做IPC?

Binder通信模型

首先在内核中,存在一个作为枢纽的东西,叫做Binder Driver(Binder驱动)。在Binder机制中,每一个进程最终都是需要在这里完成数据的交接。

其次,还有一个作为核心服务的东西叫做ServiceManager,与Binder Driver不同的是,他处于用户空间。

这两者,构成了Binder机制的核心。

举个例子,现在又两个进程A和B,A要访问B中的一个对象obj的方法f(),这就是跨进程通信了。那么在这之前,进程B会将自己注册在ServiceManager中,也就是说在这里存在一个表,进程B首先会把自己的信息作为一条数据插入在表中。之后,进程A要访问进程B,只需要访问这个ServiceManager,在这里查找B的先关信息,然后他就可以得到这个对象obj,之后就可以直接调用方法f()。

在这个流程里面,实际上并没有真的获取到对象obj,只是获取了一个obj的代理对象。实际对象还是在进程B中。调用f()时,传入的参数只会交给这个代理对象,然后代理对象再负责把数据交给真实对象。而在这整个流程之中,A和B还有ServiceManager都是进程,他们之间的数据交换都是要直接交给Binder驱动的。说起来有点乱,画个图就看出来了:

图中,虚线表示两者之间不是直接交互,因为这三者之间的交互实际上都是通过实线做的。

从AIDL到Binder

AIDL说白了其实就是帮我实现了一个可以用作Binder通信的类,抛开AIDL,我们自己也可以写一个差不多的,也可以用。通过AIDl自动生成的类,定义了一个内部类,并让内部类继承了Binder类。所以,我们只需继承Binder,也可以做简单的IPC了。

从Client开始

从MyAidlClient开始,探寻一下Binder通信的流程。

首先,如图所示

通过已经获得的IBinder对象,这里调用asInterface()方法,返回了一个IMyAidlInterface类的对象,调用他的add()方法。那就从这里开始:

IMyAidlInterface.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Cast an IBinder object into an com.levent_j.myaidlserver.IMyAidlInterface interface,
* generating a proxy if needed.
*/
public static com.levent_j.myaidlserver.IMyAidlInterface asInterface(android.os.IBinder obj) {
//非空判断
if ((obj == null)) {
return null;
}
//查找本地是否存在 如果存在,则直接可以使用,就不需要跨进程通信了
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.levent_j.myaidlserver.IMyAidlInterface))) {
return ((com.levent_j.myaidlserver.IMyAidlInterface) iin);
}
//没有找到,那么就只能跨进程通信了
//这里通过IBinder对象创建了一个Proxy对象并返回
//从名字就可以看得出,返回了一个代理对象
return new com.levent_j.myaidlserver.IMyAidlInterface.Stub.Proxy(obj);
}

再来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//首先要知道,这个类实现了那个接口
private static class Proxy implements com.levent_j.myaidlserver.IMyAidlInterface {
//持有的一个IBinder对象的引用
private android.os.IBinder mRemote;
//创建对象的时候,只是让代理对象保持了对IBinder对象的引用
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
//返回保存的那个引用
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
//…………

}

调用asInterface()方法到这里就结束了,可以看到实际上返回来一个代理对象Proxy,那么之后调用add()方法也就是调用了代理对象的add()方法,也就是Proxy类的add()方法:

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

@Override
public int add(int arg1, int agr2) throws android.os.RemoteException {
//创建两个Parcel对象
//obtain()方法意味着这儿有个Parcel对象的缓存池,避免浪费
//Parcel对象就是支持跨进程对象的数据结构
//这个_data用来存放调用的方法的请求参数
android.os.Parcel _data = android.os.Parcel.obtain();
//_reply用来存放返回结果
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
//先向_data中写入数据
_data.writeInterfaceToken(DESCRIPTOR);
//两个arge刚好就是我们传入的参数
_data.writeInt(arg1);
_data.writeInt(agr2);
//重点来了,这里调用了IBinder对象的transact()方法
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
//最后释放掉
_reply.recycle();
_data.recycle();
}
return _result;
}

这个IBinder类是个接口,而在这获取的对象实际上是Binder.java中的内部类BinderProxy类的对象(什么?Proxy?对没错,这里又是一个代理)。那么获取到这个BinderProxy对象之后,如上所示调用了他的transcat()方法,将参数传入,之后数据传到Server那里,经过实际对象的add()之后会取得返回值。所以这里就是Binder的起点了:

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
//参数code为前面的Stub.TRANSACTION_add,作用是做一个标识,后面会用到
//两个Parcel对象,作为数据
//最后flags为0
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
//先检查一下两个Parcel
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");

if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0)) {
// For now, avoid spamming the log by disabling after we've logged
// about this interface at least once
mWarnOnBlocking = false;
Log.w(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY",
new Throwable());
}

final boolean tracingEnabled = Binder.isTracingEnabled();
if (tracingEnabled) {
final Throwable tr = new Throwable();
Binder.getTransactionTracker().addTrace(tr);
StackTraceElement stackTraceElement = tr.getStackTrace()[1];
Trace.traceBegin(Trace.TRACE_TAG_ALWAYS,
stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName());
}
try {
//最后是调用了transactNative()方法,也就是到了Native层
return transactNative(code, data, reply, flags);
} finally {
if (tracingEnabled) {
Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
}
}
}

看这个方法的定义:

1
2
3

public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;

从这里开始,就进入了native层:

在android_util_Binder.cpp中:

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
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
if (dataObj == NULL) {
jniThrowNullPointerException(env, NULL);
return JNI_FALSE;
}
//将Java的Parcel转换为C++的Parcel
Parcel* data = parcelForJavaObject(env, dataObj);
if (data == NULL) {
return JNI_FALSE;
}
Parcel* reply = parcelForJavaObject(env, replyObj);
if (reply == NULL && replyObj != NULL) {
return JNI_FALSE;
}
//此时target指向了BpBinder
//这是开机时Zygote调用AndroidRuntime::startReg方法来完成jni方法的注册
//其中register_android_os_Binder()过程就有一个初始并注册BinderProxy的操作
IBinder* target = (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);
if (target == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
return JNI_FALSE;
}

ALOGV("Java code calling transact on %p in Java object %p with code %" PRId32 "\n",
target, obj, code);


bool time_binder_calls;
int64_t start_millis;
if (kEnableBinderSample) {
// Only log the binder call duration for things on the Java-level main thread.
// But if we don't
time_binder_calls = should_time_binder_calls();

if (time_binder_calls) {
start_millis = uptimeMillis();
}
}

//这里就是BpBinder的transact()
//printf("Transact from Java code to %p sending: ", target); data->print();
status_t err = target->transact(code, *data, reply, flags);
//if (reply) printf("Transact from Java code to %p received: ", target); reply->print();

if (kEnableBinderSample) {
if (time_binder_calls) {
conditionally_log_binder_call(start_millis, target, code);
}
}

if (err == NO_ERROR) {
return JNI_TRUE;
} else if (err == UNKNOWN_TRANSACTION) {
return JNI_FALSE;
}

signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/, data->dataSize());
return JNI_FALSE;
}

然后是BpBinder.cpp中的transact()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
//IPCThreadState采用单例模式
//返回了一个status
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}

return DEAD_OBJECT;
}

到了IPCThreadState.cpp的transact()方法:

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
tatus_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck();

flags |= TF_ACCEPT_FDS;

IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
<< handle << " / code " << TypeCode(code) << ": "
<< indent << data << dedent << endl;
}

if (err == NO_ERROR) {
LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
(flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
//传输数据
//看函数名应该是写入数据了
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
}

if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
}

//根据是否是ONE WAY方式而分别给waitForResponse()传了不同的参数
if ((flags & TF_ONE_WAY) == 0) {
#if 0
if (code == 4) { // relayout
ALOGI(">>>>>> CALLING transaction 4");
} else {
ALOGI(">>>>>> CALLING transaction %d", code);
}
#endif
if (reply) {
//等待应答
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
#if 0
if (code == 4) { // relayout
ALOGI("<<<<<< RETURNING transaction 4");
} else {
ALOGI("<<<<<< RETURNING transaction %d", code);
}
#endif

IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
<< handle << ": ";
if (reply) alog << indent << *reply << dedent << endl;
else alog << "(none requested)" << endl;
}
} else {

err = waitForResponse(NULL, NULL);
}

return err;
}

这里的write方法显然是写入数据

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
//写入数据 
//此时cmd:BC_TRANSACTION
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数据结构
binder_transaction_data tr;

tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
tr.target.handle = handle;//handle指向AMS
tr.code = code;
tr.flags = binderFlags;
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;

const status_t err = data.errorCheck();
if (err == NO_ERROR) {//数据没有错误,则封装数据
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();
} else if (statusBuffer) {
tr.flags |= TF_STATUS_CODE;
*statusBuffer = err;
tr.data_size = sizeof(status_t);
tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
tr.offsets_size = 0;
tr.data.ptr.offsets = 0;
} else {
return (mLastError = err);
}
//给mOut写数据
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));

return NO_ERROR;
}

可以看出,mOut用来将数据写入
那么在将数据写入之后,来到了这个waitForResponse()方法,等待应答

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
//一个死循环,一直等待返回数据
while (1) {
//调用taklWithDriver()方法,返回一个错误码
//如果有error 则break
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break;
//没有可用数据,继续循环
if (mIn.dataAvail() == 0) continue;
//从mIn读数据
cmd = (uint32_t)mIn.readInt32();

IF_LOG_COMMANDS() {
alog << "Processing waitForResponse Command: "
<< getReturnString(cmd) << endl;
}
//通过cmd
switch (cmd) {
//本次通讯结束
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;

case BR_DEAD_REPLY:
err = DEAD_OBJECT;
goto finish;

case BR_FAILED_REPLY:
err = FAILED_TRANSACTION;
goto finish;

case BR_ACQUIRE_RESULT:
{
ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
const int32_t result = mIn.readInt32();
if (!acquireResult) continue;
*acquireResult = result ? NO_ERROR : INVALID_OPERATION;
}
goto finish;

case BR_REPLY:
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
if (err != NO_ERROR) goto finish;

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, this);
} else {
err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
freeBuffer(NULL,
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), this);
}
} else {
freeBuffer(NULL,
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), this);
continue;
}
}
goto finish;

default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}

finish:
if (err != NO_ERROR) {
if (acquireResult) *acquireResult = err;
if (reply) reply->setError(err);
mLastError = err;
}

return err;
}

还有talkWithDriver()方法:

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//交给Driver处理 此时mOut已经有了数据,mIn还没有,这里来处理数据
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}

binder_write_read bwr;

// Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize();

// We don't want to write anything if we are still reading
// from data left in the input buffer and the caller
// has requested to read the next data.
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();

// This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}

IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
if (outAvail != 0) {
alog << "Sending commands to driver: " << indent;
const void* cmds = (const void*)bwr.write_buffer;
const void* end = ((const uint8_t*)cmds)+bwr.write_size;
alog << HexDump(cmds, bwr.write_size) << endl;
while (cmds < end) cmds = printCommand(alog, cmds);
alog << dedent;
}
alog << "Size of receive buffer: " << bwr.read_size
<< ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
}
//输入和输出数据都为空则直接返回
// Return immediately if there is nothing to do.
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
IF_LOG_COMMANDS() {
alog << "About to read/write, write size = " << mOut.dataSize() << endl;
}
#if defined(__ANDROID__)
//ioctl()执行到Binder Driver中 这里才是真正与Driver通信了
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
IF_LOG_COMMANDS() {
alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
}
} while (err == -EINTR);

IF_LOG_COMMANDS() {
alog << "Our err: " << (void*)(intptr_t)err << ", write consumed: "
<< bwr.write_consumed << " (of " << mOut.dataSize()
<< "), read consumed: " << bwr.read_consumed << endl;
}

if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else
mOut.setDataSize(0);
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
alog << "Remaining data size: " << mOut.dataSize() << endl;
alog << "Received commands from driver: " << indent;
const void* cmds = mIn.data();
const void* end = mIn.data() + mIn.dataSize();
alog << HexDump(cmds, mIn.dataSize()) << endl;
while (cmds < end) cmds = printReturnCommand(alog, cmds);
alog << dedent;
}
return NO_ERROR;
}

return err;
}

所以talkWithDriver()方法是直接去和Binder驱动通信了,其核心是ioctl()方法。

在通信结束之后,回到最初的起点,等待得到返回值(如果有的话),最后从mIn拿到返回的数据。

Server端做了什么

现在已经知道了,数据通过Binder代理,现在已经到了Server端,主要处理过程在内部类Stub中的onTransact()方法内:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
//正是这个方法标识,要调用add()方法
case TRANSACTION_add: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
//这里调用add()
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}

曾记否,在Server端重写了add()方法,对没错,这里就是调用了那个add()方法

总结

总体上来说,Binder的整个流程就是:

  1. Client
  2. 创建binder_transaction_data
  3. 填code
  4. 参数填入data.buffer
  5. 填入target.handle(Client端的引用)
  6. BC_TRANSACTION发送给Binder驱动
  7. 查找目标,填写target.ptr(Server端的实体)
  8. 到接受线程
  9. 调用onTransact()方法
  10. Server

我们说,Bidner相较于其他IPC机制的一个优势就在于只存在一次拷贝。那么这是怎么一回事呢?
通过mmap()映射了一片缓存池,数据拷贝时,binder_transaction_data是可以分为很多部分,但是其中只有一个叫做buffer的部分是大小不可预料的,其他的部分其实大小是限定的。因此除了buffer之外的其他部分由接收方自己提供,而buffer的存储区由缓存池提供,这样就完成了数据的“一次拷贝”,给人的感觉就是完整的数据直接从Client端拷贝到了Server端,实际上还是借助了内核。