初探Android中的binder机制 下载本文

内容发布更新时间 : 2024/11/8 21:30:22星期一 下面是文章的全部内容请认真阅读。

典型代表就是App中通过aidl实现的service组件。

aidl实际上帮我们完整实现了服务代理类,以及是是实现了binder服务类中与语义处理相关的所有操作,例如方法编号的分配,方法参数从parcel中的提取,以及返回值打入parcel中等所有的操作。开发者只需要实现服务接口即可。

因为app是没有权限向ServiceManager注册服务的,那么怎么获取app中的额service实体的引用binder呢???

那就是直接传递binder实体,将binder实体对象打入到Parcel中,跨进程传入到AMS中去。

Binder实体在Binder驱动中的传输,会被特殊处理,最终返回到AMS中的是一个binder引用对象。(详细过程后续在分析喽!!!)

其他App进程中的组件便可以通过AMS拿到要请求的service服务的binder引用对象了。要注意的是,此过程中是AMS将所请求的binder服务的引用对象打入Parcel,然后通过Binder驱动传递到请求者进程中。

简单的说就是Binder实体对象的传递过程,伴随着binder服务在Binder驱动中相关数据结构初始化以及binder引用对象的创建过程。

不通过aidl实现一个service,来熟悉一下整个过程:

1. 首先顶定义一个服务接口,即服务要对外提供哪些方法。

IBinderService.java:

publicinterfaceIBinderServiceextendsIInterface{

String getMessage();

/**

* 服务的描述,客户端在使用parcel跨进程传输数据的时候

* 必须首先写入服务的描述,即该数据是发给哪个binder的。

* 将来服务端收到数据后会检查这个服务描述是否和自己的一致,不一致就不做处理了

*/

String DESCRIPITON = \;

// 定义方法编号

int GET_MESSAGE = IBinder.FIRST_CALL_TRANSACTION+0;

}

binder服务接口必须继承自IInterface接口,该接口中只有一个方法:

public IBinder asBinder()

binder服务接口一般要包含三部分内容:

首先是该binder服务的描述DESCRIPITON,发送数据时必须先发送该描述,接收数据时必须先对该描述进行检查,和自己不匹配的话那就不用继续进行了。

然后是方法编号,这个编号实际含义要在binder实体对象中的onTransact()方法中才能体现出来。可以理解为onTransact()根据这个编号调用不同的处理分支。

最后就是该服务对外提供的具体方法声明了。

binder实体端和代理对象端必须都继承这个服务接口,并实现其中的方法。另外服务端还要重载binder的onTransact()方法。

2. 实现bidner服务端

binder服务端的重点在于实现onTransact()方法,该方法中会依据客户端传入的方法编号,调用恰当的分支进行处理。

处理过程也是很简单的,就是从parcel中解析参数,调用对应的方法执行,将执行结果打入parcel中。

publicclassBinderServiceStubextendsBinderimplementsIBinderService{

publicBinderServiceStub(){

// 调用该方法后binder实体端的binder.queryLocalInterface()

// 返回就不会为null。

attachInterface(this,DESCRIPITON);

}

// 实现服务接口方法

public String getMessage() {

return\i am from Message!!!!!\;

}

/**

* 顾名思义,将自身转换为一个IBinder对象,

* 因为Binder继承子Binder,Binder继承自IBinder

*/

@Override

public IBinder asBinder() {

returnthis;

}

@Override

protectedbooleanonTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {

switch (code){

case GET_MESSAGE:{

// 客户端先发送的是服务描述,所以这里先接收服务描述并判断是否和自己一致

data.enforceInterface(DESCRIPITON);

// 开始执行客户端请求的服务端的方法

String msg = getMessage();

// 将结果打入Parcel

reply.writeNoException();

reply.writeString(msg);

returntrue;

}

}

/**