Android Binder IPC

来源:互联网 发布:ubuntu登陆循环nvidia 编辑:程序博客网 时间:2024/05/29 03:27

android进程和linux进程一样,他们只运行在进程固有的虚拟地址空间中。一个4G的虚拟地址空间,3G是用户空间,1G是内核空间(通过内核设定可以修改)。用户代码和相关库分别运行在用户空间的代码区域,数据区域以及堆栈区域中,而内核空间中运行的代码则运行在内核空间的各个区域,并且进程具有各自独立的地址空间,单独运行。

一个具有独立地址空间的进程向另一个进程传递数据是通过共享的内核空间。从内核的角度来看,进程只不过是一个作业单位,虽然各个进程的用户空间是独立的,但是运行在内核空间中的任务数据和代码是彼此共享的。

linux本身就提供相应的IPC通讯手段,用于两个进程通过内核空间来进行通信。android的Binder是更高级的,功能更加强大。在IPC的基础上实现便捷的RPC。Binder使用运行在内核空间的抽象驱动程序Binder(IPC)Driver:

Binder调用的模式为:


IPC数据由:待调用服务号,待调的函数名,Binder协议构成。服务号是各个服务的ID。下图表明IPC数据对应的关系:


应用程序在通过Binder尝试RPC操作时,会进行open()系统调用(实际传递给__open()调用),获取Binder Drver的文件描述符,而后,通过mmap()系统调用,在内核中开辟一块区域,以便存放接受的IPC数据。最后调用ioct1()函数,将IPC数据作为参数,传递给Binder Driver。

ioct1()函数形式:ioct1(文件描述符,ioct1命令,数据类型)

文件描述符是open()函数打开Binder Driver时返回值,ioct1命令和数据类型对应如下表:

命令

含义

arg

BINDER_WRITE_READ

该命令向Binder写入或读取数据。参数分为两段:写部分和读部分。如果write_size不为0就先将write_buffer里的数据写入Binder;如果read_size不为0再从Binder中读取数据存入read_buffer中。write_consumed和read_consumed表示操作完成时Binder驱动实际写入或读出的数据个数。

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_SET_MAX_THREADS

该命令告知Binder驱动接收方(通常是Server端)线程池中最大的线程数。由于Client是并发向Server端发送请求的,Server端必须开辟线程池为这些并发请求提供服务。告知驱动线程池的最大值是为了让驱动在线程达到该值时不要再命令接收端启动新的线程。

int max_threads;

BINDER_SET_CONTEXT_MGR

将当前进程注册为SMgr系统中同时只能存在一个SMgr。只要当前的SMgr没有调用close()关闭Binder驱动就不能有别的进程可以成为SMgr。

int

BINDER_THREAD_EXIT

通知Binder驱动当前线程退出了。Binder会为所有参与Binder通信的线程(包括Server线程池中的线程和Client发出请求的线程)建立相应的数据结构。这些线程在退出时必须通知驱动释放相应的数据结构。

int

BINDER_VERSION

获得Binder驱动的版本号。

Struct binder_version

主要考虑BINDER_WRITE_READ命令来传递数据。

以上结果就可以抽象出一个Binder IPC通信的层次结构:


通过该结构模型,以Binder Driver作为代理人,转移数据给server,实现RPC。

在client到Binder Driver或者Binder Driver到server传递数据的过程中,封装的IPC数据有一内容就为:Binder Protocol;该协议简单根据来源和接受者分为两类:即cilent 到Driver的BINDER COMMAND PROTOCOL和driver 到 server的BINDER RETURN PROTOCOL。对应两种协议:BC_TRANSACTION和BR_TRANSACTION.