图⽂详解AndroidBinder跨进程通信机制原理
⽬录
⽬录
1. Binder到底是什么?
中⽂即粘合剂,意思为粘合了两个不同的进程
⽹上有很多对Binder的定义,但都说不清楚:Binder是跨进程通信⽅式、它实现了IBinder接⼝,是连接ServiceManager的桥梁blabla,估计⼤家都看晕了,没法很好的理解我认为:对于Binder的定义,在不同场景下其定义不同
定义
在本⽂的讲解中,按照⼤⾓度 -> ⼩⾓度去分析Binder,即:
先从机制、模型的⾓度去分析整个Binder跨进程通信机制的模型
其中,会详细分析模型组成中的Binder驱动
再从源码实现⾓度,分析Binder在Android中的具体实现
从⽽全⽅位地介绍Binder,希望你们会喜欢。
2. 知识储备
在讲解Binder前,我们先了解⼀些基础知识
2.1 进程空间分配
⼀个进程空间分为⽤户空间 & 内核空间(Kernel),即把进程内⽤户 & 内核隔离开来
⼆者区别:
1. 进程间,⽤户空间的数据不可共享,所以⽤户空间 = 不可共享空间
2. 进程间,内核空间的数据可共享,所以内核空间 = 可共享空间
进程内⽤户与内核进⾏交互称为系统调⽤
⽰意图
2.2 进程隔离
为了保证安全性 & 独⽴性,⼀个进程不能直接操作或者访问另⼀个进程,即Android的进程是相互独⽴、隔离的2.3 跨进程通信(IPC)
隔离后,由于某些需求,进程间需要合作 / 交互
跨进程间通信的原理
1. 先通过进程间的内核空间进⾏数据交互
2. 再通过进程内的⽤户空间 & 内核空间进⾏数据交互,从⽽实现进程间的⽤户空间的数据交互
⽰意图
⽽Binder,就是充当连接两个进程(内核空间)的通道。
3. Binder 跨进程通信机制模型
3.1 模型原理
Binder跨进程通信机制模型基于Client - Server模式,模型原理图如下:
相信我,⼀张图就能解决问题
⽰意图
3.2 额外说明
说明1:Client进程、Server进程 & Service Manager进程之间的交互都必须通过Binder驱动(使⽤open和ioctl⽂件操作函数),⽽⾮直接交互 **
原因:
1. Client进程、Server进程 & Service Manager进程属于进程空间的⽤户空间,不可进⾏进程间交互
2. Binder驱动属于进程空间的内核空间,可进⾏进程间 & 进程内交互
所以,原理图可表⽰为以下:
虚线表⽰并⾮直接交互
⽰意图
说明2:Binder驱动 & Service Manager进程属于Android基础架构(即系统已经实现好了);⽽Client进程和Server进程属于Android应⽤层(需要开发者⾃⼰实现)
所以,在进⾏跨进程通信时,开发者只需⾃定义Client & Server进程并显式使⽤上述3个步骤,最终借助Android的基本架构功能就可完成进程间通信
⽰意图
说明3:Binder请求的线程管理
Server进程会创建很多线程来处理Binder请求
管理Binder模型的线程是采⽤Binder驱动的线程池,并由Binder驱动⾃⾝进⾏管理
⽽不是由Server进程来管理的
⼀个进程的Binder线程数默认最⼤是16,超过的请求会被阻塞等待空闲的Binder线程。
所以,在进程间通信时处理并发问题时,如使⽤ContentProvider时,它的CRUD(创建、检索、更新和删除)⽅法只能同时有16个线程同时⼯作
⾄此,我相信⼤家对Binder跨进程通信机制模型已经有了⼀个⾮常清晰的定性认识
下⾯,我将通过⼀个实例,分析Binder跨进程通信机制模型在Android中的具体代码实现⽅式
即分析上述步骤在Android中具体是⽤代码如何实现的
4. Binder机制在Android中的具体实现原理
Binder机制在Android中的实现主要依靠Binder类,其实现了IBinder接⼝
下⾯会详细说明
实例说明:Client进程需要调⽤Server进程的加法函数(将整数a和b相加)
即:
1. Client进程需要传两个整数给Server进程
2. Server进程需要把相加后的结果返回给Client进程
具体步骤
下⾯,我会根据Binder跨进程通信机制模型的步骤进⾏分析
步骤1:注册服务
过程描述
Server进程通过Binder驱动向Service Manager进程注册服务
代码实现
Server进程创建⼀个Binder对象
1. Binder实体是Server进程在Binder驱动中的存在形式
2. 该对象保存Server和ServiceManager的信息(保存在内核空间中)
3. Binder驱动通过内核空间的Binder实体到⽤户空间的Server对象
代码分析
Binder binder = new Stub();
// 步骤1:创建Binder对象 ->>分析1
// 步骤2:创建 IInterface 接⼝类的匿名类
// 创建前,需要预先定义继承了IInterface 接⼝的接⼝ -->分析3
IInterface plus = new IPlus(){
/
/ 确定Client进程需要调⽤的⽅法
public int add(int a,int b) {
return a+b;
}
// 实现IInterface接⼝中唯⼀的⽅法
public IBinder asBinder(){
return null ;
}
};
// 步骤3
binder.attachInterface(plus,"add two int");
/
/ 1. 将(add two int,plus)作为(key,value)对存⼊到Binder对象中的⼀个Map<String,IInterface>对象中
// 2. 之后,Binder对象可根据add two int通过queryLocalIInterface()获得对应IInterface对象(即plus)的引⽤,可依靠该引⽤完成对请求⽅法的调⽤ // 分析完毕,跳出
<-- 分析1:Stub类 -->
public class Stub extends Binder {
// 继承⾃Binder类 ->>分析2
// 复写onTransact()
@Override
boolean onTransact(int code, Parcel data, Parcel reply, int flags){
// 具体逻辑等到步骤3再具体讲解,此处先跳过
switch (code) {
case Stub.add: {
int arg0 = adInt();
int arg1 = adInt();
int result = this.queryLocalIInterface("add two int") .add( arg0, arg1);
reply.writeInt(result);
return true;
}
}
Transact(code, data, reply, flags);
}
/
/ 回到上⾯的步骤1,继续看步骤2
<-- 分析2:Binder 类 -->
public class Binder implement IBinder{
// Binder机制在Android中的实现主要依靠的是Binder类,其实现了IBinder接⼝
// IBinder接⼝:定义了远程操作对象的基本接⼝,代表了⼀种跨进程传输的能⼒
// 系统会为每个实现了IBinder接⼝的对象提供跨进程传输能⼒
// 即Binder类对象具备了跨进程传输的能⼒
void attachInterface(IInterface plus, String descriptor);
// 作⽤:
// 1. 将(descriptor,plus)作为(key,value)对存⼊到Binder对象中的⼀个Map<String,IInterface>对象中
/
/ 2. 之后,Binder对象可根据descriptor通过queryLocalIInterface()获得对应IInterface对象(即plus)的引⽤,可依靠该引⽤完成对请求⽅法的调⽤ IInterface queryLocalInterface(Stringdescriptor) ;
// 作⽤:根据参数 descriptor 查相应的IInterface对象(即plus引⽤)
boolean onTransact(int code, Parcel data, Parcel reply, int flags);
// 定义:继承⾃IBinder接⼝的
// 作⽤:执⾏Client进程所请求的⽬标⽅法(⼦类需要复写)
// 参数说明:
// code:Client进程请求⽅法标识符。即Server进程根据该标识确定所请求的⽬标⽅法
// data:⽬标⽅法的参数。(Client进程传进来的,此处就是整数a和b)进程间通信和线程间通信的区别
// reply:⽬标⽅法执⾏后的结果(返回给Client进程)
// 注:运⾏在Server进程的Binder线程池中;当Client进程发起远程请求时,远程请求会要求系统底层执⾏回调该⽅法
final class BinderProxy implements IBinder {
// 即Server进程创建的Binder对象的代理对象类
// 该类属于Binder的内部类
}
// 回到分析1原处
}
<-- 分析3:IInterface接⼝实现类 -->
public interface IPlus extends IInterface {
// 继承⾃IInterface接⼝->>分析4
// 定义需要实现的接⼝⽅法,即Client进程需要调⽤的⽅法
public int add(int a,int b);
/
/ 返回步骤2
}
<-- 分析4:IInterface接⼝类 -->
// 进程间通信定义的通⽤接⼝
// 通过定义接⼝,然后再服务端实现接⼝、客户端调⽤接⼝,就可实现跨进程通信。
public interface IInterface
{
// 只有⼀个⽅法:返回当前接⼝关联的 Binder 对象。
public IBinder asBinder();
}
// 回到分析3原处
注册服务后,Binder驱动持有Server进程创建的Binder实体
步骤2:获取服务
Client进程使⽤某个service前(此处是相加函数),须通过Binder驱动向ServiceManager进程获取相应的Service信息
具体代码实现过程如下:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论