在文章开始前,我必须把我参照的这篇文章先贴出来: Android Bander设计与实现 - 设计篇【1】(是的,作者标题里的Binder还写错了😂。这里标注一下,后面篇幅中提到【1】就指这篇文章。)
必须说一下,这是我看过的目前为止,讲Binder通信最为透彻的一篇。文章通篇没有涉及具体代码的讲解,作者基于Binder源码做了高度抽象,但又没完全脱离代码层面通篇理论。当然,这也不是说这篇文章通俗易懂,如果想要理解细节,则必须有一些积累(Linux进程的虚拟内存,Linux一些系统调用函数 ioctl, mmap等)。作为学习者而言,脱离了具体的代码,只看理论,则怎样都不能说凭借这篇就想完全理清Binder脉络,勿论掌握。所以,这里还推荐Binder系列博客gityuan.com/2015/10/31/…,结合着来看,对弄懂Binder通信有着极大作用。
所以,在读过这些文章后,我觉得有必要把一些要点或者自认为重要的点整理出来。这样,往后再回过头来看时,说不定会有不一样的收获。
1 C/S结构
整个Binder通信机制被设计成Client/Server结构。Android系统将大量的核心功能放在不同的Service组件中实现,视为Server端。通过提供相关接口为Client端使用Server端提供的功能。通常,把Service组件所在的进程称为Server进程,把使用Service组件的进程称为Client进程。
2 关于Binder通信模型
通信模型这个词,是引自【1】,这个词听上去好像存在着一个官方标准或者规范的东西。但如果去Android官方文档去查,好像也不存在这样的一个词汇(我还在继续查资料),在我看过的一些Frameworks的书中也没见过这个词。暂且认为是【1】作者对Binder机制做的一个概念总结吧。
3 Binder通信机制建立
servicemanager可以说是Binder模型中一个特殊的存在,它本身就是一个service,只是要先于其他系统service启动。在Binder机制中,它同样作为一个server,为其他server进程提供功能,具体的就是系统服务注册、服务获取。这里存在一个悖论:servicemanager用来实现C/S结构的Binder通信机制,可是实现过程中还要使用C/S结构的Binder通信机制,这个要怎么处理?Android实现起来也是朴实无华,server进程中servicemanager的binder引用固定为0,也就是说,一个server(在servicemanager看来是client)若要向servicemanager注册自己,就通过0这个引用号,相当于获取了servicemanger的Binder引用,这样就解决了和servicemanager通信问题。servicemanager程序入口为service_manager.c,看一下main函数,
int main(int argc, char** argv)
{
struct binder_state *bs;
char *driver;
if (argc > 1) {
driver = argv[1];
} else {
driver = "/dev/binder";
}
//打开Binder字符设备
bs = binder_open(driver, 128*1024);
...
//当前进程变为 service manager
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
...
//进入循环,准备接收
binder_loop(bs, svcmgr_handler);
return 0;
}
service_manager main函数做了三件事: ① binder_open,打开binder设备; ② binder_become_context_manager,当前进程注册为上下文管理者,变为service manager进程; ③ binder_loop 开启无限循环,等待处理IPC请求消息;
3.1 binder_open
struct binder_state *binder_open(const char* driver, size_t mapsize)
{
struct binder_state *bs;
struct binder_version vers;
bs = malloc(sizeof(*bs));
if (!bs) {
errno = ENOMEM;
return NULL;
}
//打开binder字符设备
bs->fd = open(driver, O_RDWR | O_CLOEXEC);
if (bs->fd < 0) {
fprintf(stderr,"binder: cannot open %s (%s)\n",
driver, strerror(errno));
goto fail_open;
}
//Binder信息的检查
if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
(vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
fprintf(stderr,
"binder: kernel driver version (%d) differs from user space version (%d)\n",
vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
goto fail_open;
}
bs->mapsize = mapsize;//mapsize = 128 * 1024
//内核中开辟出一块128K大小的缓冲区,用来存放Binder通信的数据,并建立缓冲区与binder设备的一一映射
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
if (bs->mapped == MAP_FAILED) {
fprintf(stderr,"binder: cannot map device (%s)\n",
strerror(errno));
goto fail_map;
}
return bs;
fail_map:
close(bs->fd);
fail_open:
free(bs);
return NULL;
}
binder_open主要工作可以分为三部分: ① 创建binder_state结构体类型的bs,分配内存; ② open系统调用打开binder字符设备; ③ 在内核中开辟出一块128K大小的缓冲区,建立缓冲区与binder设备的映射。 binder_open中有对Binder信息的检查,使用的是ioctl函数,这里援引【1】的一段话,对Server、Client进程同binder驱动交互方式做一些说明:
驱动和应用程序之间定义了一套接口协议,主要功能由ioctl()接口实现,不提供read(),write()接口,因为ioctl()灵活方便,且能够一次调用实现先写后读以满足同步交互
3.2 binder_become_context_manager
int binder_become_context_manager(struct binder_state *bs)
{
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
在3.1中,对ioctl函数的使用进行了说明,所以binder_become_context_manager是当前进程向binder驱动发送形式“命令+参数”的数据,BINDER_SET_CONTEXT_MGR命令生效后,当前进程就摇身一变成为servicermanager进程。
3.2.1 binder_ioctl
ioctl函数经过系统调用,对应于Binder驱动层的binder_ioctl函数。
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {
binder_lock(__func__);
switch (cmd) {
case BINDER_WRITE_READ:
case BINDER_SET_MAX_THREADS:
case BINDER_THREAD_EXIT:
case BINDER_VERSION:
...
case BINDER_SET_CONTEXT_MGR:
ret = binder_ioctl_set_ctx_mgr(filp);
break;
}
...
}
binder_unlock(__func__);
}
进入BINDER_SET_CONTEXT_MGR分支,再看binder_ioctl_set_ctx_mgr(filp);
static int binder_ioctl_set_ctx_mgr(struct file *filp)
{
int ret = 0;
struct binder_proc *proc = filp->private_data;
kuid_t curr_euid = current_euid();
//根据错误信息知道,BINDER_SET_CONTEXT_MGR命令只需设置一次,
//也就是binder_context_mgr_node只需创建一次
if (binder_context_mgr_node != NULL) {
pr_err("BINDER_SET_CONTEXT_MGR already set\n");
ret = -EBUSY;
goto out;
}
if (uid_valid(binder_context_mgr_uid)) {
...
} else {
binder_context_mgr_uid = curr_euid;
}
//创建ServiceManager在binder驱动中对应的实体节点
binder_context_mgr_node = binder_new_node(proc, 0, 0);
if (binder_context_mgr_node == NULL) {
ret = -ENOMEM;
goto out;
}
binder_context_mgr_node->local_weak_refs++;
binder_context_mgr_node->local_strong_refs++;
binder_context_mgr_node->has_strong_ref = 1;
binder_context_mgr_node->has_weak_ref = 1;
out:
return ret;
}
创建struct binder_node类型的binder_context_mgr_node,并将binder_context_mgr_node的强弱引用各加1。
再回头看binder_ioctl函数,其可以处理的命令还有BINDER_WRITE_READ、BINDER_SET_MAX_THREADS、BINDER_THREAD_EXIT、BINDER_VERSION。这些命令是Binder协议的一部分。除了BINDER_VERSION命令在3.1小节binder_open函数见过,其余的在接下来内容中也会接触到。
3.3 binder_loop
servicemanager本身是一个可以处理client进程请求的server进程。为了应对来自client进程的请求,servicemanager会进入一个无限循环等待处理client进程的IPC请求。
void binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
//创建binder_write_read
struct binder_write_read bwr;
uint32_t readbuf[32];
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
//发送BC_ENTER_LOOPER命令给binder驱动
readbuf[0] = BC_ENTER_LOOPER;
binder_write(bs, readbuf, sizeof(uint32_t));
//进入无限循环,等待处理IPC读写请求
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
if (res == 0) {
ALOGE("binder_loop: unexpected reply?!\n");
break;
}
if (res < 0) {
ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
break;
}
}
}
这里,我们看一下结构体binder_write_read
struct binder_write_read {
signed long write_size;
signed long write_consumed;
unsigned long write_buffer;
signed long read_size;
signed long read_consumed;
unsigned long read_buffer;
};
binder_write_read是应用程序与Binder驱动交互直接使用的数据包。参数分为两段:写部分和读部分。如果write_size不为0,就先将write_buffer里的数据写入Binder;如果read_size不为0,从Binder中读取数据存入read_buffer中。write_consumed和read_consumed表示操作完成时Binder驱动实际写入或读取的数据个数。
3.3.1 binder_write
int binder_write(struct binder_state *bs, void *data, size_t len) {
struct binder_write_read bwr;
int res;
bwr.write_size = len;
bwr.write_consumed = 0;
//写入的data为BC_ENTER_LOOPER
bwr.write_buffer = (uintptr_t) data;
bwr.read_size = 0;
bwr.read_consumed = 0;
bwr.read_buffer = 0;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
return res;
}
binder_write函数比较简单,填充binder_write_read变量后,向binder驱动发送BC_ENTER_LOOPER命令。回看3.2.1小节,binder_ioctl函数中BINDER_WRITE_READ分支,调用binder_ioctl_write_read
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
...
}
3.3.2 binder_ioctl_write_read
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
int ret = 0;
//当前情形下,binder_proc表示smgr进程
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;
}
//从用户空间拷贝数据到内核缓冲区 ubuf表示数据
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
...
//bwr.write_size大于0表示向内核缓冲区写入数据
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
//bwr.read_size大于0表示从内核缓冲区读取数据
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
trace_binder_read_done(ret);
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
...
// 从内核缓冲区拷贝数据到用户空间,ubuf表示数据
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}
根据3.3.1可知,bwr.write_size > 0,执行binder_thread_write函数。
3.3.3 binder_thread_write
static int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed) {
uint32_t cmd;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {
//获取具体的命令
get_user(cmd, (uint32_t __user *)ptr);
...
switch (cmd) {
case BC_ENTER_LOOPER:
//设置该线程的looper状态
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
break;
...
}
}
}
binder_thread_write函数,会进入BC_ENTER_LOOPER分支,thread是在binder_ioctl函数中通过如下方式获得的,
//thread为servicemanager所在线程
thread = binder_get_thread(proc);
进入该分支,servicemanager所在线程的looper标记设置为BINDER_LOOPER_STATE_ENTERED,表示该线程进入循环状态,即servicemanager马上要进入binder_looper的无限循环开始处理IPC请求。binder_thread_write函数执行完,最终返回到3.3小节部分,binder_loop函数中继续执行,进入无限for循环中,开始等待IPC请求。
先不去管无限for循环中逻辑,该函数截至至此,Binder通道已经打通,可以在server进程和client进程之间进行自由通信了。当然binder_loop方法还没完,binder_parse的细节,后续篇幅会深入。
4 特殊的Service——ServiceManager
Binder通道建好后,是不是就能进行数据通信了?是的,但是还要提一个重要的概念:ServiceManager。ServiceManager在系统服务注册(client为server进程)、获取(client为client进程)的过程中充当着server的角色。所以,这一节重点讲一下ServiceManager。获取Service Manager是通过defaultServiceManager()方法来完成。
4.1 defaultServiceManager
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
逐级深入,
4.2 ProcessState::self
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != nullptr) {
return gProcess;
}
gProcess = new ProcessState(kDefaultDriver);
return gProcess;
}
函数逻辑较简单,直接看ProcessState的构造函数
4.2.1 ProcssState构造函数
ProcessState::ProcessState(const char *driver)
: mDriverName(String8(driver))
//在初始化列表中打开binder驱动
, mDriverFD(open_driver(driver))
, mVMStart(MAP_FAILED)
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
, mExecutingThreadsCount(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
, mStarvationStartTimeMs(0)
, mBinderContextCheckFunc(nullptr)
, mBinderContextUserData(nullptr)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
, mCallRestriction(CallRestriction::NONE)
{
if (mDriverFD >= 0) {
// mmap the binder, providing a chunk of virtual address space to receive transactions.
// 采用内存映射函数mmap,给binder分配一块虚拟地址空间,用来接收事务
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
...
}
...
}
4.2.2 open_driver
static int open_driver(const char *driver)
{
int fd = open(driver, O_RDWR | O_CLOEXEC);
if (fd >= 0) {
int vers = 0;
//获取binder版本信息
status_t result = ioctl(fd, BINDER_VERSION, &vers);
...
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
...
}
}
return fd;
}
open_driver函数调用ioctl函数向驱动获取binder版本信息,同时检查binder协议的版本信息。之后,open_driver会设置binder进程可以支持的最大线程数。看一下binder_ioctl函数中BINDER_SET_MAX_THREADS分支的逻辑,
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
...
case BINDER_SET_MAX_THREADS:
//设置binder进程支持的最大线程数量,值为DEFAULT_MAX_BINDER_THREADS
if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
ret = -EINVAL;
goto err;
}
break;
...
}
4.3 ProcessState::getContextObject
ProcessState::self之后,接着来看ProcessState::getContextObject会做什么,
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
sp<IBinder> context = getStrongProxyForHandle(0);
...
return context;
}
4.3.1 getStrongProxyForHandle
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
//从一个维护handle_entry类型的全局集合中返回handle值对应的handle_entry指针
handle_entry* e = lookupHandleLocked(handle);
if (e != nullptr) {
// We need to create a new BpBinder if there isn't currently one, OR we
// are unable to acquire a weak reference on this current one.
IBinder* b = e->binder;
//如果该handle_entry的binder指针为空指针 或者 无法获取当前binder弱引用
if (b == nullptr || !e->refs->attemptIncWeak(this)) {
//当前传入的handle == 0
if (handle == 0) {
// Special case for context manager...
Parcel data;
//确保context manager是否已经被注册,
//即前面的BINDER_SET_CONTEXT_MGR命令已发送到binder驱动且生效
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, nullptr, 0);
if (status == DEAD_OBJECT)
return nullptr;
}
//新建一个BpBinder对象
b = BpBinder::create(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
该函数的主要工作已在代码中做了注释。还是逐级查看,
4.3.2 lookupHandleLocked
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
const size_t N=mHandleToObject.size();
if (N <= (size_t)handle) {
handle_entry e;
e.binder = nullptr;
e.refs = nullptr;
status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
if (err < NO_ERROR) return nullptr;
}
return &mHandleToObject.editItemAt(handle);
}
mHandleToObject是一个元素类型为handle_entry的容器,handle_entry是一个封装了binder指针的结构体。
struct handle_entry {
IBinder* binder;
RefBase::weakref_type* refs;
};
getContextObject函数调用结果最终返回一个BpBinder的实例对象。
4.4 interface_cast
getContextObject返回BpBinder实例后
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
就相当于
gDefaultServiceManager = interface_cast<IServiceManager>(
new BpBinder(0));
interface_cast方法定义在frameworks/native/include/binder/IInterface.h中,其代码如下,
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj){
return INTERFACE::asInterface(obj);
}
将泛型类型替换为IServiceManager,就变为,
template<typename INTERFACE>
inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj){
return IServiceManager::asInterface(obj);
}
最终相当于
IServiceManager::asInterface(new BpBinder(0));
4.4.1 IServiceManager::asInterface
android::sp<IServiceManager> IServiceManager::asInterface(const android::sp<android::IBinder>& obj)
{
android::sp<IServiceManager> intr;
if(obj != NULL) {
intr = static_cast<IServiceManager *>(
obj->queryLocalInterface(IServiceManager::descriptor).get());
if (intr == NULL) {
intr = new BpServiceManager(obj);
}
}
return intr;
}
该函数逻辑比较简单,其实直接返回的是BpServiceManager实例对象。
最后,defaultServiceManager返回的是BpServiceManager实例对象。这里我们再接着看一下BpServiceManager的构造函数。
4.4.2 BpServiceManager构造函数
explicit BpServiceManager(const sp<IBinder>& impl)
: BpInterface<IServiceManager>(impl)
{ }
注意到,BpServiceManager构造函数是一个空函数,沿着继承结构看BpInterface的构造函数,
template<typename INTERFACE>
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
: BpRefBase(remote)
{
}
依然不见IBinder指针类型的参数赋值,接着看BpRefBase的构造函数
BpRefBase::BpRefBase(const sp<IBinder>& o)
: mRemote(o.get()), mRefs(nullptr), mState(0)
{
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
if (mRemote) {
mRemote->incStrong(this); // Removed on first IncStrong().
mRefs = mRemote->createWeak(this); // Held for our entire lifetime.
}
}
这里,BpBinder的实例对象赋给IBinder指针类型的mRemote变量。
5 后记
在Binder通道建立以及获得ServiceManager之后,应该说,基于Binder通信的通道已经完全打通,为后续的系统服务注册、系统服务获取做好了准备。到这里,【1】中提到的Binder通信模型中的Binder驱动、servicemanager我们都已经接触到了。下篇聚焦系统服务注册与获取,就会涉及到server、client。
参考资料
aosp.tuna.tsinghua.edu.cn/platform/fr… clone)
《Android的设计与实现 卷一》杨云君。
《深入理解Android 卷一》邓凡平。