从事android作业一年了,感觉要学习的东西真的太多了,并且android的远景也不容乐观,最近在看项目时,一直运用Bundle,也知道是Binder通讯,可是Binder是什么,什么原理,我真的不知道。感觉Binder是在Android中呈现频率很高的一个名词,提到IPC,无论如何都绕不开Binder,深化理解binder需求一定的积累,感觉把binder理解的滚瓜乱熟,就能换岗了,哈哈哈哈哈,今日找时刻看一些网上的博客,帖子,浅浅的学习一下Binder。
1.Binder的布景
Binder是Android体系中的一种跨进程通讯(IPC)机制,它是由Android的创始人之一安迪鲁宾(Andy Rubin)在Google时期规划的。Binder开始是为了处理Android体系中进程间通讯
的需求而开发的。
Android体系是依据Linux内核的,在Linux内核中,每个应用程序在Android体系中运转在独立的进程中。
为了完成应用程序
之间的通讯和数据同享
,Android需求一种高效且安全的跨进程通讯机制
。
Binder的规划创意来自于Object Request Broker(ORB)模型,它是一种用于分布式体系中的目标恳求署理模型。Binder依据这一思维,在Android体系中完成了一套轻量级的进程间通讯机制。
2.Binder的演进进程
从布景能够看出来,binder是Android的特有的一种IPC结构,那么为什么不直接运用Linux的本身的跨进程通讯的结构呢?是内存太大?仍是Android不支持? 这儿我参阅了hackmd.io/@AlienHackM… && zhuanlan.zhihu.com/p/35519585
图就不自己画了。
2.1 Linux的内存缺陷
- 首要了解下几个linux名词:
进程阻隔
、进程空间区别
、体系调用
.
-
进程阻隔
简单的说便是操作体系中,进程与进程间内存是不同享的。两个进程就像两个平行的国际,A 进程没法直接拜访 B 进程的数据,这便是进程阻隔的通俗解说。A 进程和 B 进程之间要进行数据交互就得选用特别的通讯机制:进程间通讯(IPC)。
-
进程空间区别:用户空间(User Space)/内核空间(Kernel Space)
内核空间是操作体系内核拜访的区域,独立于普通的应用程序,是受保护的内存空间。其实早期操作体系是不区别内核空间和用户空间的,可是应用程序能拜访任意内存空间,假如程序不稳定常常把体系搞崩溃,比如清除操作体系的内存数据。后来觉得让应用程序随意拜访内存太危险了,就依照CPU 指令的重要程度对指令进行了分级, 指令分为四个等级 :Ring0~Ring3 (和电影分级有点像),linux 只运用了 Ring0 和 Ring3 两个运转等级,进程运转在 Ring3 等级时运转在用户态,指令只拜访用户空间,而运转在 Ring0 等级时被称为运转在内核态,能够拜访任意内存空间。
-
体系调用:用户态/内核态 用户态跟内核态的界说和进程空间的区别是一一对应的。当进程/线程运转在内核空间时就处于内核态,而进程/线程运转在用户空间时则处于用户态。
- Linux中IPC原理
上面这个图很明晰的表达了Linux的通讯原理,先介绍下图中的两个函数,
copy_from_user()
将数据从用户空间拷贝到内核空间
copy_to_user()
将数据从内核空间拷贝到用户空间
能够看到蓝色部分是进程A的经过copy_from_user()将数据从用户的内存拷贝到内核缓存中。而从绿色的能够看到,当进程C想运用A中的数据时,经过copy_to_user()
将数据从内核缓存中拷贝到用户进程的内存缓存中(也便是用户空间)。
- 能够看到在跨进程通讯进程中,数据经过2次拷贝,频繁的用户态和内核态切换,十分影响功用
- 进程C无法确认进程A传递的数据巨细,所以会尽可能打的敞开内存空间,这就可能导致了内存糟蹋。
2.2 Android中binder机制
上面了解了Linux中的跨进程通讯(IPC)的缺点,Android手机的内存在初期是很小的,必定比电脑的小,所以,Google工程师,就针对上面Linux的跨进程通讯的坏处,敞开了Binder之旅。
既然是优化,必定是使用了某个技术,减去或许优化了某个环节。在了解是怎样优化之前,咱们需求先了解Binder用到的几个技术名词:动态内核可加载模块
,内存映射
-
动态内核可加载模块(Loadable Kernel Modules,LKM) 是一种答应在运转时加载和卸载的内核模块。在Android体系中,Binder作为一种进程间通讯(IPC)机制,它在内核层面起着重要的效果。
- 功用扩展和定制化:经过加载动态内核可加载模块,能够向Android体系增加新的功用或修正现有功用。在Binder中,能够经过加载LKM来扩展Binder的功用,完成更多的通讯特性或许优化通讯功用。
- 驱动程序支持:一些硬件设备的驱动程序可能需求在运转时加载到内核中,以便在体系启动后供给相应的功用和服务。这些驱动程序可能与Binder通讯,因而加载到内核中的LKM能够经过Binder与用户空间的进程进行通讯。
- 安全性和稳定性:动态内核可加载模块答应在运转时加载和卸载,这意味着能够依据需求增加或移除功用,而无需从头编译整个内核。这种灵活性有助于提高体系的安全性和稳定性,因为能够随时依据需求调整体系的功用。
在binder中的效果:
binder作为Android特有的机制,并不是Linux内核本身就包含的机制,而动态内核可加载模块的效果便是做到了插件的效果,动态加载、新增功用、不需求从头编译整个内核
长处。 -
内存映射(Memory Mapping)是一种将磁盘上的文件映射到进程的内存空间的技术。它答应
进程
直接拜访文件的内容,而无需经过传统的读取和写入操作。在内存映射中,操作体系
会将文件的一部分或整个文件映射
到进程的地址空间中的一段内存区域。一旦文件被映射到内存中
,进程就能够像拜访内存相同拜访文件
,而不用
像传统的文件I/O操作那样进行读取和写入。
怎样样,看完上面两个技术点,就能够猜到Binder相关于传统的Linux的IPC通讯的优化之处应该是在哪里了。这么看的话态内核可加载模块
要是关于Binder在Android中运用做了功用支持
,内存映射
是针对传统的IPC通讯做了功用优化
。
Binder的IPC通讯是这样的(直接粘贴了) 从图中能够一眼看出来的是:Binder的机制跟传统的IPC不同的地方是,内核空间拓荒了两个内存。 首要 Binder 驱动在内核空间创立一个数据接纳缓存区; 接着在内核空间拓荒一块内核缓存区,树立内核缓存区和内核中数据接纳缓存区之间的映射联系,以及内核中数据接纳缓存区和接纳进程用户空间地址的映射联系;
- 最左边跟传统的IPC通讯仍是相同的,都是要将进程A的数据经过
copy_from_user()
拷贝到内核中(留意这个内核是动态内核可加载模块) - 首要 Binder 驱动在内核空间创立一个数据接纳缓存区;
- 接着在内核空间拓荒一块内核缓存区,树立内核缓存区和内核中数据接纳缓存区之间的映射联系,以及内核中数据接纳缓存区和接纳进程用户空间地址的映射联系;
- 发送方进程经过体系调用 copyfromuser() 将数据 copy 到内核中的内核缓存区,因为内核缓存区和接纳进程的用户空间存在内存映射,因而也就相当于把数据发送到了接纳进程的用户空间,这样便完成了一次进程间的通讯。
OK,这样一个逾越传统IPC通讯的架构就呈现了。
2.Binder在Android中的运用
Binder在Android体系中被广泛用于进程间通讯(IPC)和组件间通讯,它供给了一种安全而高效
的机制来完成不同应用程序
或不同进程
之间的数据传输和办法调用。以下是在Android开发中运用Binder的一些常见场景和办法:
- 跨进程通讯(IPC) :Binder答应不同进程之间的通讯,包含进程之间的数据传输、办法调用等。在Android开发中,能够运用Binder完成进程间的通讯,比如Activity和Service之间的通讯、应用程序和体系服务之间的通讯等。
- AIDL(Android Interface Definition Language) :AIDL是Android中界说Binder接口的一种语言,它用于描述Binder接口的办法和参数。经过编写AIDL文件,能够界说一个接口,然后让客户端和服务端依据这个接口进行通讯。
- Service:在Android中,Service是一种能够在后台履行长时刻运转操作的组件,它能够与其他组件或后台进程进行通讯。经过承继Service类并完成其间的onBind()办法,能够创立一个能够绑定的服务,并经过Binder目标供给对服务的拜访。
- 客户端-服务器方式:Binder能够用于完成客户端-服务器方式的通讯。在这种方式下,服务端供给了一个Binder目标,客户端经过Binder目标调用服务端供给的办法或获取数据。
- HandlerThread:HandlerThread是Android中的一个线程类,它承继了Thread类并完成了Handler,能够用于处理异步使命。在HandlerThread中,能够运用Binder来进行线程间的通讯,完成数据的传输和使命的调度。
3.Binder通讯的原理(宏观)
前面了解了,微观上的Binder的原理,面试的知识点现已get了一半了,相似于咱们了解了什么是HTTP,那么后面咱们应该了解下,前端和服务端是怎样样经过http通讯的呢?
首要咱们先猜测一下,进程通讯,必定是双向的,双向通讯就设置消息的发送接纳了,就跟咱们进出停车场,必定有一个办理体系。要不停车场满了或许进出口堵塞了都没有感知体系。那么在Binder进程通讯中必定也有一个办理体系,来处理消息的行列。大体架构应该是这样。
猜测图
大体结构应该是这样,可是每个结构都处理一些特别情况,所以可能是有一些小变化,可是也是以这个演进的,废话不多说,去网上直接Google下,看看具体的结构是怎样样的。
知乎上的图
这个图记起来比较费事,实例化一下,便是你家里的Wifi,现在咱们依照在家里运用wifi
的步骤来分析下,binder在IPC通讯的进程。
-
Binder 驱动 (
装置路由器
)
跟咱们运用wifi时要有一个路由器担任通讯以及办理设备相同,Binder驱动便是整个binder在IPC中的中心;驱动担任进程之间的 Binder 通讯树立
,Binder 传递
,引证计数办理
,数据包的传递
和交互
等一系列底层支持(怎样样,这种双向通讯或许说有数据通讯的机制,必定有一个要害的办理器)。
-
ServiceManager 与实名 Binder (
路由器注册到手机Wifi列表
)
当我拿着开手机去蹭网时,打开wifi,手机列表一般有很多个wifi姓名,咱们挑选想要链接姓名的Wifi,那么这一个列表的Wifi是怎样来的呢?
ServiceManager 和手机Wifi办理器
相似,效果是将字符方式的 Binder 姓名转化成 Client 中对该 Binder 的引证,使得 Client 能够经过 Binder 的姓名取得对 Binder 实体的引证(手机Wifi列表依据姓名直接找到对应的Wifi,不需求Wifi地址)。注册了姓名的 Binder 叫实名 Binder(实名老王家的Wifi
)。
Server 创立了 Binder,并为它起一个字符方式,可读易记得姓名,将这个 Binder 实体连同姓名一起以数据包的方式经过 Binder 驱动发送给 ServiceManager(路由器注册好wifi后,注册到手机Wifi衔接页面
),这样咱们就知道一个Wifi姓名为老王家的Wifi,它坐落老王家。
驱动为这个穿越进程鸿沟的 Binder 创立坐落内核中的实体节点以及 ServiceManager 对实体的引证,将姓名以及新建的引证打包传给 ServiceManager。ServiceManger 收到数据后从中取出姓名和引证填入查找表。
细心的读者可能会发现,ServierManager 是一个进程,Server 是另一个进程,Server 向 ServiceManager 中注册 Binder 必然涉及到进程间通讯。当前完成进程间通讯又要用到进程间通讯,这就如同蛋能够孵出鸡的前提却是要先找只鸡下蛋!Binder 的完成比较巧妙,便是预先发明一只鸡来下蛋。ServiceManager 和其他进程同样选用 Bidner 通讯,ServiceManager 是 Server 端,有自己的 Binder 实体,其他进程都是 Client,需求经过这个 Binder 的引证来完成 Binder 的注册,查询和获取。ServiceManager 供给的 Binder 比较特别,它没有姓名也不需求注册。当一个进程运用 BINDERSETCONTEXT_MGR 命令将自己注册成 ServiceManager 时 Binder 驱动会主动为它创立 Binder 实体(这便是那只预先造好的那只鸡)。其次这个 Binder 实体的引证在所有 Client 中都固定为 0 而无需经过其它手法取得。也便是说,一个 Server 想要向 ServiceManager 注册自己的 Binder 就必须经过这个 0 号引证和 ServiceManager 的 Binder 通讯。类比互联网,0 号引证就好比是域名服务器的地址,你必须预先动态或许手艺配置好。要留意的是,这儿说的 Client 是相关于 ServiceManager 而言的,一个进程或许应用程序可能是供给服务的 Server,但关于 ServiceManager 来说它仍然是个 Client。
-
Client 取得实名 Binder 的引证
手机衔接对应wifi
前面现已知道了,小明,小强,老王家的wifi名称是怎样呈现在我的手机列表里的。现在我就能够经过名称直接衔接到他们的真实的WIFI地址。
Server 向 ServiceManager 中注册了 Binder 以后, Client(我的手机) 就能经过姓名取得 Binder 的引证了。Client 也使用保留的 0 号引证向 ServiceManager 恳求拜访某个 Binder: 我申请链接老王家的Wifi
的时,手机wifi模块就找到老王家的wifi对应的真实地址,然后建议衔接恳求。
衔接对应的Binder 引证跟上面也是一致的。ServiceManager 收到这个恳求后从恳求数据包中取出 Binder 名称,在查找表里找到对应的条目,取出对应的 Binder 引证作为回复发送给建议恳求的 Client。
从面向目标的视点看,Server 中的 Binder 实体现在有两个引证:一个坐落 ServiceManager 中,一个坐落建议恳求的 Client 中。假如接下来有更多的 Client 恳求该 Binder,体系中就会有更多的引证指向该 Binder ,就像 Java 中一个目标有多个引证相同。
3.2 Binder 通讯进程
上面是一个更为具体的binder IPC通讯架构。
其间 Client、Server、Service Manager 运转在用户空间,Binder 驱动运转在内核空间。其间 Service Manager 和 Binder 驱动由体系供给
,而 Client、Server 由应用程序来完成
。Client、Server 和 ServiceManager 均是经过体系调用
open、mmap 和 ioctl 来拜访设备文件 /dev/binder,从而完成与 Binder 驱动的交互来直接的完成跨进程通讯。
需求要点了解的便是
:
-
首要,一个进程运用 BINDERSETCONTEXT_MGR 命令经过 Binder 驱动将自己注册成ServiceManager;
-
Server 经过驱动向 ServiceManager 中注册 Binder(Server 中的 Binder 实体),表明能够对外供给服务。驱动为这个 Binder 创立坐落内核中的实体节点以及 ServiceManager 对实体的引证,将姓名以及新建的引证打包传给 ServiceManager,ServiceManger 将其填入查找表。
-
Client 经过姓名,在 Binder 驱动的协助下从 ServiceManager 中获取到对 Binder 实体的引证,经过这个引证就能完成和 Server 进程的通讯。
可是从上面的图中咱们能够看到在蓝色跟最顶层之间,仍是在framework层,有一层为BinderProxy,他的效果是什么呢?
其实这个跟咱们在serviceManger中注册的service是一回事,一个是使用映射,一个是使用署理。咱们在Client中运用的Binder目标,也是server中的一个署理。binder此处的规划,也是突出了署理方式的长处。就像上面咱们只管调用binder,咱们并不需求知道署理怎样完成的。
- 你能够在客户端毫无察觉的情况下操控服务目标。
- 假如客户端对服务目标的生命周期没有特别要求,你能够对生命周期进行办理。
- 即便服务目标还未准备好或不存在,署理也能够正常作业。
- 开闭原则。你能够在不对服务或客户端做出修正的情况下创立新署理。
这篇文章断断续续整理了好几天,理论部分就到这儿吧。实践部分大家网上看下代码就能够。首要的是这个思维和原理。总结便是
- 两次内存仿制变为一次
- 使用动态内存块和分页映射原理完成通讯。
- 还有便是几个要害名词以及在binder中的效果,(binder驱动(中枢)、clinent,server、serviceManger(办理存储))