Android中Binder机制学习

1、Binder机制是什么以及其作用是什么?

Binder是android系统里面的进程间通信机制,它是Android中的一个类,实现了IBinder接口。在应用层中我们所使用的activity,service等组件都需要和ActivityManagerService通信,包括我们使用的各种系统service,这种跨进程的通信都是通过binder来完成的。binder可以比喻成Android系统的血管,看不到摸不着但是却非常重要。

在Android系统中,不同的app运行在不同的进程中,当一个进程想调用其他进程的服务时,就需要通过进程间通信的方式来提供服务。比如,APP1所在进程有一个对象object1,其中有一个方法method1。APP2所在的另外一个进程,想调用object1的method1方法。binder机制可以帮助我们在APP2所在进程拿到一个object1对象的引用,使我们能够像调用本地对象一样,通过object1.method1()直接调用。利用binder,我们可以突破进程的限制,将对象传给其它进程,让其它进程方便调用对象的方法。

2、Binder中的几个重要角色

在Binder机制中最主要的四个角色分别是:Client(想要使用服务的进程)、Service(实际提供服务的进程)、ServiceManager以及Binder内核驱动。

Binder的整个请求过程可以非常形象的用网络请求进行类比描述,Client就是我们的浏览器,Service即服务端,ServiceManager的作用就是用来进行域名解析,而Binder内核驱动就是我们的网络,整个网站浏览的过程大致如下:在浏览器输入一个具体的网址如http://www.baidu.com,然后域名解析服务会将该网址解析成一个具体的ip地址,然后浏览器会把请求数据发送到该ip地址所对应的服务器,服务器处理完毕后将结果返回给浏览器进行展示。

3、各角色工作机制

从客户端Client的角度来看,只需要获取服务端进程的服务即可,可以通过下图来表明该功能。

但是我们知道,两个不同的进程之间是不能够直接进行通信的,所以在不同进程之间可以增加内核机制,通过Binder内核驱动可以传递进程间的请求。

有了Binder驱动后,对于Client客户端和Service服务端,还需要额外专门与Binder驱动打交道,为了帮Client和Service端屏蔽掉与Binder驱动打交道这件很low的工作,我们可以分别为Client和Service设计一个代理,让他们只与代理打交道即可,将与Binder驱动打交道的任务放在代理里面:

再进一步,对于客户端而言更理想的状态是,客户端完全不用知道调用的对象是一个本地对象,还是一个服务端进程中的对象。如果Client端知道要调用一个远程对象,会通过一个Proxy来调用。我们在开发android应用程序的过程中,都会用到一些系统提供的XXXManager(ActivityManager、PackageManager、WifiManager、PowerManager等等),而这些manager所要实现的目的之一,正是帮Client屏蔽掉Binder的实现细节。有了这些Manager,Client在使用时,首先通过getServiceManager(xxx)获取一个manager对象,后面就直接调用manager中封装好的服务方法即可。这样以来,manager内部实际上还是通过客户端代理,通过binder驱动来跟运行在另外一个进程中的xxxService来通信,但对于Client来说,完全不用知道。如下图:

4、Binder通信机制工作原理

在Binder请求中,我们要使用某一个系统服务特定的功能,就可以类比成上述的浏览器请求页面数据,有些不同的地方在于Client端通过ServiceManager获取到指定系统服务的binder引用,这个binder引用的作用就类似于网络请求中的ip,当Client拿到这个binder引用后就能知道需要将数据发往具体的Service地址,这里有一个问题就是Service如何知道将处理完毕的数据返还给哪个Client,因为可能有多个Client同时对Service发起请求,这里就要分两种情况:

(1) Service处理完请求后不需要将数据返回给Client,这个是由TF_ONE_WAY标志位来控制的,当发送的数据带上这个标志位后那么Service在处理完后不会将请求结果返回。

(2) Service需要将数据返回给Client,此时TF_ONE_WAY没有被设置,当数据从binder内核传递给Service进行处理时会将Client的thread信息进行保存,具体会放到一个binder_transaction的队列中,当Service处理完请求将结果返回时就可以从binder_transaction中得到返回Client的thread信息。

在所有服务进程中,ServiceManager是第一个启动的,原因也不难理解,如果其它服务进程先于servicemanager启动,到哪里去注册。

4.1 Server向ServiceManager注册服务

首先,XXXServer在自己的进程中向Binder内核驱动申请创建一个XXXServiceBinder的实体,Binder驱动为这个XXXService创建位于内核中的Binder实体节点以及Binder的引用,注意,是将名字和新建的引用打包传递给SM(实体并没有传给SM),通知SM注册一个名叫XXXServiceSM收到数据包后,从中取出XXXService名字和引用,填入一张查找表中。此时,如果有Client向SM发送申请服务XXXService的请求,那么SM就可以在查找表中找到该ServiceBinder引用,并把Binder引用返回给Client

4.2 如何获得SM的远程接口

ServiceManager和Server都是进程,Server向ServiceManager注册Binder需要进程间通信,当前实现的是进程间通信却又用到进程间通信。这就好比鸡生蛋、蛋生鸡,但至少得先有其中之一。

巧妙的Binder解决思路:

针对Binder的通信机制,Server端拥有的是Binder的实体;Client端拥有的是Binder的引用。如果把ServiceManager看作Server端,让它在Binder驱动一运行起来时就有自己的Binder实体(代码中设置SM的Binder其handle值恒为0)。这个Binder实体没有名字也不需要注册,所有的client都认为handle值为0的binder引用是用来与SM通信的(代码中是这么实现的),那么这个问题就解决了。那么,Client和Server中这么达成协议了(handle值为0的引用是专门与SM通信之用的),还不行,还需要让SM有handle值为0的实体才算大功告成。怎么实现的呢?当一个进程调用Binder驱动时,使用BINDER_SET_CONTEXT_MGR命令(在驱动的binder_ioctl中)将自己注册成SM时,Binder驱动会自动为它创建Binder实体。这个Binder的引用对所有的Client都为0。

4.3 Client从SM获得Service的远程接口

Server向SM注册了Binder实体及其名字后,Client就可以通过Service的名字在SM的查找表中获得该Binder的引用了(BpBinder)。Client也利用保留的handle值为0的引用向SM请求访问某个Service:我申请访问XXXService的引用。SM就会从请求数据包中获得XXXService的名字,在查找表中找到该名字对应的条目,取出Binder的引用打包回复给client。之后,Client就可以利用XXXService的引用使用XXXService的服务了。如果有更多的Client请求该Service,系统中就会有更多的Client获得这个引用。

4.4 建立C/S通路后

首先要理清一个概念:Client拥有自己Binder的实体,以及Server的Binder的引用;Server拥有自己Binder的实体,以及Client的Binder的引用。我们也可以从接收方和发送方的方式来理解:

  • 从Client向Server发数据:Client为发送方,拥有Binder的实体;Server为接收方,拥有Binder的引用
  • 从Server向Client发数据:Server为发送方,拥有Binder的实体;Client为接收方,拥有Binder的引用。

也就是说,我们在建立了C/S通路后,无需考虑谁是Client谁是Server,只要理清谁是发送方谁是接收方,就能知道Binder的实体和引用在哪边。


建立CS通路后的流程:(当接收方获得Binder的实体,发送方获得Binder的引用后)

1、发送方会通过Binder实体请求发送操作。

2、Binder驱动会处理这个操作请求,把发送方的数据放入写缓存(binder_write_read.write_buffer) (对于接收方为读缓冲区),并把read_size(接收方读数据)置为数据大小(对于具体的实现后面会介绍)。

3、接收方之前一直在阻塞状态中,当写缓存中有数据,则会读取数据,执行命令操作。

4、接收方执行完后,会把返回结果同样用binder_transaction_data结构体封装,写入写缓冲区(对于发送方,为读缓冲区)

4.5 匿名Binder

Binder可以建立点对点的私有通道,匿名Binder就是这种方式。在Binder通信中,并不是所有用来通信的Binder实体都需要注册给SM广而告之的,Server可以通过已建立的实体Binder连接将创建的Binder实体传给Client。而这个Binder没有向SM注册名字。这样Server与Client的通信就有很高的隐私性和安全性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
千里马8年Android系统及应用开发经验,曾担任过美国unokiwi公司移动端技术总监兼架构师,对系统开发,性能优化,应用高级开发有深入的研究,Android开源定制ROM Lineage的贡献者之一,国内首家线下开辟培训Android Framework课程,拥有2年的Android系统培训经验。成为腾讯课堂专业负责android framework课程分享第一人,致力于提高国内android Framework水平Android Framework领域内是国内各大手机终端科技公司需要的人才,应用开发者都对Android系统充满着好奇,其binder是重之重,都说无binderAndroidbinde是Android系统的任督二脉。课程水平循序渐进,由级再到高级,满足各个层次水平的android开发者。1、灵活使用binder跨进程通信,在app端对它的任何api方法等使用自如2、可以单独分析android系统源码任何binder部分,分析再也没有难度3、掌握binder驱动本质原理,及对应binder驱动怎么进行跨进程通信,及内存等拷贝方式数据等4、对binder从上层的java app端一直到最底层的内核binder驱动,都可以顺利理通5、针对系统开发过程遇到的binder报错等分析方法,及binder bug案例学习6、针对面试官任何的binder问题都可以对答自如7、socket这种跨进程通信实战使用8、针对android源码使用的socket源码轻松掌握9、android系统源码最常见的socketpair双向跨进程通信10、使用socket实现一个可以让app执行shell命令的程序

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值