AndroidBinder机制

Android Binder


自己写的一个进程间通信例子https://github.com/dechaow/AIDLDemo



Android中为了保护操作系统中进程互不干扰设计了进程隔离机制,这个技术是为了防止进程A写入进程B的情况发生。进程隔离的实现,使用了虚拟地址空间,进程A的虚拟地址和进程B的虚拟地址不同,这样就防止进程A将数据信息写入进程B


虚拟地址和物理地址是一种映射关系,程序中使用的都是虚拟地址


Linux系统内存分为两个部分:内核空间和用户空间。内核空间是内核(即操作系统的核心)执行(即运行)并提供其服务的位置


用户空间是用户进程(即除内核以外的一切)运行的那组内存位置。进程是程序的执行示例,内核的一个角色是管理此空间内的各个用户进程,并防止它们彼此干扰


Linux Kernel是操作系统的核心,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限


用户进程只能通过使用系统调用来访问内核空间。系统调用是类似Unix的操作系统中由内核执行的服务的活动的请求。


Kernel space can be accessed by user processes only through the use of system calls.


Linux的7种运行级别:


运行级别0:系统停机状态,系统默认运行级别不能设为0,否则不能正常   启动


运行级别1:单用户工作态,root权限,用于系统维护,机制远程登录


运行级别2:多用户运行态(没有NFS)


NFS:Network File System 网络文件系统


运行级别3:完全的用户状态(有NFS),登录后进入控制台命令行模式


运行级别4:系统未使用,保留


运行级别5:X11控制台,登录后进入图形GUI模式


运行级别6:系统正常关闭并重启,默认运行级别不能设为6,否则不能正常启动




当一个任务执行系统调用而陷入内核代码中执行时,我们就成进程处于内核运行态(简称为内核态)此时处理器处于特权级最高的(0级)内核代码中执行。当进程在执行用户自己的代码时,则称其处于运行态(用户态)。即此时处理器在特权级最低的(3级)用户代码中运行。处理器在特权等级高的时候才能执行那些特权CPU命令


用户空间与用户空间进行通信:操作系统内核添加支持,传统的Linux通信机制有(Socket、管道、System V、共享内存);Android中是Binder


Linux的动态可加载内核模块(Loadable Kernel Module,LKM)机制:模块是具有独立功能的程序,它可以单独被编译,但不能独立运行,它在运行时被连接到内核作为内核的一部分在内核空间运行。这样Android系统可以通过一个内核模块运行在内核空间,用户进程之间通过这个模块作为桥梁,就可以进行通信了。


在Android中,这个运行在内核空间的,负责各个用户进程通过Binder通信的内核模块叫做Binder驱动


驱动程序一般指的是设备驱动程序(Diver Diver),是一种可以使计算机和设备通信的特殊程序,相当于硬件的接口,操作系统只有通过这个接口,才能控制硬件设备的工作。


驱动就是操作硬件的接口,为了支持Binder通信过程,Binder使用了一种“硬件”,因此这个模块被称之为驱动


Binder的优点(性能和安全方面):Binder相对于传统的Socket方式,更加高效,另外传统的通信方式对于双方的身份并没有做出严格的验证,只有在上层协议上进行架设,而Binder机制从协议本身就支持对通信双方进行身份校验,Android为每个应用程序都分配了自己的UID来作为鉴别进程身份的重要标志。大大的提升了安全性。传统的IPC只能由用户在数据包里填入UID和PID,不够可靠。


Binder基于Client-Server通信模型,传输只需要一次拷贝,为发送方添加UID/PID身份,既支持实名Binder又支持匿名Binder,安全性高。


Binder通信模型:


Client Server ServiceManager Binder驱动


做一个打电话的比喻,如果A要给B打电话,首先要有B的电话号码,而电话号码存在通讯录里面,这里的ServiceManager就相当于通讯录,但是只有电话号码还是不能打通的,还需要有基站,Binder在这里就相当于是基站的性质


整个完整的步骤如下:


1 ServiceManager的建立,首先,有一个进程向驱动提出申请为ServiceManager,驱动同意后,ServiceManager进程负责管理Service。ServiceManager的注册方式也是通过Binder机制来进行的,只不过它比较特殊,当一个进程使用用BINDER_SET_CONTEXT_MGR命令将自己注册成ServiceManager时Binder驱动会自动为它创建Binder实体,这个进程就是的ServiceManager,然后ServiceManager充当Server,其他进程都是Client


2 各个Server向ServiceManager注册,每个Server端进程启动之后,向ServiceManager进行注册自己的名字和返回对应的地址,然后这时候ServiceManager就存了很多进程的名字和地址,如果想要通信需要调用ServiceManager查询对应的地址


3 Client和Server想要通信,首先询问ServiceManager,然后查询后返回地址,就可以和Server进行通信了。


Binder驱动在这里起着最重要的关系


Binder跨进程原理:


用户空间想要操作内核空间,需要通过两个系统调用:copy_from_user,copy_to_user.


假设Client想要调用Server的object对象的add方法:


首先Server向ServiceManager注册,然后Client向ServiceManager查询这个Server,我们知道,进程间的通信都会经过运行在内核里面的驱动,驱动在数据流过的时候做了一点手脚,它并不会返回一个真正的object对象而是一个objectProxy,这objectProxy也有一个add方法,但是这并不是真正的object对象,objectProxy做的事情就是把参数包装然后交给驱动。
但是Client进程并不知道这个对象并不是真正的object对象,然后就当作是真的object对象调用它的add方法,然后这个add方法就会发消息给驱动,驱动收到消息发现是objectProxy的方法,就知道这个Client想要调用的是Server的object对象,然后驱动就会通知Server,调用你的object对象的add方法,然后把结果返回给我,然后Server进程收到这个消息,照做之后将结果返回给驱动,驱动然后把结果返回给Client进程。整个过程就完成了。


由于objectProxy与Server进程里面原始的object如此相似,给我们的感觉就是直接将Server中的object对象传递到了Client进程,所以,我们可以说Binder对象是可以进行跨进程传递的对象。但是其实这里用的是代理模式。


实际上。由于我们Server向ServiceManager注册时也是跨进程通信,驱动当然也会对这个过程进行暗箱操作。ServiceManager端存在的Server对象其实也是代理对象。后面Client向ServiceManager查询的时候,驱动会给Client返回另外一个代理对象。Server进程的本地对象只会有一个,其他进程所拥有的都是它的代理。


Binder到底是什么:


Binder的设计采用了面向对象的思想,在Binder通信模型的四个角色里。它们的代表都是“Binder”,这样对于Binder通信的使用者而言,Server里面的Binder和Client里面的Binder没有什么不同,一个BInder对象就代表了所有,它不用关心实现的细节。甚至不用关心驱动以及ServiceManager的存在,这就是抽象。


通常我们说的Binder指的是一种通信机制,我们说AIDl使用Binder进行通信,指的就是Binder这种IPC机制


对于Server进程来说,Binder指的是Binder本地对象。


对于Client来说,Binder指的是代理对象。


对于传输过程而言,Binder是可以进行跨进程传递的对象。


驱动里面的Binder


在驱动中,Binder本地对象的代表是一个binder_node的数据结构,Binder代理对象是binder_ref代表的,有的地方把Binder本地对象直接称作Binder实体,把Binder的代理对象称作为Binder引用,其实就是说的是Binder对象在驱动里面的表现形式








©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页