Android通信系列目录
博客创建时间:2020.11.06
博客更新时间:2023.03.19
以Android studio build=7.0.0,SDKVersion 31来分析讲解。如图文和网上其他资料不一致,可能是别的资料版本较低而已。
Binder机制是 Android系统中跨进程通讯(IPC)的一种方式,Android中ContentProvider、Intent、aidl都是基于Binder。
IPC除了Binder,还有共享内存、Socket、消息队列等其他方式。相比其他的跨进程通信方式Binder有其自身特有的优点:
阅读该篇博文前建议先阅读《Android 内存映射mmap浅谈》,这样更利于帮助理解Binder通信。
用户空间访问内核空间的唯一方式就是系统调用;通过这个统一入口接口,所有的资源访问都是在内核的控制下执行,以免导致对用户程序对系统资源的越权访问,从而保障了系统的安全和稳定。
Binder通信采用C/S架构,包含Client、 Server、 ServiceManager 以及 Binder 驱动。在 framework 层进行了封装,通过 JNI 技术调用 Native(C/C++)层的 Binder 架构,在 Native 层以 ioctl 的方式与 Binder 驱动通讯。
Client进程
使用服务的进程。
Server进程
提供服务的进程。
ServiceManager进程
Android OS的整个服务的管理程序,在binder通信中ServiceManager的作用是将字符形式的Binder名字转化成Client中对该Binder的引用,使得Client能够通过Binder名字获得对Server中Binder实体的引用。
任何service在被使用之前,均要向SM(Service Manager)注册。当客户端需要访问某个service时,应该首先向SM查询是否存在该服务。如果SM存在这个service,那么会将该service的handle返回给client,handle是每个service的唯一标识符。
Binder
一个进程的Binder线程数默认最大是16,超过的请求会被阻塞等待空闲的Binder线程。所以,在进程间通信时处理并发问题时,如使用ContentProvider时,它的CRUD(创建、检索、更新和删除)方法只能同时有16个线程同时工作
Binder驱动
驱动负责进程之间Binder通信的建立,Binder在进程之间的传递,Binder引用计数管理,数据包在进程之间的传递和交互等一系列底层支持。
一个Binder驱动中有很多个Binder对象,通过InterfaceToken区分他们
了解进程间通信的人都知道在Android使用的是Binder进行进程间通信,它的核心是mmap 内存映射方式进行的跨进程通信。
Binder机制在 Android中的实现主要依靠 Binder类以 MyClient进程
调用 MyServer进程
的加法函数,a+b举例来分析其过程
1. 获取服务
MyClient进程
通过Binder驱动 向 ServiceManager进程 查询相应的Service是否已注册,如未注册则注册服务。最终MyClient进程
获得BinderProxy对象。
此时 MyClient进程
与 MyServer进程
建立了连接。
MyClient进程
通过binderService()向Binder驱动发起获取Service的请求,并传递要获取的服务名。MyServer进程
Binder对象的引用信息返回给Binder驱动,该引用对象实质是指BinderProxy对象MyServer进程
Binder对象的引用信息返回给MyClient进程
,通过onServiceConnected()获得Binder对象的代理对象BinderProxy对象。2. 注册服务
MyServer进程
进程通过Binder驱动 向 Service Manager进程注册服务,通过调用该Service的onBinder返回一个Binder对象到Binder驱动中
MyServer进程
在 Binder 驱动中的存在形式,存在于内核空间中3. 使用服务
MyClient进程
通过BinderProxy对象操作Binder驱动内的Binder对象,进而操作MyServer进程
MyClient进程
将参数(整数a和b)发送到 MyServer进程
MyServer进程
根据MyClient进程
要求调用 目标方法(即加法函数)MyServer进程
将目标方法的结果(即加法后的结果)返回给MyClient进程
MyClient进程
获得一个MyServer进程
的代理接口,对MyServer进程
进行直接调用MyServer进程
中定义的方法是一一对应的MyClient进程
调用某个代理接口中的方法时,代理接口的方法会将MyClient进程
传递的参数打包成为Parcel对象MyServer进程
会读取binder driver中的请求数据,如果是发送给自己的,解包Parcel对象,处理并将结果返回MyServer进程
处理的时候,MyClient进程
的当前线程block阻塞在说Binder通信之前先说说跨进程通信IPC。
我们知道为了保证进程的安全性与独立性,一个进程不能直接操作或者访问另一个进程,即Android的进程是相互独立、隔离的。
如果进程间需要进行数据交换和通信就需要用到跨进程通信(IPC)。跨进程通信有两种方式,传统方式与mmap方式。
1. 传统的跨进程通信
发送进程通过系统调用,将需要发送的数据从用户空间copy_from_user
拷贝到Linux进程的内核空间中(Page Cache)
内核服务程序唤醒接收进程的接收线程,通过系统调用将数据从内核空间中copy_to_user
发送到用户空间中
缺点:
效率低下,需要2次数据拷贝, 用户空间>>内核空间>>用户空间
接收器的数据缓存需要接收方来提供,但是接收方却不知道到底要多大的缓存才能满足需求
尽量开辟大的空间,这样容易浪费空间;先调用API接收消息头获得信息体大小然后确定缓存大小,该方法浪费时间
2. mmap跨进程通信
以Android中Binder IPC跨进程通信为例
用户空间
发送到自生的虚拟内存区域
,其实质是拷贝到了共享缓冲区优点:
注意
: 进程中的空间分为用户空间
和 内核空间
,用户空间
中数据不可共享,内核空间
中的数据可以共享。
说明1
MyClient进程
、MyServer进程
& Service Manager 进程之间的交互 都必须通过Binder驱动(使用 open 和 ioctl文件操作函数),而非直接交互
原因:
MyClient进程
、MyServer进程
& Service Manager进程属于进程空间的用户空间,不可进行进程间交互说明2
Binder驱动 & Service Manager进程 属于 Android基础架构(即系统已经实现好了);而Client 进程 和 Server 进程 属于Android应用层(需要开发者自己实现)
所以,在进行跨进程通信时,开发者只需自定义Client & Server 进程 并 显式使用上述3个步骤,最终借助 Android的基本架构功能就可完成进程间通信
从不同角度理解Binder:
1、从IPC角度,Binder是跨进程通信方式
2、从FrameWork角度,Binder是ServiceManager连接各种Manager(如am,wm等)的桥梁
3、从应用层角度,Binder是客户端与服务端通信的媒介
本篇博文主要讲解Binder原理及通信流程,弄懂如下几个问题
1、Binder是什么?为什么要使用它,比如它有何优点?
2、它是如何实现跨进程通信的? 以一次跨进程函数为例,调用过程是怎样的?
相关链接:
扩展链接:
博客书写不易,您的点赞收藏是我前进的动力,千万别忘记点赞、 收藏 ^ _ ^ !