要着手binder分析,我们可以用一个简单的activity跳转逻辑来分析,最好的办法是让intent中携带的数据超过1M的数据,然后通过logcat中异常堆栈来分析:
1
2
3
4
|
val intent = Intent(this, BitmapActivity::class.java)
val data = ByteArray(1024*1024)
intent.putExtra("data",data)
startActivity(intent)
|
此处是直接携带1M的数据,然后系统给我来了个异常信息:
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
|
2025-04-17 20:33:24.613 8782-8782 JavaBinder com.example.coroutinescopedemo E !!! FAILED BINDER TRANSACTION !!! (parcel size = 1049068)
--------- beginning of crash
2025-04-17 20:33:24.627 8782-8782 AndroidRuntime com.example.coroutinescopedemo E FATAL EXCEPTION: main
Process: com.example.coroutinescopedemo, PID: 8782
java.lang.RuntimeException: Failure from system
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1749)
at android.app.Activity.startActivityForResult(Activity.java:5533)
at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.kt:704)
at android.app.Activity.startActivityForResult(Activity.java:5486)
at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.kt:683)
at android.app.Activity.startActivity(Activity.java:5892)
at android.app.Activity.startActivity(Activity.java:5845)
at com.example.coroutinescopedemo.BottomSheetActivity.onCreate$lambda$0(BottomSheetActivity.kt:27)
at com.example.coroutinescopedemo.BottomSheetActivity.$r8$lambda$CWhZfDsJCDnJCQuDq0om0F9MZaU(Unknow
at com.example.coroutinescopedemo.BottomSheetActivity$$ExternalSyntheticLambda0.onClick(D8$$Synthet
at android.view.View.performClick(View.java:7753)
at android.view.View.performClickInternal(View.java:7730)
at android.view.View.access$3700(View.java:861)
at android.view.View$PerformClick.run(View.java:29146)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:210)
at android.os.Looper.loop(Looper.java:299)
at android.app.ActivityThread.main(ActivityThread.java:8293)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)
Caused by: android.os.TransactionTooLargeException: data parcel size 1049092 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(BinderProxy.java:624)
at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java:2664)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1743)
at android.app.Activity.startActivityForResult(Activity.java:5533)
at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.kt:704)
at android.app.Activity.startActivityForResult(Activity.java:5486)
at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.kt:683)
at android.app.Activity.startActivity(Activity.java:5892)
at android.app.Activity.startActivity(Activity.java:5845)
at com.example.coroutinescopedemo.BottomSheetActivity.onCreate$lambda$0(BottomSheetActivity.kt:27)
at com.example.coroutinescopedemo.BottomSheetActivity.$r8$lambda$CWhZfDsJCDnJCQuDq0om0F9MZaU(Unknow
at com.example.coroutinescopedemo.BottomSheetActivity$$ExternalSyntheticLambda0.onClick(D8$$Synthet
at android.view.View.performClick(View.java:7753)
at android.view.View.performClickInternal(View.java:7730)
at android.view.View.access$3700(View.java:861)
at android.view.View$PerformClick.run(View.java:29146)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:210)
at android.os.Looper.loop(Looper.java:299)
at android.app.ActivityThread.main(ActivityThread.java:8293)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)
|
可以看到异常分两块,一块是上面的java.lang.RuntimeException: Failure from system
,它是Instrumentation中的execStartActivity抛的异常,最终是因为在android.os.BinderProxy.transactNative(Native Method)中抛了android.os.TransactionTooLargeException: data parcel size 1049092 bytes
异常,异常堆栈越是往上面是异常所在点,越往下面是上层代码。当点击按钮的时候屏幕底层会给android应用层发送主线程的消息,然后在消息队列轮训该消息的时候,由于底层抛出异常,在looper轮训消息的时候继续往上层抛,最终该异常会抛给到ZygoteInit。java默认的异常处理机制是交给当前线程的defaultUncaughtExceptionHandler,而RuntimeInit中定义过主线程的defaultUncaughtExceptionHandler,最终该Handler是KillApplicationHandler,在该handler中先收集日志,然后kill掉进程。
客户端到驱动层
在上面堆栈中,我们直接分析IActivityTaskManager$Stub$Proxy.startActivity
方法,其中IActivityTaskManager$Stub$Proxy
类是aidl工具帮我们生成的类,它是IActivityTaskManager接口中的一个内部类,它是客户端拿到服务端的binder起始类,它的获取如下:
1
2
|
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);
|
其中ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE)拿到的是binderProxy对象,它是c++层的BinderProxy对应java层的BinderProxy对象,在IActivityTaskManager.Stub.asInterface中判断如果调用进程和目标进程不是一个的话,会返回Proxy对象,然后调用到Proxy的startActivity方法:
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
|
@Override
public int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int flags, ProfilerInfo profilerInfo,
Bundle options) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR); // 验证远程接口
_data.writeStrongBinder(caller != null ? caller.asBinder() : null);
_data.writeString(callingPackage);
if (intent != null) {
_data.writeInt(1);
intent.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
_data.writeString(resolvedType);
_data.writeStrongBinder(resultTo);
_data.writeString(resultWho);
_data.writeInt(requestCode);
_data.writeInt(flags);
if (profilerInfo != null) {
_data.writeInt(1);
profilerInfo.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
if (options != null) {
_data.writeInt(1);
options.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_startActivity, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
|
在该方法里面,会创建两个Parcel对象,一个是_data,一个是_reply。然后将参数都放到_data中,最终调用了mRemote的transact方法,并把_data和_reply传入其中。此处的_remote对象java层的BinderProxy对象,从堆栈上看然后调用了transactNative方法,该方法是一个native方法,对应的aosp中是android_util_Binder.cpp的android_os_BinderProxy_transact方法,可以看如下方法注册:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
static const JNINativeMethod gBinderProxyMethods[] = {
/* name, signature, funcPtr */
{"pingBinder", "()Z", (void*)android_os_BinderProxy_pingBinder},
{"isBinderAlive", "()Z", (void*)android_os_BinderProxy_isBinderAlive},
{"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
{"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
{"linkToDeathNative", "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
{"unlinkToDeathNative", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
{"addFrozenStateChangeCallbackNative",
"(Landroid/os/IBinder$FrozenStateChangeCallback;)V", (void*)android_os_BinderProxy_addFrozenStateChangeCallback},
{"removeFrozenStateChangeCallbackNative",
"(Landroid/os/IBinder$FrozenStateChangeCallback;)Z", (void*)android_os_BinderProxy_removeFrozenStateChangeCallback},
{"getNativeFinalizer", "()J", (void*)android_os_BinderProxy_getNativeFinalizer},
{"getExtension", "()Landroid/os/IBinder;", (void*)android_os_BinderProxy_getExtension},
};
|
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
|
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
//①、dataObj是java层传过来的发送数据的parcel
if (dataObj == NULL) {
jniThrowNullPointerException(env, NULL);
return JNI_FALSE;
}
//②、将java层的parcel数据转成native层的parcel
Parcel* data = parcelForJavaObject(env, dataObj);
if (data == NULL) {
return JNI_FALSE;
}
//③、将java层的reply的parcel数据转成native层的parcel
Parcel* reply = parcelForJavaObject(env, replyObj);
if (reply == NULL && replyObj != NULL) {
return JNI_FALSE;
}
//④、通过java层的BinderProxy获取到native层的BpBinder
IBinder* target = getBPNativeData(env, obj)->mObject.get();
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);
//⑤、调用native层的BpBinder的transact方法
status_t err = target->transact(code, *data, reply, flags);
if (err == NO_ERROR) {
return JNI_TRUE;
}
//⑥、通过jni调用到java层的Binder的transactionCallback方法
env->CallStaticVoidMethod(gBinderOffsets.mClass, gBinderOffsets.mTransactionCallback, getpid(),
code, flags, err);
if (err == UNKNOWN_TRANSACTION) {
return JNI_FALSE;
}
//⑦、输出错误信息
signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/, data->dataSize());
return JNI_FALSE;
}
|
在①处如果传进来的java层的parcel类型的data数据为空,则直接返回失败。
在②处将java层的parcel类型的data数据转成native层的parcel数据。
在③处将java层的parcel类型的reply数据转成native层的parcel数据。
在④处通过java层的BinderProxy获取到native层的BpBinder,主要是通过java层BinderProxy的mNativeData指针(native层BpBinder指针)来获取到native层的BpBinder。
在⑤处调用native层的BpBinder的transact方法。
在⑥处通过jni调用到java层的Binder的transactionCallback方法。
最后在⑦处根据transact的结果输出错误信息。
着重看下在上面⑤处,看下native层的BpBinder如何处理binder的:
1
2
3
4
5
6
7
|
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
status_t status;
status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags);
return status;
}
|
上面只列出关键代码,IPCThreadState::self()是线程单例,调用到IPCThreadState的transact方法,并且可以看到第一个参数是获取BpBinder的binderHandle方法,它就是获取服务端的binder句柄,通过它告诉驱动层,想要的服务端binder是哪个,下面来看下IPCThreadState的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
|
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err;
flags |= TF_ACCEPT_FDS;
//往驱动层写数据
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
//如果有error就不往下执行
if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
}
//如果不是one way的请求方式
if ((flags & TF_ONE_WAY) == 0) {
//等待返回结果
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
//如果是one way,传进去的reply是空的
err = waitForResponse(nullptr, nullptr);
}
return err;
}
|
transact逻辑还是挺清晰的,首先往驱动层写数据,如果有error就不往下执行。如果没问题判断是不是one way的请求方式,如果不是则等待返回结果,如果是one way传进入的reply是null。
writeTransactionData是往驱动写数据的方法,看下该方法:
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
|
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;
//判断发送的数据是否有问题
const status_t err = data.errorCheck();
if (err == NO_ERROR) {
//如果没有问题,则往binder_transaction_data中写数据
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);
}
//将BC_TRANSACTION和binder_transaction_data写入到mOut这个parcel里面
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
|
首先定义binder_transaction_data数据结构,然后判断发送的数据是否有问题,如果没有则将data相关的数据给到binder_transaction_data,如果有问题,则返回失败,最后将BC_TRANSACTION和binder_transaction_data写入到mOut这个parcel里面。
上面通过data.errorCheck()来判断发送的数据是否有问题,下面来看下如何验证的:
1
2
3
4
|
status_t Parcel::errorCheck() const
{
return mError;
}
|
直接返回mError字段,它是在Parcel::continueWrite()方法中赋值的,而continueWrite()方法是在growData()->writeInplace()->android_os_Parcel.cpp.android_os_Parcel_write***()方法,最终是java层的Parcel.write***()等方法调用的,关于java层的parcel是如何通过jni调用到android_os_Parcel.cpp主要是因为java层parcel存储了native的parcel指针,它是mNativePtr。
其中关于最大parcel的内存值判断在growData方法中,其中变量SIZE_MAX是64位机器上最大的byte数。如果超过这个值,则返回NO_MEMORY,在continueWrite中会继续判断binder总内存,关于最大内存申请在ProcessState.cpp中调用mmap内存映射的时候,指定了binder的最大内存位BINDER_VM_SIZE = ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)。
回到上面的IPCThreadState::transact,写完数据后如果发现有问题,则通过android_util_Binder.cpp中的signalExceptionForError抛出异常。接着就是判断如果不是one way的请求方式,则通过waitForResponse等待返回结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult){
uint32_t cmd;
while (1) {
//往驱动层写东西
talkWithDriver();
cmd = (uint32_t)mIn.readInt32();
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
break;
case BR_REPLY:{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
reply->ipcSetDataReference(tr.data.ptr.buffer,tr.data_size);
}
goto finish;
}
}
return err;
}
|
通过while循环来判断命令,首先每次先通过talkWithDriver往驱动层写东西:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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;
}
ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr);
return err;
}
|
前面在分析writeTransactionData时候,会把binder_transaction_data数据结构写到oOut这个parcel里面,此处又把mOut中的数据给读到放到binder_write_read数据结构中,如果要读的话,通过mIn这个parcel读取,然后放到binder_write_read数据结构中。最后通过ioctl方法将binder_write_read发送到驱动层。关于ioctl是驱动层的方法,在linux内核代码中。
继续回到上面的waitForResponse方法在BR_REPLY指令中会从mIn这个parcel中读取到数据,然后放到binder_transaction_data数据结构中,这个跟前面写入到mOut中是一样的数据结构,最后将binder_transaction_data中的输入放到reply这个parcel中,最终客户端也就收到了服务端的数据。
在上面分析IPCThreadState::transact中如果是one way的请求方式,则调用waitForResponse时候传进入的reply和acquireResult都是null。而在waitForResponse中如果reply和acquireResult为null的时候,如果是BR_TRANSACTION_COMPLETE则直接goto finish,在one way中不会收到BR_REPLY指令。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult){
uint32_t cmd;
while (1) {
//往驱动层写东西
talkWithDriver();
cmd = (uint32_t)mIn.readInt32();
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
}
}
return err;
}
|
异步消息时序图:
同步消息时序图:

上面就是整个客户端到驱动层的调用流程,客户端到驱动层的流程图如下:

服务端到驱动层
服务端如何跟驱动层通信,得从zygote初始化的时候说起,在该阶段会启动binder机制,启动过程的最后会开启loop循环,通过调用PoolThread::threadLoop方法,源码地址:/frameworks/native/libs/binder/ProcessState.cpp
1
2
3
4
5
6
7
8
9
|
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
|
server端主要通过binder线程,这个binder线程其实就是new了一个普通的线程,然后再调用了IPCThreadState::self()->joinThreadPool(mIsMain)折行代码,把这个线程注册到binder驱动,这样他就成为一个binder线程了,接着来看下IPCThreadState的joinThreadPool方法:
1
2
3
4
5
6
7
8
9
10
11
|
void IPCThreadState::joinThreadPool(bool isMain)
{
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
status_t result;
do {
result = getAndExecuteCommand();
} while (result != -ECONNREFUSED && result != -EBADF);
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
|
这里省略了其它无关的代码,先是往mOut里面写了一个BC_ENTER_LOOPER或者BC_REGISTER_LOOPER,BC_ENTER_LOOPER表示这个线程是自己主动注册到binder驱动的,BC_REGISTER_LOOPER表示是被动的,由binder先申请,然后由应用来注册。注册成功之后,他在一个while循环里面不停地执行getAndExecuteCommand方法,不停地去取指令、处理指令,这个while循环一般是不会退出的,除非是遇到了什么错误。
我们接着看getAndExecuteCommand的实现,方法位于/frameworks/native/libs/binder/IPCThreadState.cpp中:
1
2
3
4
5
6
7
8
9
10
11
|
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver();
cmd = mIn.readInt32();
result = executeCommand(cmd);
return result;
}
|
通过talkWithDriver从驱动读取请求,这个在前面讲过,主要是通过binder_write_read的数据结构和驱动读和写数据。再就是executeCommand处理这个请求,在处理请求之前要先从mIn里面把指令读出来,然后根据这个指令来执行不同的操作。
接着看下IPCThreadState::executeCommand方法,位于/frameworks/native/libs/binder/IPCThreadState.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
|
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
case BR_TRANSACTION:
{
binder_transaction_data& tr;
result = mIn.read(&tr, sizeof(tr));
Parcel buffer;
buffer.ipcSetDataReference(...);
Parcel reply;
reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags);
sendReply(reply, (tr.flags & kForwardReplyFlags));
break;
}
return result;
}
|
这里根据不同的cmd走到不同的case里面,我们主要关注BR_TRANSACTION这个case,它的意思是说Client把请求发给驱动,驱动再把请求转发给Server端,转发给Server端的时候呢Server端的Binder线程就会收到这个指令BR_TRANSACTION。
收到指令后,首先把数据从mIn里面读出来,放到binder_transaction_data里面,接着准备两个Parcel,一个buffer一个reply,buffer是要传递给Server端上层的,reply就是上层要回复给Client端的。
binder_transaction_data里面有个cookie字段,保存的是Binder实体对象,因为这里是native层,所以cookie就是Binder实体对象在native层的对象,也就是BBinder,获取这个Binder对象。
接着调用BBinder的transact方法, 把这个请求往上传,往Server端的上层去传。我们看下transact方法的参数,第一个是code,第二是buffer,也就是参数,第三个是reply回复的参数,第四个是flags。
上层处理完之后就调用sendReply,把这个回复的reply发出去。来看下sendReply实现:
1
2
3
4
5
6
7
|
status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
{
status_t err;
status_t statusBuffer;
err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
return waitForResponse(nullptr, nullptr);
}
|
sendReply的实现中,先调用writeTransactionData方法,把数据写到驱动里面,驱动再转发给Client端,我们需要注意下这里的协议是BC_REPLY;接着调用waitForResponse方法,方法的两个入参都是NULL,跟oneway有点像,表示不用等待对方回复了。
上面executeCommand中通过BBinder的transact调用服务端的上层,它位于/frameworks/native/libs/binder/Binder.cpp:
1
2
3
4
5
6
7
8
9
10
11
|
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
status_t err = NO_ERROR;
switch (code) {
default:
err = onTransact(code, data, reply, flags);
break;
}
return err;
}
|
在transact中根据不同的code执行不同的指令,这里走的是default分支,调用的是onTransact方法,BBinder的实际对象是JavaBBinder对象,继续看JavaBBinder::onTransact,源码位于/frameworks/base/core/jni/android_util_Binder.cpp:
1
2
3
4
5
6
7
8
|
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;
}
|
javavm_to_jnienv方法是根据java的VM拿到当前线程的jni Environment,当前线程是在binder线程池中,拿到之后就可以发起jni调用了。接着发起jni调用,调用了Binder对象的execTransact函数,execTransact函数的源码位于/frameworks/base/core/java/android/os/Binder.java中,在它里面调用了Binder对象的onTransact函数。
在上面的gBinderOffsets.mExecTransact
对应了Binder对象的execTransact方法,它是在frameworks/base/core/jni/android_util_Binder.cpp#int_register_android_os_Binder方法中注册的:
1
2
3
4
5
6
7
8
9
10
11
12
|
const char* const kBinderPathName = "android/os/Binder";
static int int_register_android_os_Binder(JNIEnv* env)
{
jclass clazz = FindClassOrDie(env, kBinderPathName);
gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
return RegisterMethodsOrDie(
env, kBinderPathName,
gBinderMethods, NELEM(gBinderMethods));
}
|
而我们服务端的binder对象正是aidl生成的Stub内部类,比如在启动activity过程中,实际就是IActivityTaskManager.aidl通过aidl工具编译成的内部类stub,而frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java它是继承自IActivityManager.Stub,所以最终是调用了ActivityManagerService的onTransact方法。
总结
-
one way请求方式
分析完整个流程后,我们再来看下one way
请求方式,在上面客户端到驱动层请求过程中,在IPCThreadState::transact
方法中,会通过flags参数判断是不是one way
请求方式,/如果是one way
,给waitForResponse方法传进去的reply和acquireResult参数都是空,在该方法里面如果收到了BR_TRANSACTION_COMPLETE的时候,也就是驱动层收到了客户端的binder请求,然后给到服务端的回执,在这里面如果reply和acquireResult参数为空,直接退出了waitForResponse的while循环,也就是客户端不进行休眠等待服务端的相应。
-
TransactionTooLargeException问题
再来看开篇讲到的parcel中数据量大的问题,IPCThreadState::writeTransactionData方法中先判断data这个parcel的数据量是否有问题,是通过errorCheck来判断,这个错误信息,是在write**
等系列方法中调用continueWrite时候,判断是否超过总大小,这个总大小是在在ProcessState.cpp中调用mmap内存映射的时候,指定了binder的最大内存位BINDER_VM_SIZE = ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)。最终这个error一路返回到android_util_Binder.cpp的android_os_BinderProxy_transact方法方法,在该方法里面会调用signalExceptionForError方法,在该方法里面会通过判断错误码是FAILED_TRANSACTION
,然后通过jni给java层抛出TransactionTooLargeException异常。
-
通信协议

①首先从Client发起一个BC_TRANSACTION,也就是Client向Server端发起一个IPC调用的时候,它首先会向binder驱动写了BC_TRANSACTION指令,binder收到之后会给Client一个回执,也就是BR_TRANSACTION_COMPLETE。
②回执发完了之后,binder驱动再把这个请求转发给Server端,通过BR_TRANSACTION指令。
③Server端收到BR_TRANSACTION指令之后去处理这个请求,处理完之后会回复binder驱动,通过BC_REPLY指令。
④驱动收到Server端的回复之后,也会给Server端一个回执,就是BR_TRANSACTION_COMPLETE指令。
⑤最后binder驱动再把返回结果转发给Client端,通过BR_REPLY指令。
⑥需要注意的是,Client在发出请求之后,在等待Server端回复的过程中,Client处于休眠状态。另外Server端应该是Binder线程,Binder线程在处理请求之外的时间也是处于休眠状态的,等着binder驱动发过来的请求。
最后来一张别人总结的binder分层架构图:
