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是如何解决上述两个问题
*第一个问题:
*客户端通过binderService和startService来启动服务
*bindService(service,conn,flags)和StartService(service)
*ServiceConnection{
*onServiceConnected(ComponentNamename,IBinderservice);
*}
*通过bind来绑定服务,如果service启动成功,ActivityManagerService就会调用ActivityThread类中的ApplicationThread对象,调用的参数中会包含service的Binder引用,然后再ApplicationThread中回调bindService中的conn接口,客户端可将其设为全局变量。
*第二个问题:
*Androidsdk中提供了aidl工具,可以把一个aidl文件转化成java类,其重载了transact和onTransact方法,统一了包裹存放和包裹读取的参数
*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();
}
}