为什么Android要采用Binder作为IPC机制?
在开始回答 前,先简单概括性地说说Linux现有的所有进程间IPC方式:1. 管道:在创建时分配一个page大小的内存,缓存区大小比较有限;2. 消息队列:信息复制两次,额外的CPU消耗;不合适频繁或信息量大的通信;3. 共享内存:无须复制,共享缓冲区直接付附加到进程虚拟地址空间,速度快;但进程间的同步问题操作系统无法实现,必须各进程利用同步工具解决;4. 套接字:作为更通用的接口,传输效率低,主要用于不通机器或跨网络的通信;5. 信号量:常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。6. 信号: 不适用于信息交换,更适用于进程中断控制,比如非法内存访问,杀死某个进程等;
在Linux系统里面,进程之间是相互隔离的,也就是说进程之间的各个数据是互相独立,互不影响,而如果一个进程崩溃了,也不会影响到另一个进程。
Binder解决问题的初衷:
- 本质上需要解决的问题是让两个不同的进程之间能够互相调用的问题:
- 从效能的角度上出发,希望提供服务调用的程序能够支持并发,这样使得能够尽可能地响应多个程序的IPC请求
如何跨进程调用
那么如何使得调用者能像上述一样简单地调用远程方法?毕竟两者存在于不同的进程空间里面。那么可以引入一个黑盒模块,用这个黑盒模块来帮我们完成其中的细节,这个模块也被称为Binder Driver。方法的跨进程调用受到了 Linux 进程隔离的限制,而解决方案就是将其置于所有进程都能共享的区域 – Kernel,而 Binder Driver 提供的功能也就是让各进程使用内核空间,将进程中的地址和Kernel中的地址映射起来,其中Linux ioctl 函数实现了从用户空间转移到内核空间的功能。在 Binder Driver 的支持下,就能实现跨进程调用
Binder 架构分为 Client、Server、Service Manager 和 Binder Driver。
- Client: 服务调用者,一般就是我们应用开发者,通过调用诸如
List<PackageInfo> packs = getActivity().getPackageManager().getInstalledPackages(0);
这样的代码,来向 ServerManager 请求 Package 服务。 - Server: 服务提供者,这里面会有许多我们常用的服务,例如 ActivityService 、 WindowMananger, 这些系统服务提供的功能,是的我们能够使用 Wifi,Display等等设备,从而完成我们的需求。
- Service Manager: 这里是类似于前文中的DNS,绝大多数的服务都是通过 Service Manager来获取,通过这个 DNS 来屏蔽掉 对其他Server的直接操作。
- Binder Driver: 底层的支持逻辑,在这里承担路由的工作,不论风雨,使命必达,即使对面的server挂掉了,也会给你相应的死亡通知单 (Death Notification)
总结起来说,应用程序(Client) 首先向 Service Manager 发送请求 WindowManager 的服务,Service Manager 查看已经注册在里面的服务的列表,找到相应的服务后,通过 Binder kernel 将其中的 Binder 对象返回给客户端,从而完成对服务的请求。
网友评论