前言
谈到到Binder相对于其他传统进程间通信方式的优点的时候,我们总会说Binder只需要做“一次拷贝”就行了,而其他传统方式需要“两次拷贝”。这确实是Binder的优点,但再进一步思考就会碰到两个问题:
这所谓的“一次拷贝”到底是发生在什么地方?
拷贝的到底是什么东西?
而很多介绍Binder的文章会列出“一次拷贝”是其优点,但对上面的两个问题要么一笔带过,要么就是回答的并不完全正确,造成一些理解上的混乱。
本篇文章意在探索这两个问题的正确答案,所以需要读者对Binder驱动的工作过程和Binder驱动源码有一个大致的了解。
那么接下来就让我们带着这两个问题去源码的世界一探究竟。
源码
在看源码之前,我们需要先理一理一些关于Binder的预备知识。
- Binder的mmap发生在ProcessState的构造函数中,也就是一个进程就这么一块内存映射,大小大概是1M左右。
- 内核空间读写用户空间的数据是通过以下两个函数完成的:
- copy_from_user() 将数据从用户空间拷贝到内核空间。
- copy_to_user() 将数据从内核空间拷贝到用户空间。
- Binder驱动源码中有很多地方都会出现这两个函数的调用。我们需要搞清楚每次调用都是在拷贝些什么东西,拷贝到哪里去了。
- 为了抓住本文的“一次拷贝”这个点,下面源码引用会尽量集中在和内存操作相关的代码而暂时略过其他代码。
下面我们就先从内存映射说起
Binder内存映射
ProcessState构造函数
ProcessState::ProcessState(const char *driver)
{
if (mDriverFD >= 0) {
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
}
}
注意mmap上方的注释,已经说的很清楚了,这块内存映射只是作为接收transactions来使用的,也就是说往驱动写数据的时候是与内存映射无关的。记住这一点。
下面我们看一下内核空间相应的调用:
binder_mmap
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
...
ret = binder_alloc_mmap_handler(&proc->alloc, vma);
...
}
真正的映射操作由函数binder_alloc_mmap_handler()完成。这里我们只需要记住这个函数的第一个入参&proc->alloc。通过这个结构体我们就能找到映射好的内存块。
内存映射完成之后,就让我们看一下Binder的传输过程中哪里使用到了这块特殊的内存。
Binder传输过程
传输过程我们只关注内存和数据。
发起方用户空间
发起方用户空间做的事情其实就像发快递一样不停的打包,注意一下都包了些啥。
IPCThreadState::writeTransactionData
// 我们要传输的数据在data这个入参中
status_t IPCThreadState::writeTransactionData(... const Parcel& data...)
{
binder_transaction_data tr;
...
//tr.data.ptr.buffer保存了指向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();
...
// 将tr写入mOut。
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
这里tr只保存了指向数据的指针。然后tr被写入mOut这个

本文详细探讨了Android中Binder通信的一次拷贝优化,解释了这个拷贝发生在何处,涉及哪些数据。文章从Binder的内存映射开始,逐步剖析从发起方用户空间到接收方内核空间,再到接收方用户空间的数据传输过程,明确了一次拷贝的关键点在于将数据从发起方用户空间直接拷贝到接收方内核的内存映射区域,从而减少了数据拷贝的次数,提高了效率。
最低0.47元/天 解锁文章
741

被折叠的 条评论
为什么被折叠?



