Android系统 Binder机制浅析(一)
- 为什么需要跨进程通信(IPC)?
- 怎么做到跨进程通信?
- 为什么使用Binder?
(一)进程隔离
进程隔离是为了保护操作系统中进程互不干扰而设计的一组不同硬件和软件的技术。这个技术是为了防止进程A写入了进程B的情况发生。进程隔离的实现,使用了虚拟地址空间,进程A的虚拟地址和进程B的虚拟地址不相同;这样就防止进程A将数据写入了进程B中。
操作系统的不同进程之间,数据不共享;对于每个进程而言,它都天真的以为自己独享着整个系统,完全不知道其他进程的存在。
因此,如果一个进程需要与另一个进程进行通信,就需要有某种系统机制才能完成。
(二)用户空间/内核空间
Linux Kernel是操作系统的核心,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。
对于Kernel这么一个高安全级别的东西,显然是不容许其它的应用程序随便调用或访问的,所以需要对Kernel提供一定的保护机制,这个保护机制用来告诉那些应用程序,你只可以访问某些许可的资源,不许可的资源是拒绝被访问的,于是就把Kernel和上层的应用程序抽像的隔离开,分别称之为Kernel Space和User Space。
(三)系统调用/内核态/用户态
虽然从逻辑上抽离出用户空间和内核空间;但是不可避免的的是,总有那么一些用户空间需要访问内核的资源;比如应用程序访问文件,网络是很常见的事情,怎么办呢?
Kernel space can be accessed by user processes only through the use of system calls.用户空间访问内核空间的唯一方式就是系统调用;
通过这个统一入口接口,所有的资源访问都是在内核的控制下执行,以免导致对用户程序对系统资源的越权访问,从而保障了系统的安全和稳定。
当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态)。此时处理器处于特权级最高的(0级)内核代码中执行。当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。即此时处理器在特权级最低的(3级)用户代码中运行。处理器在特权等级高的时候才能执行那些特权CPU指令。
(四)内核模块/驱动
通过系统调用,用户空间可以访问内核空间,那么如果一个用户空间想与另外一个用户空间进行通信怎么办呢?很自然想到的是让操作系统内核添加支持;传统的Linux通信机制,比如Socket,管道等都是内核支持的;但是Binder并不是Linux内核的一部分,它是怎么做到访问内核空间的呢?Linux的动态可加载内核模块(Loadable Kernel Module,LKM)机制解决了这个问题;模块是具有独立功能的程序,它可以被单独编译,但不能独立运行,它在运行时被链接到内核作为内核的一部分在内核空间运行。这样,Android系统可以通过添加一个内核模块运行在内核空间,用户进程之间的通过这个模块作为桥梁,就可以完成通信了。
(驱动程序一般指的是设备驱动程序(Device Driver),是一种可以使计算机和设备通信的特殊程序。相当于硬件的接口,操作系统只有通过这个接口,才能控制硬件设备的工作)
(五)为什么使用Binder?
Android使用的Linux内核拥有着非常多的跨进程通信机制,比如管道,System V,Socket等;
为什么还需要单独搞一个Binder出来呢?主要有两点,性能和安全。
在移动设备上,广泛地使用跨进程通信肯定对通信机制本身提出了严格的要求;Binder相对于传统的Socket方式,更加高效;另外,传统的进程通信方式对于通信双方的身份并没有做出严格的验证,只有在上层协议上进行架设;比如Socket通信ip地址是客户端手动填入的,都可以进行伪造;而Binder机制从协议本身就支持对通信双方做身份校检,因而大大提升了安全性。这个也是Android权限模型的基础。
Android系统Binder机制中的四个组件Client、Server、Service Manager和Binder驱动程序的关系如下图所示: