当前位置: 移动技术网 > 移动技术>移动开发>Android > Binder在Native的实现

Binder在Native的实现

2020年07月17日  | 移动技术网移动技术  | 我要评论
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的关系。
这里定义了一个接口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的设计与实现)
 
上面简单描述了从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通信。

server与client和servicemanager通信或者是client和普通server通信都是通过BpBinder实现的,下图是BpBinder与servermanager通信的过程。
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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网