Android通信方式篇(六)-Binder机制(Native层(上))

Binder通信采用C/S架构,从组件视角来说,包含Client、Server、ServiceManager以及binder驱动,其中ServiceManager用于管理系统中的各种服务。无论是注册服务和获取服务的过程都需要ServiceManager,需要注意的是此处的Service Manager是指Native层的ServiceManager,framework层的ServiceManager只是对Native层的封装,方便上层调用而已。Binder核心实现是在Native层, 牵扯到的东西比较多,我尽量捋清楚一个大框架出来。

这层打算总结下如下几个流程:

  • ServiceManager的启动
  • ServiceManager的获取
  • Server通过addService向ServiceManager注册服务
  • Client通过getService向ServiceManager获取Server的服务
一、 ServiceManager的启动:

这个过程简单描述就是:ServiceManager告知Binder驱动程序它是Binder机制的上下文管理者,成为Binder驱动的守护进程。

整个启动过程流程如下:

Android通信方式篇(六)-Binder机制(Native层(上))_第1张图片
from gityuan

相关类:

framework/native/cmds/servicemanager/
- service_manager.c
- binder.c

kernel/drivers/ (不同Linux分支路径略有不同)
- staging/android/binder.c
- android/binder.c

通过main入口启动 ServiceManager 的启动是系统在开机时,init 进程解析 init.rc 文件调用 service_manager.c 中的 main() 方法入口启动的。
main()方法中主要做了如下这么几件事:

int main(int argc, char **argv) {
   //1 打开binder驱动,申请128k字节大小的内存空间
   bs = binder_open(128*1024);
   ...
   //2 成为上下文管理者
   if (binder_become_context_manager(bs)) {
       return -1;
   }
   ...
   selinux_enabled = is_selinux_enabled(); //3 selinux权限是否使能
   ...
   //4 进入无限循环,处理client端发来的请求 
   binder_loop(bs, svcmgr_handler);
   return 0;
}

1 binder_open( )

  • open("/dev/binder", O_RDWR); 通过系统调用陷入内核,打开Binder设备驱动,对应Binder Driver :binder_open()

  • ioctl(bs->fd, BINDER_VERSION, &vers) //通过系统调用,ioctl获取binder版本信息

  • bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);//通过系统调用,mmap内存映射,调用mmap()方法分配128k的内存映射空间。这样Binder的接收方就有了一片大小为MAP_SIZE的接收缓存区。对应Binder Driver :binder_mmap()

2 binder_become_context_manager( )

在介绍这个方法之前,先思考一个问题:ServiceManager是个进程,Client和Server是另外的进程,不管是Client getService 还是Server addService, 都是与ServiceManager进行进程间通信,且ServiceManager都是充当服务端,用的也是Binder IPC。既然是服务端,那么它本身也得注册Binder吧,那么实现就看下面这个方法:

  • ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); //binder_become_context_manager整个对应的就是这个方法,经过ioctl对应到Binder Driver的binder_ioctl_set_ctx_mgr() :当一个进程使用BINDER_SET_CONTEXT_MGR命令将自己注册成ServiceManager时Binder驱动会自动为它创建Binder实体,这个Binder的引用在所有Client中都固定为0而无须通过其它手段获得。所以进程必需通过0这个引用号(handle)和ServiceManager的Binder通信。这个过程不例外地创建binder_node结构体并加入到Binder驱动中的binder_procs 全局链表。

3 is_selinux_enabled()

验证selinux权限,判断进程是否有权注册或查看指定服务。

4 binder_loop()

发送BC_ENTER_LOOPER命令给binder驱动,让Service Manager进入循环。那么循环是在做什么?

 for(;;){
    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); //1 进入循环,不断地binder读写过程
     …
    res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);//2 解析binder信息
}

4.1 ioctl命令BINDER_WRITE_READ

kernel层我们了解过,是收发Binder IPC数据。此时进一步将数据封装为binder_write_read,传入到kernel binder 驱动, 对应的驱动方法:binder_ioctl_write_read(filp, cmd, arg, thread); 根据不同的BC协议做出反应,该方法执行流程:首先,把用户空间数据ubuf拷贝到内核空间bwr;当bwr写缓存有数据,则执行binder_thread_write;当写失败则将bwr数据写回用户空间并退出;当bwr读缓存有数据,则执行binder_thread_read;当读失败则再将bwr数据写回用户空间并退出;最后,把内核数据bwr拷贝到用户空间ubuf。

4.2 binder_parse()

数据传回用户空间后,通过binder_parse()对内核反馈给用户空间的数据进行解析,根据不同的BR协议作出反应,其中调用svcmgr_handler()来做两件事情:do_find_service()根据名称查找相应服务,do_add_service()注册指定服务,如果同一个服务已注册,重新注册前会先移除之前的注册信息。另外,binder_parse中通过BR_FAILED_REPLY能收到死亡通知: 当binder所在进程死亡后,会调用binder_release方法,然后调用binder_node_release.这个过程便会发出死亡通知的回调。

最后再看看整体执行流程图:

Android通信方式篇(六)-Binder机制(Native层(上))_第2张图片
from Jeanboydev
二、 ServiceManager的获取

现在ServiceManager大管家已经启动好了,那么进程就可以进行addService或者getService操作了吗?不,还差一步,那就是操作前要先获取ServiceManager,而这个获取过程并非简单的,下面来一起看看。

整个获取过程流程如下:

Android通信方式篇(六)-Binder机制(Native层(上))_第3张图片
from gityuan

相关类:

framework/native/libs/binder/
- ProcessState.cpp
- BpBinder.cpp
- Binder.cpp
- IServiceManager.cpp

framework/native/include/binder/
- IServiceManager.h
- IInterface.h

整个过程总结如下:

1 defaultServiceManager()

gDefaultServiceManager中获取ServiceManager采用单例,但是里面多了一层while循环,目的是当尝试创建或获取ServiceManager时,ServiceManager可能尚未准备就绪,这时通过循环尝试获取直到成功。gDefaultServiceManager的创建过程,可分解为以下3个步骤:ProcessState::self();getContextObject();interface_cast()。

2 ProcessState::self() 获取ProcessState对象

new ProcessState 实例化ProcessState,也是单例,保证每一个进程只有一个ProcessState对象。在ProcessState.cpp的构造方法中:

执行open_driver() :

open("/dev/binder", O_RDWR);打开/dev/binder设备,建立与内核的Binder驱动的交互通道;

mmap()创建大小为1M-8K的内存地址空间(BINDER_VM_SIZE);

再通过ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); ioctl设置binder驱动,能支持的最大线程数(DEFAULT_MAX_BINDER_THREADS:binder默认的最大可并发访问的线程数为16 )

又是open+mmap,这个套路已经很熟了。

3 getContextObject():获取BpBinder对象

getStrongProxyForHandle() 当handle值所对应的IBinder不存在或弱引用无效时会创建BpBinder,否则直接获取。(BpBinder对应客户端,BBinder对应服务端)。

4 interface_cast: 获取BpServiceManager

interface_cast是一个模板函数,可得出,interface_cast() 等价于 IServiceManager::asInterface(),而IServiceManager::asInterface()最终又等价于new BpServiceManager(BpBinder)。

BpServiceManager巧妙将通信层与业务层逻辑合为一体:

  • 通过继承接口IServiceManager实现了接口中的业务逻辑函数;
        interface IServiceManager {
               IBinder getService(String name);
               oneway void addService(String name, IBinder service);
         }
  • 通过成员变量mRemote= new BpBinder(0)进行Binder通信工作。
  • BpBinder通过handler来指向所对应BBinder, 在整个Binder系统中handle=0代表ServiceManager所对应的BBinder。

ServiceManager最核心的两个功能为查询和注册服务:

  • 注册服务:记录服务名和handle信息,保存到svclist列表;
  • 查询服务:根据服务名查询相应的的handle信息。

这两个过程,ServiceManager都是充当Server端,下篇文章就来分析下这两个过程。

参考:

https://blog.csdn.net/freekiteyu/article/details/70082302
http://gityuan.com/2015/11/07/binder-start-sm/
http://gityuan.com/2015/11/08/binder-get-sm/

你可能感兴趣的:(Android通信方式篇(六)-Binder机制(Native层(上)))