安卓跨进程通信:Binder解析

Binder

从机制、模型角度分析:
Binder是一种安卓中实现跨进程通信(IPC)的方式(即Binder机制模型)
作用:在安卓中实现跨进程通信

从模型的结构、组成来说:
Binder是一种虚拟的物理设备驱动(即Binder驱动)
作用:连接Service进程、Client进程和ServiceManager进程

从安卓代码实现角度来说:
Binder是一个类,实现了IBinder接口(即Binder类)
作用:将Binder机制模型以代码的形式具体体现在安卓中

基础知识

Linux进程空间划分

一个进程空间分为用户空间、内核空间
用户空间:进程间,用户空间中的数据不可共享
内核空间:进程间,内核空间可共享,所有进程共用一个内核空间
进程间用户空间和内核空间交互需要进行系统调用(copy_from_user()将用户空间的数据拷贝到内核空间,copy_to_user()将内核空间数据拷贝到用户空间)

进程隔离、跨进程通信(IPC)

进程隔离 为了保证进程安全性、独立性,一个进程不能直接操作或访问另一个进程,即安卓的进程是相互独立、隔离的
跨进程通信 即进程间进行数据交互、通信
基本原理:
①发送进程通过系统调用,将需要发送的数据拷贝到Linux进程的内核空间的缓存区中(copy_from_user)
②内核服务程序唤醒接收进程,通过系统调用将数据发送到接收进程的用户空间,完成数据发送(copy_to_user)
缺点:①效率低:数据需要进行两次拷贝
②接收方无法知道需要开辟多大的空间才能接收下来数据(所以通常接收方会开辟尽量大的空间或先获取消息头,了解大小再接收;前者浪费空间,后者浪费时间)

Binder优势 ①Binder连接两个进程,实现mmap()系统调用,主要负责数据接收的缓存空间与管理
②上述说传递需要两次数据拷贝,而Binder只需要一次(用到内存映射)

内存映射

定义

关联进程中的一个虚拟内存区域和一个磁盘上对象,产生映射关系
注:①上述映射过程实际就是初始化该虚拟内存区
②虚拟内存区域被初始化后,会在交换空间中换来换去
③被映射的磁盘对象称为:共享对象

作用

当上述映射关系成立后,则
在多个进程的虚拟内存区域 和同一个对象建立映射的时候:若一个进程对虚拟区域进行写操作,对于其他将该共享对象映射到自身虚拟内存区域的进程,该进程的写操作也是可见的

实例:假设进程A、B的虚拟内存区域同时映射到同一个共享对象,那么当进程A对其虚拟内存区域进行写操作,该操作也会同步映射到进程B的虚拟内存区域

实现过程

主要通过Linux系统下的mmap(),该函数用于创建虚拟内存区域+与共享对象建立映射关系

特点

提高数据读、写与传输时间性能
①减少了数据拷贝次数
②用户空间与内核空间高效交互(通过映射直接交互)
③用内存读写代替I/O读写
提高内存利用率 通过虚拟内存+共享对象

Binder跨进程通信机制、模型

模型原理:

基于CS模式:
①Server进程向Binder驱动注册服务
②Client进程向Binder驱动获取并使用服务

模型组成

①Client进程:使用服务的进程(客户端)
②Server进程:提供服务的进程(服务器端)
③ServiceManager进程:管理Service注册与查询(类似路由器)
④Binder驱动:虚拟设备驱动,连接上述三者;通过内存映射传递进程数据、采用Binder的线程池进行线程控制(由Binder驱动自身进程线程管理);Binder驱动持有每个Server进程在内核空间中的Binder实体,并且给Client进程提供Binder实体的引用

Binder驱动跨进程通信核心
工作流程:
①Binder驱动创建一块接收缓存区
②实现地址映射关系:根据需映射的接收进程信息,实现内核缓存区(先前不用Binder时,用于中介传输数据的空间)和接收进程用户空间地址同时映射到一个共享接收缓存区
③发送进程通过系统调用copy_from_user()发送数据到虚拟内存区域
④由于内核缓存区与接收进程的用户空间地址存在映射关系(同时映射到Binder创建的接收缓存区),故相当于第三步也发送到了接收进程的用户空间地址,实现跨进程通信

注:实际就是发送进程在内核空间有内核缓存区,并且该缓存区与Binder创建的接收缓存区、接收进程用户空间三者互成映射关系,所以只要发送进程对内核缓存区有操作,接收进程就能同步获取该变动;发送进程只需要将需要发送的内容从用户空间拷贝到内核缓存区即可实现通信

模型原理步骤

注册服务
①Server进程向Binder驱动发起服务注册请求
②Binder驱动将注册请求转发给ServiceManager进程
③ServiceManager进程添加该Server进程(已注册)

获取服务
①Client向Binder驱动发起获取服务的请求,传递要获取的服务名称
②Binder驱动将该请求转发给ServiceManager进程
③ServiceManager查找到该Client需要的Server并返回对应信息
④通过Binder驱动将上述服务信息发送给Client进程

使用服务
①Binder驱动为跨进程通信做准备(实现内存映射)
a.Binder驱动创建接收缓存区
b.实现地址映射关系:依据从ServiceManager获取的Server进程信息,实现内核缓存区+Server进程用户控件地址两者通过接收缓存区映射起来

②Client进程将参数数据发送到Server进程
a.Client进程通过系统调用copy_from_user发送数据到内核缓存区(因为映射关系的建立,这一步相当于也发送到了Binder接收缓存区+接收进程的用户空间)
b.Binder驱动通知Server进程执行解包

③Server进程依据Client进程要求调用目标方法
a.Server进程收到Binder驱动通知后,Server进程从线程池中取出线程,进行解包+调用目标方法
b.将最终执行结果写入自己的共享内存

④Server进程将目标方法执行结果返回给Client进程
a.Server进程将结果写入存在映射的用户空间内存区域(同上述2.a,此处通过映射在三个位置同步发生操作)
b.Binder驱动通知Client进程获取返回结果
c.Client进程通过系统调用copy_to_user()从内核缓存区接收Server进程返回的数据

额外说明

Client进程、Server进程、ServiceManager进程间的交互都需要通过Binder驱动,并非直接交互
因为Client进程、Server进程、ServiceManager进程都处于进程控件中的用户空间,不可以跨进程交互;Binder进程属于内核空间,可以跨进程

Binder驱动与ServiceManager进程属于安卓基础架构(系统已经实现),而Client进程与Server进程属于安卓应用层(需要额外开发)

Binder请求的线程管理
①Server进程会创建很多线程处理Binder请求
②Binder模型的线程管理采用Binder驱动的线程池,并且由Binder驱动自身管理
③一个进程Binder线程数默认最大16,超过则会被阻塞等待

你可能感兴趣的:(安卓,android,网络,linux)