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驱动的守护进程。

整个启动过程流程如下:

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.这个过程便会发出死亡通知的回调。

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

from Jeanboydev
二、 ServiceManager的获取

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

整个获取过程流程如下:

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<IServiceManager>()。

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>() 等价于 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/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352