AIDL解析

前言
在Android的系统中有几种跨进程通信方式,但我们使用最常见的就是Aidl,Aidl底层调用使用的是Binder,Binder通信又是Android四大组件跨进程通信的根本,所以学习Aidl有助于我们理解Binder,也助于我们后续理解四大组件。这里我会详细讲解Aidl的实现方式,以及生成的Aidl Java文件

  • Aidl是什么

  • Aidl支持哪些数据类型

  • Aidl的使用

  • Aidl生成文件的讲解

    Aidl(Android接口定义语言)是Android提供的一种ICP通信机制。 首先学习Aidl我们心中要有Clien端和Server端的概念,并且在Clien和Server通信过程中涉及到Binder的相关知识。

    Aidl支持的数据类型一共有4种

  1. Java的基本数据类型
  2. List和map: 集合中数据必须是Aidl支持的数据类型, 并且在Server端必须是ArrayList和HashMap
  3. 其他Aidl生成的接口
  4. 实现Parcelable的实体

Aidl的使用一般是两个App一个作为客户端一个作为服务端,以及一个 客户端和服务端通信的媒介Aidl,客户端的Aidl和服务端的Aidl 需要定义成一样的,在客户端序列化后要在服务端反序列换查询。
在这里我为了方便就讲客户端和服务端写在一起

新建客户端和服务端通信的Aidl

  • 在main目录新建Aidl,文件名叫StudentAidl, 并添加方法 getStudent(int no)方法;
  • 然后Build 一下项目,会在build/generated/source/aidl 下面看到生成了一个和你项目目录一下的StudentAidl的Java文件,这就是clien 和 server通信的媒介

生成的文件中有几个很关键的方法,介绍完client和server后我们根据整个流程再介绍这个类

interface StudentAidl {
/**
* 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);

String getStudent(int no);
}

接下来server端实现
StudentService 继承Service,实现Service中的抽象方法onBinder();在onCreate()中创建一个IBinder对象,在onBinder()中返回 IBinder对象。这里我们要知道 StudentAidl.Stub的Stub对象是继承于Binder,而Binder又实现了IBinder接口

public class StudentService extends Service {

private String[] studentNo = {"张三", "李四", "王五"};
private IBinder binder;

@Override
public void onCreate() {
super.onCreate();
binder = new StudentQueryBinder();
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}

class StudentQueryBinder extends StudentAidl.Stub {

@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

}

@Override
public String getStudent(int no) throws RemoteException {
int l = studentNo.length;
if (l < 0) {
no = 0;
}
if (no >= l) {
no = l - 1;
}
return studentNo[no];
}
}
}

Service需要在Manifest中注册,注册如下:

<service
android:name=".StudentService"
android:process="com.aidl.student.service">
<intent-filter>
<action android:name="student.query" />
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</service>

接下来Client端实现

  • Client 是以一个Activity来实现,首先使用Intent绑定Service, 绑定的时候,会需要传递一个ServiceConnection对象
  • ServiceConnectionImpl 内部类实现ServiceConnection接口,生成一个ServiceConnection对象
  • ServiceConnection对象需要实现onServiceConnectedonServiceDisconnected方法。onServiceConnected会返回一个IBinder,这个IBinder就是bindService注册后在StudentService类onBind方法里返回的
  • 然后调用会在onServiceConnected 中调用StudentAidl.Stud.asInterface(IBinder obj)方法,返回一个StudentAidl,而StudentAidl对象就是我们后面调用之前Aidl中定义的相应方法所需要的对象
public class MainActivity extends AppCompatActivity {

private ServiceConnectionImpl sci;
private StudentAidl student;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Intent intent = new Intent();
intent.setAction("student.query");
intent.setPackage("com.aidl");
sci = new ServiceConnectionImpl();
bindService(intent, sci, Service.BIND_AUTO_CREATE);

}

public void queryOnClick(View v) {
EditText et_no_text = (EditText) findViewById(R.id.et_no_text);
String no = et_no_text.getText().toString();
String sname;
try {
sname = student.getStudent(new Integer(no));
TextView tv_no = (TextView) findViewById(R.id.tv_no);
tv_no.setText(sname);
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

class ServiceConnectionImpl implements ServiceConnection {

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
student = StudentAidl.Stub.asInterface(service);
}

@Override
public void onServiceDisconnected(ComponentName name) {
student = null;
}
}

@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if (sci != null) {
unbindService(sci);
}
}
}

分析Aidl生成的Java文件

查看首先我们看整个类的大结构,我们会返现整个StudentAidl外层只有三个东西,

  1. StudentAidl是一个接口并继承了IInterface接口,IInterface里面有一个asBinder方法,返回一个IBinder
  2. 该接口里面有一个静态抽象类Stub,并继承了Binder类,实现了外层的StudentAidl接口
  3. 定义了Aidl里面声明接口的java形式

**接下来我们看看 静态抽象类Stub **

  1. 该类实现了StudentAidl继承于IInterface的接口asBinder;
  2. 该类同时提供了一个可以将Binder转化为StudentAidl实现类的方法,asInterface。
  3. 该类继承了android.os.Binder类,重写了Binder类的onTransact方法。该方法的作用是,接收客户端发来的请求,并将请求分发至各个接口。
  4. 该类中又自定义了一个静态类Proxy,实现了IMyService。该类在asInterface中被调用。
  5. 该类为每个接口方法定义了一个整型的唯一标识。

再看Proxy,该类的作用是作为一个代理,将接受到的请求转发给服务器

  1. 该类实现了IMyService继承自IInterface的方法asBinder
  2. 该类的构造函数,以Binder作为传参,保存为成员变量。
  3. 该类实现了IMyService中定义的两个接口
    具体的调用时机是,在client端中返回IBinder的时候,会调用asInterface,在这个地方会在本地查询返回Interface,如果不为空且为当前接口,则为同一进程那么就返回Stub,否则Stub.Proxy,返回结果将作为Service实现类的实例
public interface StudentAidl extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/



public static abstract class Stub extends android.os.Binder implements com.aidl.StudentAidl {
private static final java.lang.String DESCRIPTOR = "com.aidl.StudentAidl";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.aidl.StudentAidl interface,
* generating a proxy if needed.
*/
public static com.aidl.StudentAidl asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.aidl.StudentAidl))) {
return ((com.aidl.StudentAidl) iin);
}
return new com.aidl.StudentAidl.Stub.Proxy(obj);
}

@Override
public android.os.IBinder asBinder() {
return this;
}

//MyBinder继承了Binder类同时实现了IEthan接口中的方法。同时在onTransact中得到客户端发过来的数据,
// 并且解析,然后调用实现getAdd()和getminus();为什么要在onTransact执行方法,因为客户端拿到的是一个IBinder接口对象,
// 会调用IBinder中的Transact()方法,由于Transact()方法被IBinder的实现类重写了,
// 根据多态,客户端接口对象会调用Binder(实现类)中的Transact()方法,
// 而Binder类中的Transact()内部又会调用onTransact(),因此最终会执行到onTransact()方法中。

// 2 onTransact 根据标识调用对应的方法
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
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();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
case TRANSACTION_getStudent: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
//这里直接调用相应的方法

java.lang.String _result = this.getStudent(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
//在Aidl跨进程通信,则调用`Proxy`的对应方法,根据`transact`方法将信息传递到服务端,此时客户端挂起等待响应

private static class Proxy implements com.aidl.StudentAidl {
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;
}

/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override
public void 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();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean) ? (1) : (0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}

@Override
public java.lang.String getStudent(int no) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(no);

mRemote.transact(Stub.TRANSACTION_getStudent, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}

static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0)
static final int TRANSACTION_getStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}




/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;

public java.lang.String getStudent(int no) throws android.os.RemoteException;
}

在这个例子中,由于我将Service在注册的时候设置成了跨进程启动,那整个流程是什么样的呢

  1. 客户端调用bindService绑定服务时,将触发Service的onBind监听方法。该方法将调用asBinder方法,返回一个Binder对象。
  2. 客户端将通过onServiceConnected回调函数,获取到该Binder对象(以传参的形式传入)。
  3. 客户端获取到Binder对象后,可调用stub.asInterface方法,将其转换为service实现类的对象。
  4. 在asInterface方法中,将判断service与当前进程,是否在同一进程中。若是,则返回stub本身,否则返回stub.proxy。返回结果将作为Service实现类的实例。
  5. 在通过Service实现类的实例调用接口方法时,若为同一进程,则直接调用方法本身。若为跨进程,则调用stub.proxy的对应接口方法,通过Transact方法将信息传送到服务端。此时,客户端将挂起,等待结果返回。
  6. 服务端接收到信息,通过onTransact()方法,根据方法的唯一标识,将信息转发至各对应方法。
  7. 信息处理完成后,再由服务端onTransact返回结果。

在整个分析中还有没有实际去分析的和理解的

  • bindService注册的时候是怎么注册的,又怎么回传一个IBinder对象的
  • 跨进程中stub.proxy中调用接口方法mRemote.transact的时候是这么传递到服务端的
  • server处理后怎么回传到onTransact又怎么返回到client的
  • Adil中使用了代理模式,代理模式的理解,为什么Aidl使用代理模式
    server告诉你我提供哪些方法供你使用,可是server在onBinder()方法返回一个对象的时候,返回的是一个IBinder,这个对象并不能直接调用server提供的方法,所以Aidl引入了代理模式,重新封装的Proxy代理了server所有的方法。当在多进程调用的时候,那么Proxy中原先保存的原始IBinder就可以调用mRemote.transact方法,经过底层Binder的实现就将消息传递到Server,Server根据方法的code处理相应的逻辑,然后再经过底层onTransact将数据reply并写入到Bindle,Bindle返回并唤醒Client

后面有更加深入的理解再添加到之中来!

https://www.jianshu.com/p/cfb1d2a109a2
http://blog.sina.com.cn/s/blog_e4b5d6be0102ws5u.html
https://blog.csdn.net/daihuimaozideren/article/details/79456953
https://blog.csdn.net/u011240877/article/details/72765136
https://blog.csdn.net/gdutxiaoxu/article/details/78358260
https://blog.csdn.net/luoshengyang/article/details/6745181
https://blog.csdn.net/tiefeng0606/article/details/50977239
http://weishu.me/2016/01/12/binder-index-for-newer/
https://blog.csdn.net/qian520ao/article/details/78089877

猜你喜欢

转载自blog.csdn.net/oheg2010/article/details/82826170