Binder是Android系统进程间通信(IPC)方式之一。 android 系统基于linux,目前linux支持的IPC包括传统的管道,System V IPC,即消息队列/共享内存/信号量,以及socket等。那么android系统也支持这些传统的进程间通信方式,为什么android系统还要单独开发一套使用Binder来进行通信呢?
主要有如下两个方面:
1, 性能角度
由于在移动设备诸如省电等性能的考虑,广泛地使用进程间通讯对于通信机制的性能有严格的要求,Binder相对于传统的Socket、管道方式更加高效。Bidner数据拷贝只需要一次,而管道、消息队列、Socket都需要2次,内存共享方式一次内存拷贝都不需要,但是实现起来难度高,复杂性大。
2,稳定性角度
传统的进程通信方式对于通信双方的身份并没有做出严格的验证,比如Socket通信ip地址是客户端手动填入,很容易进行伪造,而Binder机制从协议本身就支持对通信双方做身份校检,因而大大提升了安全性。
在讲解Binder之前先简单介绍一下有关进程方面的基础知识点:
进程空间分配
一个进程空间分为 用户空间 & 内核空间(Kernel),即把进程内 用户 & 内核 隔离开来
二者区别:
1. 进程间,用户空间的数据不可共享,所以用户空间 = 不可共享空间
2. 进程间,内核空间的数据可共享,所以内核空间 = 可共享空间
进程内 用户 与 内核 进行交互 称为系统调用(ioctl方法)
进程隔离
为了保证 安全性 & 独立性,一个进程 不能直接操作或者访问另一个进程,即Android的进程是相互独立、隔离的。
跨进程通信( IPC )
1,隔离后,由于某些需求,进程间 需要合作 / 交互。
2,跨进程间通信的原理
先通过 进程间 的内核空间进行 数据交互
再通过 进程内 的用户空间 & 内核空间进行 数据交互,从而实现 进程间的用户空间 的数据交互,而Binder,就是充当 连接 两个进程(内核空间)的通道。
Binder 通信模型(C/S框架)
Binder框架定义了四个角色:Server,Client,ServiceManager以及Binder驱动。Binder驱动 & Service Manager进程 属于 Android基础架构(即系统已经实现好了);而Client 进程 和 Server 进程 属于Android应用层(需要开发者自己实现)。
ServiceManger(SM):负责注册管理所有的Server,并为Client提供查询Server的功能,SM更像是Server和Client中间的一个中介。而SM、Server、Client这三个组件都是运行在各自独立的进程中的。所以这三者之间进行的通信也是进程间的通信,而且也是采用的Binder机制来进行进程间通信的。在这个通信的过程中,SM除了要管理各种Server,同时自己也充当着Server的角色。
Server: Server通过SM的远程接口,将自己的Service注册到SM中,然后将Service启动起来,同时会启动Binder线程池,等待客户端请求。提供服务的进程。
Client: Client通过SM的远程接口,获取到在SM中相对应的远程Service进行通信。使用服务的进程。
Binder驱动: Binder驱动是整个Binder通信机制的核心,进程间的数据交换就是通过它来完成的。如果Client要将数据传递给Server,正常情况下,Client把数据从自己的进程空间拷贝到内核空间,然后在从内核空间拷贝到Server的进程空间,这样Server就拿到了Client传递的数据,但是这个过程进行了两次内存拷贝。而通过Binder驱动,同一个物理页面,一方面映射到进程虚拟地址空间,另一方面又映射到内核虚拟地址空间。这样,只需要Client把要传递的数据拷贝到内核空间中,然后将拷贝到内核空间的数据同时映射到Server进程虚拟地址空间和内核虚拟地址空间,这样Server和内核就可以共享该数据了,一次内存拷贝就可以了。
Binder架构同tcp/ip一样也是采用分层架构设计, 每一层都有其不同的功能:
Java应用层: 对于上层应用通过调用AMP.startService, 完全可以不用关心底层,经过层层调用,最终必然会调用到AMS.startService.
Java IPC层: Binder通信是采用C/S架构, Android系统的基础架构便已设计好Binder在Java framework层的Binder客户类BinderProxy和服务类Binder;
Native IPC层: 对于Native层,如果需要直接使用Binder(比如media相关), 则可以直接使用BpBinder和BBinder(当然这里还有JavaBBinder)即可, 对于上一层Java IPC的通信也是基于这个层面.
Kernel物理层: 这里是Binder Driver, 前面3层都跑在用户空间,对于用户空间的内存资源是不共享的,每个Android的进程只能运行在自己进程所拥有的虚拟地址空间, 而内核空间却是可共享的. 真正通信的核心环节还是在Binder Driver.
调用流程:
总之一次完成的通信过程可简单描叙如下:
服务端跨进程的类都要继承Binder类。我们所持有的Binder引用(即服务端的类引用)并不是实际真实的远程Binder对象,我们的引用在Binder驱动里还要做一次映射。也就是说,设备驱动根据我们的引用对象找到对应的远程进程。客户端要调用远程对象函数时,只需把数据写入到Parcel,在调用所持有的Binder引用的transact()函数,transact函数执行过程中会把参数、标识符(标记远程对象及其函数)等数据放入到Client的共享内存,Binder驱动从Client的共享内存中读取数据,根据这些数据找到对应的远程进程的共享内存,把数据拷贝到远程进程的共享内存中,并通知远程进程执行onTransact()函数,这个函数也是属于Binder类。远程进程Binder对象执行完成后,将得到的写入自己的共享内存中,Binder驱动再将远程进程的共享内存数据拷贝到客户端的共享内存,并唤醒客户端线程。
android 系统进程间通信 Binder
最新推荐文章于 2025-05-24 16:27:57 发布