android Binder讲解

Binder用于完成进程间通信(IPC),即把多个进程“别”在一起,从线程的角度来讲,Binder驱动代码运行在内核态,客户端程序调用Binder是通过系统调用完成的。Binder是一种架构,这种架构提供了服务端接口、Binder驱动、客户端接口三个模块。

 技术分享

重载onTransactO函数的主要内容是把onTmnSact()函数的参数转换为服务函数的参数,而onTransact()函数的参数来源是客户端调用transact()函数时输入的。

任意一个服务端Binder对象被创建时,同时会在Binder驱动中创建一个

mRemote对象,该对象的类型也是Binder类。客户端要访问远程服务时,都是通过mRemote对象。客户端似乎是直接调用远程服务对应的Binder,而事实上则是通过Binder驱动进行了中转。即存在两个Binder对象,一个是服务端的Binder对象,另一个则是Binder驱动中的Binder对象,所不同的是Binder驱动中的对象不会再额外产生一个线程。

服务端设计

Public class MusicPlayService extends Binder{
/**
* MusicPlayServicemusicPlayService=newMusicPlayService();会开启一个新线程
* code:是客户端与服务端约定的,代表变量存取的编号(多个变量公用一个编号)
* data:客户端数据存放
* replay:服务端返回的数据存放
* flag:IPC调用的模式
* 一种是双向,用常量0表示,其含义是服务端执行完指定服务后会返回一定的数据;
* 一种是单向,用常量1表示,其含义是不返回任何数据。
*/
@Override
Protected boolean onTransact(int code,Parcel data,Parcel reply,int flags) throws RemoteException{
switch(code){
case1000:
//为了某种校验,它与客户端的writeInterfaceToken()对应
data.enforceInterface("MusicPlayService");
String arg=data.readString();
String arg1 = data.readString();
break;
case2000:
data.enforceInterface("MusicPlayService");
arg=data.readString();
break;
}
returnsuper.onTransact(code,data,reply,flags);
}
publicvoidstart(){
}
publicvoidstop(){
}
 
}


Binder驱动

当创建一个Binder对象时,服务端进程内部创建一个Binder对象,Binder驱动中也会创建一个Binder对象。如果从远程获取服务端的Binder,则只会返回Binder驱动中的Binder对象,而如果从服务端进程内部获取Binder对象,则会获取服务端本身的Binder对象。

客户端设计

publicclassMusicPlayClient{

/**

* 两个问题:

* 1客户端如何获得服务端的Binder对象引用?

*为什么使用Binder为了提供一个全局服务,系统的任何应用程序都可以使用,解决方案就是用service服务

*  2客户端和服务端必须事先约定好两件事情:服务端函数的参数在包裹中的顺序、服务端不同函数的int型标识

*

*service是如何解决上述两个问题

*第一个问题:

*客户端通过binderServicestartService来启动服务

*bindService(service,conn,flags)StartService(service)

*ServiceConnection{

*onServiceConnected(ComponentNamename,IBinderservice);

*}

*通过bind来绑定服务,如果service启动成功,ActivityManagerService就会调用ActivityThread类中的ApplicationThread对象,调用的参数中会包含serviceBinder引用,然后再ApplicationThread中回调bindService中的conn接口,客户端可将其设为全局变量。

*第二个问题:

*Androidsdk中提供了aidl工具,可以把一个aidl文件转化成java类,其重载了transactonTransact方法,统一了包裹存放和包裹读取的参数

*Proxy:客户端访问服务端的代理,统一包裹参数写入的顺序

*Stub:由服务端使用

*当创建一个Binder对象时,服务端进程内部创建一个Binder对象,Binder驱动中也会创建一个Binder对象。如果从远程获取服务端的Binder,则只会返回Binder驱动中的Binder对象,而如果从服务端进程内部获取Binder对象,则会获取服务端本身的Binder

*/

Public void sendPacket()throwsRemoteException{

IBinde rmRemote=null;

String arg="agr0";

Parcel data=Parcel.obtain();

Parcel reply=Parcel.obtain();

data.writeInterfaceToken("MusicPlayService");//标注远程服务名称

data.writeString(arg);

Int flags=0;

/**

*客户端线程进入Binder驱动,Binder驱动就会挂起当前线程,并向远程服务发送一个消息,

*消息中包含了客户端传进来的包裹。服务端拿到包裹后,会对包裹进行拆解,然后执行指定的服务函数,

*执行完毕后,再把执行结果放入客户端提供的reply包裹中。然后服务端向Binder驱动发送一个notify的消息,

*从而使得客户端线程从Binder驱动代码区返回到客户端代码区。

*/

mRemote.transact(1,data,reply,flags);

IBinderbinder=reply.readStrongBinder();

data.recycle();

reply.recycle();

}

}

技术分享

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。