AIDL设计思路
AIDL
1.实现一个自定义的AIDL
// IMyService.aidl
package com.yetao.testaidl;
interface IMyService {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
上面声明了aidl接口、带基础数据类型的方法
2.IDE自动生成IMyService.java文件
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package com.yetao.testaidl;
// Declare any non-default types here with import statements
public interface IMyService extends android.os.IInterface {
/**
* IMyService的默认实现
*/
public static class Default implements com.yetao.testaidl.IMyService {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override
public int basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
return 0;
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
/**
* 本地IPC需要实现子类
*/
public static abstract class Stub extends android.os.Binder implements com.yetao.testaidl.IMyService {
private static final java.lang.String DESCRIPTOR = "com.yetao.testaidl.IMyService";
/**
* 构造函数,将标识符赋给当前对象
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
*将IBinder对象转换为com.yetao.testaidl.IMyService接口,并在需要时生成代理。
*/
public static com.yetao.testaidl.IMyService asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
//通过DESCRIPTOR查找本地是否有对应接口
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
//如果本地找到了,就返回
if (((iin != null) && (iin instanceof com.yetao.testaidl.IMyService))) {
return ((com.yetao.testaidl.IMyService) iin);
}
//没有的话,就构建远程代理对象
return new com.yetao.testaidl.IMyService.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@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;
}
case TRANSACTION_basicTypes: {
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0 != data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
int _result = this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.yetao.testaidl.IMyService {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
/**
* 演示一些基本类型,您可以将它们用作参数并在AIDL中返回值。
*/
@Override
public int basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean) ? (1) : (0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
boolean _status = mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().basicTypes(anInt, aLong, aBoolean, aFloat, aDouble, aString);
}
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public static com.yetao.testaidl.IMyService sDefaultImpl;
}
//方法对应Id,依次增加
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
public static boolean setDefaultImpl(com.yetao.testaidl.IMyService impl) {
if (Stub.Proxy.sDefaultImpl == null && impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static com.yetao.testaidl.IMyService getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
/**
* 演示一些基本类型,您可以将它们用作参数并在AIDL中返回值。
*/
public int basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
}
自动生成的java类,主要有以下几个功能:
1.生成接口类IMyService(实现了IInterface接口来转换成Binder对象)
2.生成一个默认实现类Default(IMyService的实现类)
3.生成本地IPC的实现类-Stub(Binder子类,实现IMyService接口),用于本地实现对应的Binder服务,避免不必要的远程IPC通信,同时也能兼顾本地提供服务
4.生成远端IPC的实现类-Proxy(实现IMyService接口),通过传入的远程Binder对象,调用transact()和远端通信,然后获取reply返回值
3.本地IPC-Stub本地的使用
public class AidlService extends Service {
private IMyService.Stub stub = new IMyService.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return stub;
}
}
上面主要做了:
1.继承IMyService.Stub,实现basicTypes方法
2.将stub对象赋值给Service的onBind()绑定,这也是为什么IMyService.Stub要继承Binder的原因,需要来兼容本地IPC
4.远端IPC使用
public class ClientActivity extends AppCompatActivity {
private IMyService aidlService;
private boolean connected;
private void bindMyService() {
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
aidlService = IMyService.Stub.asInterface(service);
connected = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
connected = false;
}
};
//远端访问应该使用隐式启动,这里为了方便,使用显式调用
Intent intent = new Intent(this, AidlService.class);
bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindMyService();
initListener();
}
private void initListener() {
findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(connected){
try {
aidlService.basicTypes(1,2,false,0f,0,"sa");
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}
}
使用第三部的AidlService,上面做了几步:
1.构建连接回调ServiceConnection,监听onServiceConnected()方法,获取到远端的binder对象,转换为IMyService类型对象
2.传入ServiceConnection启动服务,供回调
3.点击按钮,通过获取到的binder对象(IMyService)调用远端方法做交互
5.aidl整体流程
从basicTypes() -> transact() -> onTransact() 来进行分析
上面Proxy中的basicTypes()里面调用Binder对象的transact()方法
Binder.java
/**
* 默认实现倒回包裹并在onTransact上调用。在远端,将调用交易到活页夹中以进行IPC。
*/
public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
int flags) throws RemoteException {
if (false) Log.v("Binder", "Transact: " + code + " to " + this);
if (data != null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}
1.调用服务端的Binder对象实现的onTransact方法
2.设置数据位置为0
来看Service中继承的Stub的类
public static abstract class Stub extends android.os.Binder implements com.yetao.testaidl.IMyService {
private static final java.lang.String DESCRIPTOR = "com.yetao.testaidl.IMyService";
``````省略无关代码
@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;
}
case TRANSACTION_basicTypes: {
data.enforceInterface(descriptor);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0 != data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
int _result = this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
`````
}
主要步骤:
1.客户端调用transact()发送TRANSACTION_basicTypes(code)后,服务端onTransact()接受到
2.从data读出客户端传过来的数据
3.调用对应实现方法(basicTypes)获取到返回值,写入到reply;如果没有返回值,则不写入
小结,截止目前,了解到了在应用层aidl使用所做的流程,将在下一篇说明具体Binder驱动是怎么交互的