欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Binder在Native的实现

程序员文章站 2022-07-01 16:18:36
android中的跨进程通信(ipc)用的是C/S体系系统,Binder为这个体系系统提供IPC通信能力。在android的C/S体系中增加了一个组件servicemanager,提供注册和检索Service的功能。Service在启动过程中将自身信息注册到servicemanager,servicemanager中维护了一个Service信息的列表,Client在使用服务时,可以通过名字像servermanager获取对应Service信息。servicemanager由init启动的进程,本身也是个...
android中的跨进程通信(ipc)用的是C/S体系系统,Binder为这个体系系统提供IPC通信能力。
在android的C/S体系中增加了一个组件servicemanager,提供注册和检索Service的功能。Service在启动过程中将自身信息注册到servicemanager,servicemanager中维护了一个Service信息的列表,Client在使用服务时,可以通过名字像servermanager获取对应Service信息。servicemanager由init启动的进程,本身也是个Server。
 
启动servicemanager
 
servicemanager是在init.rc中配置的系统Service,在系统启动的过程中先于其他服务启动,servicemanager启动过程分为三步:
1.初始化BInder通信环境,打开BInder设备映射共享内存。
打开本地Binder设备文件,可以访问Binder驱动程序,将设备文件映射到当前进程虚拟地址空间。
2.将自身注册为上下文管理者(context manager)
servicemanager向Binder驱动程序发送指令,将自身注册为Binder通信的上下文管理者binder_context_mgr_node,这里会建立一个索引值为0的全局节点Binder node,将0节点存入全局变量binder_context_mgr_node。
3.进入无限循环中等待接收并处理IPC通信请求。
servicemanager本身就是一个Servier,可以相应Service组件注册服务的请求和Client组件使用服务的请求。当Service组件向servicemanager注册服务时,对于servicemanager来讲Service进程也是一个Client。
这里会先将当前线程的looper标记设置为BINDER_LOOPER_STATE_ENTERED,表示当前线程进入Binder Looper状态,然后进入无限循环。
如果有Client要使用servicemanager,向Binder驱动中写入数据,在servicemanager的循环中,会读取Binder驱动中的IPC请求数据,并做相应的处理,这里会接到两种操作,do_find-service和do_add_service,对应Client端的getService和addService方法。
addService是需要权限的,除了root和system用户外,还有个uid白名单,通过UID限制了可注册服务的Server,如果是系统开发者可以通过添加白名单的方式添加自定义Server。
 
Server的启动和注册
 
servicemanager作为一个Server提供了add和get服务的方法,其他的普通Server需要以Client的身份调用servicemanager的addService方法来注册自身。一个Server在启动的过程中会将自身注册到servicemanager中,一个Server的启动过程分四步:
1.创建ProcessState对象。
每个进程只有一个ProcessState对象,先创建一个ProcessState对象,存入全局变量中。在创建ProcessState时,会打开Binder设备文件,将Binder设备映射到进程空间,这点与servicemanager很类似,servicemanager除外的其他Server和servicemanager利用Binder设备文件通过共享内存来通信。
2.获取servicemanager的代理对象。
这个图简单的说明了BpBinder和IServiceManager的关系。
Binder在Native的实现
这里定义了一个接口IServiceManager,IServiceManager定义了getService,addService等几个方法。获取servicemanager会获得一个IServiceManager,BpInterface继承了BpRefBase和IServiceManager,BpServiceManager继承了BpInterface,获取到的IServiceManager是一个BpServiceManager实例,BpRefBase中有个mRemote,就是BpBinder,BpServiceManager实现的方法实际是调用BpBinder实现的。BpBInder通过IPCThreadState持有了ProcessState,就有了和Binder驱动程序通信的能力。
3.注册Service(一个Server可能有多个Service)。
servicemanager的代理对象已经得到了,调用BpServiceManager的addservice方法添加自身,这里把service的相关信息写入Parcel类型data中,调用BpBinder的transact函数,BpBinder的transact函数中调用IPCThreadState的transact函数,最终通过takWithDeriver函数与Binder驱动程序通信,这里会根据handler的值检索请求的目标进程,这里会找到binder_context_mgr_node,Binder驱动程序将Binder数据发送给serviermanager,servicemanager在循环读取Binder发送的数据,读到数据就会根据参数来做对应的处理,这里就是执行注册service。
4.Server进程开启线程池。
最后每个Service会启动一个线程,循环读取Client请求。
 
Client使用服务代理与服务端通信
 
Server在启动过程中已经通过BpBinder(0)与servicemanager进行过通信,Client端也要通过servicemanager获取到service的代理,与Server一样,通过defaultServiceManager函数获得BpServiceManager,调用getService方法,会通过BpBinder(0)将消息发送到servicemanager,servicemanager检索到对应的服务,将服务注册信息存入reply中,发送给Binder,Binder找到具体的服务对象,将服务的引用handler传递回Client,根据handler创建BpBinder,将BpBinder赋值给对应Service的mRemote,就可以通过该接口调用Server的方法,由BpBinder将消息发送到Binder,Binder发送给真正的服务。
这里Client是通过服务的接口跟服务通信,实际是通过服务的代理BpBinder跟Binder通信,再由Binder跟真正的服务进行通信这样一个过程。客户端是通过代理BpBinder跟服务端通信的,Server端有个BBinder跟客户端通信,Server端的IPCThreadState接到BpBinder发来的请求后,调用BBinder的transact进而调用onTransact方法,最终有BnServiceManager的onTransact方法解析并执行客户端传来的操作。
下图简单描述了Client和Server通信的过程(出自Android的设计与实现)
Binder在Native的实现
 
上面简单描述了从servermanager启动,service的启动和注册,到client和server的通信流程。下面进行一些总结。
Client和Server只所以能通信的核心就是它们都可以和Binder驱动,利用Binder作为桥梁进行通信的,下面说一下与Binder通信的具体方式方式。
这里需要借助一个结构体。
struct binder_state{
      int   fd;
      void *mapped;
      unsigned mapsize;
}
struct binder_state *binder_open(unsigned mapsize)
{ 
         struct binder_state *bs;                           //声明构造体
         bs=malloc(sizeof(*bs));                            //开辟内存空间
         bs->fd = open ("/dev/binder"),O_RDWR);             //打开Binder设备文件,赋值给fd
         bs->mapsize = mapsize;                             //给mapzise赋值
         //将进程空间的某个内存区域和内核空间的内存区域建立映射关系,servicemanager进程可以利用该内存区域和其他进程共享数据。
         bs->mapped = mmap(NULL,mapsize,PROT_READ,MAP_PRIVATE,bs-fd,0)
}

这里打开了binder设备文件,建立了内存映射,当前进程可以通过内核缓冲区共享数据。然后通过ioctl系统发送指令给Binder驱动程序,由驱动程序的binder_ioctl函数处理指令。

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)      filp参数传bs->fd,既设备文件,每个进程可以通过这几个操作就获得了与Binder通信的能力。这里就是与Binder的核心。

servicemanager就是直接通过通过ioctl系统与Binder通信。

Binder在Native的实现
server与client和servicemanager通信或者是client和普通server通信都是通过BpBinder实现的,下图是BpBinder与servermanager通信的过程。
Binder在Native的实现
ProcessState是名为gProcess的全局变量,在它的初始化时候进行了open_driver操作,里面打开了binder设备,这样就可以利用ioctl系统和ProcessState与Binder进行通信了。IPCThreadState的talkWithDriver函数里面通过ioctl与Binder通信。
Binder的构造函数里需要传一个handle值,该值就是openBinder设备返回的地址,这样在使用BpBinder与Binder通信的时候,Binder根据handle值就知道将消息发送给哪个Server。在获取servicemanager的时候创建一个BpBinder(0)转化为IServiceManager,在调用IServiceManager的get和add方法的时候通过BpBinder(0)与servicemanager通信。通过BpBinder(0)与servicemanager通信getService会返回一个handle值,通过这个handle值创建对应的BpBinder就可以与对应的Server通信了。

本文地址:https://blog.csdn.net/wjtzc1990/article/details/107374268