面试官: Linux 自带多种进程通信方式,为什么 Android 都没采用,而偏偏使用 Binder 通信
心理分析:面试官绝对不会现场让你分析 binder 的源码,源码又 深又广,没有面试官会傻到让你分析 binder 所有的机制。他会问 你为什么不采用 linux。 从这个地方会看出你对 binder 有多深。 这道题往往是面试 Android 高级的必考题。所以小伙伴们需要格外 的注意
求职者:应该从 linux 自带的进程通信说起。然后各个击破 指 出在 Android 这种特殊系统上的不足。最后引入 binder 的优势
Linux 现有的所有进程间 IPC 方式:
1.管道:
什么是管道:
管道可用于具有亲缘关系进程间的通信,管道是由内核管理的一个缓冲 区,相当于我们放入内存中的一个纸条。管道的一端连接一个进程的输出。这 个进程会向管道中放入信息。
管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息。一个缓冲区不需要很大,它被设计成为环形的数据结构
以便管道可以被循环利用。当管道中没有信息的话,从管道中读取的进程 会等待,直到另一端的进程放入信息。当管道被放满信息的时候,尝试放 入信息的进程会等待,直到另一端的进程取出信息。当两个进程都终结的 时候,管道也自动消失。
缺点: 在创建时分配一个管道时,缓存区大小比较有限;并不适合 Android 大量的进程通信
2.消息队列:
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方 法。 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有 不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻 塞问题。但是消息队列与命名管道一样,每个数据块都有一个最大长度的 限制。
缺点: 信息复制两次,额外的 CPU 消耗;不合适频繁或信息量大的通信;
3.共享内存:
什么是共享内存:
顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存。 共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效 的方式。不同进程之间共享的内存通常安排为同一段物理内存。进程可以 将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共 享内存中的地址
无须复制,共享缓冲区直接付附加到进程虚拟地址空间,速度快;
缺点: 通信需要设计复杂的机制保证各个进程通讯有效性。进程间的同步 问题操作系统无法实现,必须各进程利用同步工具解决;
安全问题比较 突出,如果 Android 采用 Binder 无异于将每个 App 放在一个内存中,这 样是非常不安全的
**4.套接字:**作为更通用的接口,传输效率低,主要用于不通机器或跨网络的通信;
**5.信号量:**常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访 问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
6.信号: 不适用于信息交换,更适用于进程中断控制,比如非法内存访问,杀死 某个进程等; 接下来正面回答这个问题,从 5 个角度来展开对 Binder 的分析:
**(1) 从性能的角度 数据拷贝次数:**Binder 数据拷贝只需要一次,而管道、消息 队列、Socket 都需要 2 次,但共享内存方式一次内存拷贝都不需要;从性能角 度看,Binder 性能仅次于共享内存
(2) 从稳定性的角度Binder 是基于 C/S 架构的,简单解释下 C/S 架构,是指客 户端(Client)和服务端(Server)组成的架构,Client 端有什么需求,直接发送给 Server 端去完成,架构清晰明朗,Server 端与 Client 端相对独立,稳定性较好; 而共享内存实现方式复杂,没有客户与服务端之别, 需要充分考虑到访问临界 资源的并发同步问题,否则可能会出现死锁等问题;从这稳定性角度看,Binder 架构优越于共享内存。
仅仅从以上两点,各有优劣,还不足以支撑 google 去采用 binder 的 IPC 机制
(3) 从安全的角度 传统 Linux IPC 的接收方无法获得对方进程可靠的 UID/PID, 从而无法鉴别对方身份;而 Android 作为一个开放的开源体系,拥有非常多的开 发平台,App 来源甚广,因此手机的安全显得额外重要;对于普通用户,绝不希 望从 App 商店下载偷窥隐射数据、后台造成手机耗电等等问题,传统 Linux IPC 无任何保护措施,完全由上层协议来确保。
Android 为每个安装好的应用程序分配了自己的 UID,故进程的 UID 是鉴别进程 身份的重要标志,前面提到 C/S 架构,**Android 系统中对外只暴露 Client 端, Client 端将任务发送给 Server 端,Server 端会根据权限控制策略,判断 UID/PID 是否满足访问权限,目前权限控制很多时候是通过弹出权限询问对话框,让用 户选择是否运行。**Android 6.0,也称为 Android M,在 6.0 之前的系统是在 App 第一次安装时,会将整个 App 所涉及的所有权限一次询问,只要留意看会发现 很多 App 根本用不上通信录和短信,但在这一次性权限权限时会包含进去,让 用户拒绝不得,因为拒绝后 App 无法正常使用,而一旦授权后,应用便可以胡 作非为。
针对这个问题,google 在 Android M 做了调整,不再是安装时一并询问所有权 限,而是在 App 运行过程中,需要哪个权限再弹框询问用户是否给相应的权限,对权限做了更细地控制,让用户有了更多的可控性,但**同时也带来了另一个用 户诟病的地方,那也就是权限询问的弹框的次数大幅度增多。**对于 Android M 平台上,有些 App 开发者可能会写出让手机异常频繁弹框的 App,企图直到用 户授权为止,这对用户来说是不能忍的,用户最后吐槽的可不光是 App,还有 Android 系统以及手机厂商,有些用户可能就跳果粉了,这还需要广大 Android 开发者以及手机厂商共同努力,共同打造安全与体验俱佳的 Android 手机。
传统 IPC 只能由用户在数据包里填入 UID/PID;另外,可靠的身份标记只有由 IPC 机制本身在内核中添加。其次传统 IPC 访问接入点是开放的,无法建立私有通道。 从安全角度,Binder 的安全性更高。 说到这,可能有人要反驳,Android 就算用了 Binder 架构,而现如今 Android 手机的各种流氓软件,不就是干着这种偷窥隐射,后台偷偷跑流量的事吗?没错, 确实存在,但这不能说 Binder 的安全性不好,因为 Android 系统仍然是掌握主 控权,可以控制这类 App 的流氓行为,只是对于该采用何种策略来控制,在这 方面 android 的确存在很多有待进步的空间,这也是 google 以及各大手机厂商 一直努力改善的地方之一。在 Android 6.0,google 对于 app 的权限问题作为较 多的努力,大大收紧的应用权限;另外,在Google 举办的 Android Bootcamp 2016 大会中,google 也表示在 Android 7.0 (也叫 Android N)的权限隐私方 面会进一步加强加固,比如 SELinux,Memory safe language(还在 research 中) 等等,在今年的 5 月 18 日至 5 月 20 日,google 将推出 Android N。 话题扯远了,继续说 Binder。
(4)从语言层面的角度 大家多知道 Linux 是基于 C 语言(面向过程的语言),而 Android 是基于 Java 语言(面向对象的语句),而对于 Binder 恰恰也符合面向对 象的思想,将进程间通信转化为通过对某个 Binder 对象的引用调用该对象的方 法,而其独特之处在于 Binder 对象是一个可以跨进程引用的对象,它的实体位 于一个进程中,而它的引用却遍布于系统的各个进程之中。可以从一个进程传给 其它进程,让大家都能访问同一 Server,就像将一个对象或引用赋值给另一个引 用一样。Binder 模糊了进程边界,淡化了进程间通信过程,整个系统仿佛运行于 同一个面向对象的程序之中。从语言层面,Binder 更适合基于面向对象语言的 Android 系统,对于 Linux 系统可能会有点“水土不服”。
另外,Binder 是为 Android 这类系统而生,而并非 Linux 社区没有想到 Binder IPC 机制的存在,对于 Linux 社区的广大开发人员,我还是表示深深佩服,让世 界有了如此精湛而美妙的开源系统。也并非 Linux 现有的 IPC 机制不够好,相 反地,经过这么多优秀工程师的不断打磨,依然非常优秀,每种 Linux 的 IPC 机制都有存在的价值,同时在 Android 系统中也依然采用了大量 Linux 现有的 IPC 机制,根据每类 IPC 的原理特性,因时制宜,不同场景特性往往会采用其下 最适宜的。比如在 Android OS 中的 Zygote 进程的 IPC 采用的是 Socket(套 接字)机制,Android 中的 Kill Process 采用的 signal(信号)机制等等。而 Binder 更多则用在 system_server 进程与上层 App 层的 IPC 交互。
(5) 从公司战略的角度
总所周知,Linux 内核是开源的系统,所开放源代码许可协议 GPL 保护,该协议 具有“病毒式感染”的能力,怎么理解这句话呢?受 GPL 保护的 Linux Kernel 是运行在内核空间,对于上层的任何类库、服务、应用等运行在用户空间,一旦进行 SysCall(系统调用),调用到底层 Kernel,那么也必须遵循 GPL 协议。
而 Android 之父 Andy Rubin 对于 GPL 显然是不能接受的,为此,Google 巧妙 地将 GPL 协议控制在内核空间,将用户空间的协议采用 Apache-2.0 协议(允许 基于 Android 的开发商不向社区反馈源码),同时在 GPL 协议与 Apache-2.0 之 间的 Lib 库中采用 BSD 证授权方法,有效隔断了 GPL 的传染性,仍有较大争议, 但至少目前缓解 Android,让 GPL 止步于内核空间,这是 Google 在 GPL Linux 下 开源与商业化共存的一个成功典范。
有了这些铺垫,我们再说说 Binder 的今世前缘
Binder 是基于开源的 OpenBinder 实现的,OpenBinder 是一个开源的系统 IPC 机制,最初是由 Be Inc.开发,接着由 Palm, Inc.公司负责开发,现在 OpenBinder 的作者在 Google 工作,既然作者在 Google 公司,在用户空间采用 Binder 作为 核心的 IPC 机制,再用 Apache-2.0 协议保护,自然而然是没什么问题,减少法 律风险,以及对开发成本也大有裨益的,那么从公司战略角度,Binder 也是不错 的选择。
另外,再说一点关于 OpenBinder,在 2015 年 OpenBinder 以及合入到 Linux Kernel 主线 3.19 版本,这也算是 Google 对 Linux 的一点回馈吧。
综合上述 5 点,可知 Binder 是 Android 系统上层进程间通信的不二选择。
最后
由于文章篇幅长度原因,暂且写到这了,后面还有更多丰富的干货更新,我已将后续更新内容整理成文档形式了,大家如果想要参考学习可以:https://qr18.cn/CgxrRy