首页
办公常识
办公百科
办公生活
登录
注册
首页
办公生活
正文
Binder机制深入理解
创始人
2025-06-01 12:02:40
Binder机制深入理解
目录介绍
01.Binder的背景介绍
1.1 为何会有Binder
1.2 什么是Binder
1.3 常见进程通信
1.4 为什么要用Binder
02.Binder工作流程
2.1 Binder运行机制
2.2 工作流程介绍
2.3 工作流程图
2.4 举例说Binder通信
03.Binder设计思想
3.1 Binder设计流程
3.2 Binder设计思考
04.Binder源码流程
4.1 Binder通信原理图
4.2 Binder安全校验
00.先思考一些问题
01.为什么会有Binder?不在同一个进程中的Activity和Service(比如把服务定义成一个独立进程)是如何通信的?
02.Binder的设计思想是什么?多进程通信有哪些方式?为什么在Android系统中要是用Binder通信,有什么优缺点?
03.进程通信有共享内存,管道,socket,消息队列。他们的原理大概都是什么样的?Binder中使用mmap是什么东西?
04.既然有现有的IPC方式,为什么重新设计一套Binder机制呢。是否用Binder中mmap思想解决你的APP卡顿问题?
05.Binder机制:ServiceManager什么时候注册的?这个是用来干嘛的?Binder内核所在的进程是如何找到到Server跟Client进行通信的?
01.Binder的背景介绍
1.1 为何会有Binder
每一个应用程序都是由一些Activity和Service组成的,这些Activity和Service有可能运行在同一个进程中,也有可能运行在不同的进程中。
作为一名Android开发,我们每天都在和Binder打交道,虽然可能有的时候不会注意到,譬如:
startActivity的时候,会获取AMS服务,调用AMS服务的startActivity方法
startActivity传递的对象为什么需要序列化
bindService为什么回调的是一个IBinder对象
多进程应用,各个进程之间如何通信
AIDL的使用
它们都和Binder有着莫切关系,当碰到上面的场景,或者一些疑难问题的时候,理解Binder机制是非常有必要的。这就是要介绍的Binder进程间通信机制。
1.2 什么是Binder
1.直观来说,Binder是Android中的一个类,它继承了IBinder接口。
2.从IPC角度来说,Binder是Android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,该通信方式在linux中没有
3.从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager,etc)和相应ManagerService的桥梁
4.从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当你bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。
1.3 常见进程通信
在传统的Linux上,我们还是有很多选择可以用来实现进程间通信
如管道、SystemV、Socket、共享内存等。那么Android为什么不使用这些原有的技术,而是要使开发一种新的叫Binder的进程间通信机制呢?
共享内存
什么是共享内存:共享内存是进程间通信中最简单的方式之一,共享内存允许两个或更多进程访问同一块内存,当一个进程改变了这块地址中的内容的时候,其它进程都会察觉到这个更改。
性能和安全分析:因为共享内存是访问同一块内存,所以数据不需要进行任何复制,是IPC几种方式中最快,性能最好的方式。由于能任意的访问和修改内存中的数据,如果有恶意程序去针对某个程序设计代码,很可能导致隐私泄漏或者程序崩溃,所以安全性较差。
管道
什么叫做管道:它具有固定的读端和写端,写进程通过写段向管道文件里写入数据,读进程通过读段从读进程中读出数据,构成一条数据传递的流水线。
性能和安全分析:管道一次通信需要经历2次数据复制(进程A -> 管道文件,管道文件 -> 进程B)。管道的读写分阻塞和非阻塞,管道创建会分配一个缓冲区,而这个缓冲区是有限的,如果传输的数据大小超过缓冲区上限,或者在阻塞模式下没有安排好数据的读写,会出现阻塞的情况。
消息队列
什么叫消息队列:消息队列是存放在内核中的消息链表,每个消息队列由消息队列标识符表示。消息队列允许多个进程同时读写消息,发送方与接收方要约定好,消息体的数据类型与大小。
性能和安全分析:消息队列克服了信号承载信息量少、管道只能承载无格式字节流等缺点,消息队列一次通信同样需要经历2次数据复制(进程A -> 消息队列,消息队列 -> 进程B)
Socket
什么是Socket:Socket原本是为了网络设计的,但也可以通过本地回环地址 (127.0.0.1) 进行进程间通信。
一个Socket会拥有两个缓冲区,一读一写,由于发送/接收消息需要将一个Socket缓冲区中的内容拷贝至另一个Socket缓冲区,所以Socket一次通信也是需要经历2次数据复制。
1.4 为什么要用Binder
最简单的回答:
性能:相比传统的Socket更高效;安全:安全性高,支持通信双方进行身份验证
。
性能方面的优势
在移动设备上(性能受限制的设备,比如要省电),广泛地使用跨进程通信对通信机制的性能有严格的要求,Binder相对出传统的Socket方式,更加高效。
Binder数据拷贝只需要一次,而管道、消息队列、Socket都需要2次,共享内存方式一次内存拷贝都不需要,但实现方式又比较复杂。
安全方面优势
传统的进程通信方式对于通信双方的身份并没有做出严格的验证,比如Socket通信ip地址是客户端手动填入,很容易进行伪造。
而Binder机制从协议本身就支持对通信双方做身份校检,因而大大提升了安全性。
还有一些好处,如实现面象对象的调用方式,在使用Binder时就和调用一个本地实例一样。
为何说Binder相比传统的Socket性能更高效?
跨进程通讯中,只有socket支持Client-Server的通信方式,但是socket作为一款通用接口,其传输效率低,开销大,主要用在跨网络的进程间通信和本机上进程间的低速通信。
消息队列和管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程。
共享内存虽然无需拷贝,但控制复杂,难以使用,而且相对来说特别不安全。
为何说Binder相比传统IPC安全性更高?
首先传统IPC的接收方无法获得对方进程可靠的UID和PID(用户ID进程ID),从而无法鉴别对方身份。Android为每个安装好的应用程序分配了自己的UID,故进程的UID是鉴别进程身份的重要标志。
使用传统IPC只能由用户在数据包里填入UID和PID,但这样不可靠,容易被恶意程序利用。可靠的身份标记只有由IPC机制本身在内核中添加。其次传统IPC访问接入点是开放的,无法建立私有通道。
比如命名管道的名称,systemV的键值,socket的ip地址或文件名都是开放的,只要知道这些接入点的程序都可以和对端建立连接,不管怎样都无法阻止恶意程序通过猜测接收方地址获得连接。
基于以上原因,Android需要建立一套新的IPC机制来满足系统对通信方式,传输性能和安全性的要求,这就是Binder。
Binder基于Client-Server通信模式,传输过程只需一次拷贝,为发送发添加UID/PID身份,既支持实名Binder也支持匿名Binder,安全性高。
02.Binder工作流程
2.1 Binder运行机制
Binder基于Client-Server通信模式,除了Client端和Server端,还有两角色一起合作完成进程间通信功能。
Binder通信的四个角色:
Client进程:使用服务的进程。
Server进程:提供服务的进程。
ServiceManager进程:ServiceManager的作用是将字符形式的Binder名字转化成Client中对该Binder的引用,使得Client能够通过Binder名字获得对Server中Binder实体的引用。
Binder驱动:驱动负责进程之间Binder通信的建立,Binder在进程之间的传递,Binder引用计数管理,数据包在进程之间的传递和交互等一系列底层支持。
接触这些概念可能会觉得难于理解,读者可以把四个角色和熟悉的互联网进行类比:
Server是服务器,Client是客户终端,ServiceManager是域名服务器(DNS),驱动是路由器。
2.2 工作流程介绍
Binder的工作流程是怎样的?
1客户端首先获取服务器端的代理对象。所谓的代理对象实际上就是在客户端建立一个服务端的“引用”,该代理对象具有服务端的功能,使其在客户端访问服务端的方法就像访问本地方法一样。
2客户端通过调用服务器代理对象的方式向服务器端发送请求。
3代理对象将用户请求通过Binder驱动发送到服务器进程。
4服务器进程处理用户请求,并通过Binder驱动返回处理结果给客户端的服务器代理对象。
5客户端收到服务端的返回结果。
2.3 工作流程图
binder工作流程图如下所示:
Binder主要能提供哪些功能?
用驱动程序来推进进程间的通信。
通过共享内存来提高性能。
为进程请求分配每个进程的线程池。
针对系统中的对象引入了引用计数和跨进程的对象引用映射。
进程间同步调用。
2.4 举例说Binder通信
我们知道应用进程与SystemServer进程属于两个不同的进程,进程之间需要通讯。举例子比如说:AMS通信
android系统采取了自身设计的Binder机制,这里的ActivityManagerProxy和ActivityManagerNative都是继承与IActivityManager的而SystemServer进程中的ActivityManagerService对象则继承与ActivityManagerNative。
简单的表示:Binder接口 --> ActivityManagerNative/ActivityManagerProxy --> ActivityManagerService;
这样ActivityManagerNative与ActivityManagerProxy相当于一个Binder的客户端
而ActivityManagerService相当于Binder的服务端
这样当ActivityManagerNative调用接口方法的时候底层通过Binder driver就会将请求数据与请求传递给server端,并在server端执行具体的接口逻辑。
需要注意的是Binder机制是单向的,是异步的,也就是说只能通过client端向server端传递数据与请求而不同等待服务端的返回,也无法返回,
那如果SystemServer进程想向应用进程传递数据怎么办?这时候就需要重新定义一个Binder请求以SystemServer为client端,以应用进程为server端,这样就是实现了两个进程之间的双向通讯。
03.Binder设计思想
3.1 Binder设计流程
Binder设计流程图
通过图来说一下流程
Server进程向ServiceManager注册,告诉ServiceManager我是谁,我有什么,我能做什么。就好比徐同学(Server进程)有一台笔记本(computer对象),这台笔记本有个add方法。这时映射关系表就生成了。
Client进程向ServiceManager查询,我要调用Server进程的computer对象的add方法,可以看到这个过程经过Binder驱动,这时候Binder驱动就开始发挥他的作用了。当向ServiceManager查询完毕,是返回一个computer对象给Client进程吗?其实不然,Binder驱动将computer对象转换成了computerProxy对象,并转发给了Client进程,因此,Client进程拿到的并不是真实的computer对象,而是一个代理对象,即computerProxy对象。很容易理解这个computerProxy对象也是有add方法,(如果连add方法都没有,岂不是欺骗了Client?),但是这个add方法只是对参数进行一些包装而已。
当Client进程调用add方法,这个消息发送给Binder驱动,这时驱动发现,原来是computerProxy,那么Client进程应该是需要调用computer对象的add方法的,这时驱动通知Server进程,调用你的computer对象的add方法,将结果给我。然后Server进程就将计算结果发送给驱动,驱动再转发给Client进程,这时Client进程还蒙在了鼓里,他以为自己调用的是真实的computer对象的add方法,其实他只是调用了代理而已。不过Client最终还是拿到了计算结果。
3.2 Binder设计思考
Binder设计思考
Service Manager是如何成为一个守护进程的?即Service Manager是如何告知Binder驱动程序它是Binder机制的上下文管理者。
Server和Client是如何获得Service Manager接口的?即defaultServiceManager接口是如何实现的。
Server是如何把自己的服务启动起来的?Service Manager在Server启动的过程中是如何为Server提供服务的?即IServiceManager::addService接口是如何实现的。
Service Manager是如何为Client提供服务的?即IServiceManager::getService接口是如何实现的。
3.4 Binder线程管理
Binder中是如何进行线程管理的?
每个Binder的Server进程会创建很多线程来处理Binder请求,可以简单的理解为创建了一个Binder的线程池吧(虽然实际上并不完全是这样简单的线程管理方式),而真正管理这些线程并不是由这个Server端来管理的,而是由Binder驱动进行管理的。
一个进程的Binder线程数默认最大是16,超过的请求会被阻塞等待空闲的Binder线程。理解这一点的话,你做进程间通信时处理并发问题就会有一个底,比如使用ContentProvider时(又一个使用Binder机制的组件),你就很清楚它的CRUD(创建、检索、更新和删除)方法只能同时有16个线程在跑。
总结binder讲的是什么?
通常意义上来说,Binder就是指Android的通信机制;
对于服务端进程来说,Binder指的是Binder本地对象,对于客户端进程来说,Binder指的是Binder代理对象。
对于传输过程来说,Binder是可以进行跨进程传递的对象;
04.Binder源码流程
4.1 Binder通信原理图
Binder底层使用到mmap
Binder是基于内存映射mmap设计实现的,通过这种方式,直接操作映射的这一部分内存,通过mmap,Binder通信时,只需要经历一次数据复制,从而获得更好的性能。
一次Binder IPC通信的过程分为以下几个步骤:
首先,Binder驱动在内核空间中开辟出一个数据接收缓冲区
接着,在内核空间中开辟出一个内核缓冲区
将内核缓冲区与数据接收缓冲区建立映射关系
将数据接收缓冲区与接收进程的用户空间地址建立映射关系
发送方进程通过copy_from_user将数据从用户空间复制到内核缓冲区
由于内核缓冲区与数据接收缓冲区有映射关系,同时数据接收缓冲区与接收进程的用户空间地址有映射关系,所以在接收进程中可以直接获取到这段数据
这样便完成了一次Binder IPC通信,它的原理如下图所示:
4.2 Binder安全校验
下图展示Binder IPC架构的一个简单例子。
每个通过Binder框架实现IBinder接口,允许被访问调用的对象都可被称作Binder对象。对Binder对象的调用在一个Binder事务处理(transaction)内部实现,其中包括一个对目标对象的引用、需执行方法的ID和一个数据缓冲区。
如何保证Binder安全性
Binder驱动会将调用进程的ID(PID)和有效用户ID(EUID)自动添加到事务处理数据。被调用进程可以检查PID和EUID,然后基于内部实现逻辑来决定是否执行所请求的方法。
因为PID和EUID是由内核填写的,所以调用者进程不能通过伪造身份标识来获取超出系统允许的权限。这是Android安全模型的核心之一,所有更高层次抽象,比如权限,均是建立在它之上。
调用者的PID和EUID通过类android.os.Binder的getCallingPid()和getCallingUid()来访问,他们是Android公开API的一部分。
词库加载错误:未能找到文件“E:\highferrum_mysql\Configuration\Dict_Stopwords.txt”。
上一篇:
Handler源码分析之epoll机制
下一篇:
若依微服务版之新建子模块
相关内容
热门资讯
阿西吧是什么意思 阿西吧相当于...
即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...
脚上的穴位图 脚面经络图对应的...
人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
荼蘼什么意思 岁月缱绻葳蕤生香...
感谢作者【辰夕】的原创独家授权分享编辑整理:【多肉植物百科】百科君坐标:云南 曲靖春而至,季节流转,...
猫咪吃了塑料袋怎么办 猫咪误食...
你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮...
此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...