作者:随随便便不随便 链接:https://www.jianshu.com/p/6ac715e2e81f
背景
Android官方介绍以及很多文章都讲到Binder的数据一次拷贝,Binder的数据一次拷贝到底是怎么回事呢?一次的数据拷贝真的对性能有很大改善吗?带着这个疑问,分析Binder驱动以及与Binder驱动通信的IPCThreadState。看看数据在Binder通信双方是怎么传递的。
分析从Binder通信发送端的IPCThreadState的talkWithDriver
开始,到Binder通信接收端的IPCThreadState的talkWithDriver
返回截止。分析transaction
传递过程的数据拷贝量。
分析的源码是Android P(http://androidxref.com/9.0.0_r3/xref/frameworks/native/libs/binder/IPCThreadState.cpp)
以及4.19内核(https://android.googlesource.com/kernel/common/+/refs/heads/android-4.19/drivers/android/binder.c
)
发送端
发送端的数据在进入到talkWithDriver时,已经被封装到名为mOut的Parcel中。talkWithDriver与驱动交换数据需要使用结构体binder_write_read,将mOut
的数据地址赋值给 binder_write_read
的对象bwr,然后将bwr的地址作为参数ioctl的参数传递给binder驱动。
进入binder.c
的binder_ioctl
,然后进入binder_ioctl_write_read
,在binder_ioctl_write_read
中进行了第一次的数据拷贝,目的是获得binder_write_read
的对象bwr,拷贝的数据量为sizeof(binder_write_read)。
static int binder_ioctl_write_read(struct file *filp,unsigned int cmd, unsigned long arg,
struct binder_thread *thread){
int ret = 0;
struct binder_proc *proc = filp->private_data;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {
ret = -EINVAL;
goto out;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
...
}
接着,进入binder_thread_write函数。此时传入binder_thread_write的数据地址是 bwr.write_buffer,即mOut.data()。在binder_thread_write中会循环解析bwr.write_buffer中的数据,为了便于分析,假设IPCThreadState只传递了一个CMD及数据。那么在binder_thread_write中首先拷贝一次cmd,大小为sizefo(uint32_t)。
while (ptr return_error.cmd == BR_OK) {
int ret;
if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
trace_binder_command(cmd);
...
}
再接着,进入CMD为BC_TRANSACTION的处理流程:
case BC_TRANSACTION: