使用aidl
首先看下应用使用aidl时的代码:
①在服务端和客户端创建aidl文件
服务端
// IMyAidlInterface.aidl
package aidl.com.example.test;
interface IMyAidlInterface {
void hi(String s);
String bye(int s);
void hello(int s);
}
客户端
// IMyAidlInterface.aidl
package aidl.com.example.test;
interface IMyAidlInterface {
void hi(String s);
String bye(int s);
void hello(int s);
}
两端的代码保持一致,包括包名和声明的方法(包含参数)一致,切aidl文件的存放位置,需要客户端和服务端存放在的相同的包名下。
如图
②make-project
点< make project >按钮使as根据aidl文件创建出所需要的与framework调渡的java文件
③ 服务端 实现在aidl中声明的方法
⑥客户端绑定服务,获取服务binder代理实例
private void bindService() {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.aidlserver", "MyService"));
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (iMyAidlInterface != null){
//服务断开
iMyAidlInterface.asBinder().unlinkToDeath(this, 0);
iMyAidlInterface = null;
}
//服务重连
bindService();
}
};
private IMyAidlInterface iMyAidlInterface;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获得服务binder实例
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
try {
//服务生命监听
service.linkToDeath(deathRecipient,0);
} catch (RemoteException e) {
e.printStackTrace();
}
try {
iMyAidlInterface.hi("");
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
< make project> AS自动生成的代码
首先预览下自动生成的代码的类关系图
服务端实现服务方法
在AS 新建好aidl文件后,服务端实现IMyAidlInterface.Stub()方法,进而实现第一步在aidl声明的方法。
那么从IMyAidlInterface.Stub()开始入手:
public static abstract class Stub extends android.os.Binder implements aidl.com.example.test.IMyAidlInterface
{
private static final java.lang.String DESCRIPTOR = "aidl.com.example.test.IMyAidlInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
//调用attachInterface将 此stub 实例与DESCRIPTOR进行关联
this.attachInterface(this, DESCRIPTOR);
}
...
在binder.java中attachInterface()将stub 实例与DESCRIPTOR进行关联,便于后续服务被绑定时,调用queryLocalInterface(),查询进程有没有已关联的binder实例
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
由于Stub类为抽象类,所以当实例化IMyAidlInterface.Stub时,需要实现相应的接口方法,如图
asBinder方法已在Stub类中实现,所以在我们自己实例化Stub类时不用必须实现asBinder()
public static abstract class Stub extends android.os.Binder implements aidl.com.example.test.IMyAidlInterface
{
...
@Override
public android.os.IBinder asBinder()
{
return this;
}
...
}
客户端绑定服务(获取服务)
前提引入:客户端在服务绑定时,传入ServiceConnection对象,绑定服务后该对象的onServiceConnected会回调IBinder实例,如下代码:
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//得到系统返回的iBinder对象后,传入IMyAidlInterface.Stub.asInterface()
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
try {
//服务生命监听
service.linkToDeath(deathRecipient,0);
} catch (RemoteException e) {
e.printStackTrace();
}
try {
//调用服务的方法
iMyAidlInterface.hi("");
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
接下来看看IMyAidlInterface.Stub.asInterface(service);里做了什么处理
public static abstract class Stub extends android.os.Binder implements aidl.com.example.test.IMyAidlInterface
{
...
public static aidl.com.example.test.IMyAidlInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
//查询该binder对象是否有绑定过DESCRIPTOR
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
//该binder对象有绑定过DESCRIPTOR, 则直接把该对象的类型转换为IMyAidlInterface后,即可返回该对象
if (((iin!=null)&&(iin instanceof aidl.com.example.test.IMyAidlInterface))) {
r eturn ((aidl.com.example.test.IMyAidlInterface)iin);
}
//若该binder对象没有绑定过DESCRIPTOR,这新建一个内部类Proxy返回出去
return new aidl.com.example.test.IMyAidlInterface.Stub.Proxy(obj);
}
...
}
接下来看看IMyAidlInterface.Stub.Proxy()构造方法:
private static class Proxy implements aidl.com.example.test.IMyAidlInterface
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
//返回mRemote实例
return mRemote;
}
...
}
小结
由上述代码中可得到:当客户端与服务端是同个进程时,asInterface()返回的binder实例是 IMyAidlInterface.Stub的实例,而当客户端与服务端不是同个进程时,asInterface()返回的binder实例是新建一个IMyAidlInterface.Stub.Proxy实例。
1、当客户端与服务端是同个进程时,asInterface()返回的binder实例是 IMyAidlInterface.Stub的实例,所以此时调用服务的方法时,并没有发生跨进程的传递事件:
2、当客户端与服务端不是同个进程时,asInterface()返回的binder实例是新建一个IMyAidlInterface.Stub.Proxy实例,所以此时调用服务的方法时,发生了跨进程的传递事件,这里需要看客户端的proxy类如何发送请求到服务端(应用层):
aidl的接口对应的方法编号:
IMyAidlInterface.java (IMyAidlInterface.Proxy.hi(String))
@Override public void hi(java.lang.String s) throws android.os.RemoteException
{
//获取包装类_data用于传入请求信息到服务端
android.os.Parcel _data = android.os.Parcel.obtain();
//获取包装类_reply用于接收服务端返回的信息
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
//描述请求服务端的信息(包名类名信息)
_data.writeInterfaceToken(DESCRIPTOR);
//传递服务方法的参数
_data.writeString(s);
//Stub.TRANSACTION_hi为调用的方法,为int类型,
//AS根据aidl的方法自动为这些方法进行编号,约定好某个数字对应调用服务端的某个方法
//后续依此传入_data, _reply
//如果方法正常执行,则返回true
boolean _status = mRemote.transact(Stub.TRANSACTION_hi, _data, _reply, 0);
//服务端方法执行异常,且客户端有默认实现该aidl的接口方法,则执行客户端的方法
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().hi(s);
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
调用mRemote.transact()后,经过framework-native-kernel-native-framework,后调度到服务端进程的Binder.onTransact()
服务端进程的Binder.onTransact()接下来继续看看:
IMyAidlInterface.java (IMyAidlInterface.Stub.onTransact())
...
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
java.lang.String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
//根据code跳转到对应的分支,这个方法编号是as编译自动生成
case TRANSACTION_hi: {
data.enforceInterface(descriptor);
java.lang.String _arg0;
//获取方法的参数
_arg0 = data.readString();
//调度服务端stub实例中实现的hi(String)
this.hi(_arg0);
reply.writeNoException();
//方法执行成功true返回
return true;
}
...
总结
如上述绑定服务和使用服务的过程,可类比为以下图: