Android中AIDL相关知识

前言

AIDL是Android中用于IPC的语言,具体使用可以参见这篇文章,这篇文章主要想总结一下AIDL具体为我们做了什么工作,主要参考书目《Android开发艺术探索》。

在Android中,除了SocketIntent中使用Bundle、本地文件共享,ContentProvider等等之外,还有一个独有的IPC方式即Binder。在日常编程中使用Binder的主要有AIDLMessenger两种方式,而Messenger也是用AIDL来实现的。

准备

  1. 新建一个AIDL文件
1
2
3
4
5
6
7
// IBookManager.aidl
package cf.android666.myapplication;

interface IBookManager {

void getSth();
}
  1. 用AndroidStudio自动生成一个Binder类

使用Build->Make Project,会在app/build/generated/aidl_source_output_dir/debug/compileDebugAidl/out目录下生成IBookManager.java

分析

AIDL从客户端(Client)发起请求至服务端(Server)相应的工作流程概览,图片来源(https://blog.csdn.net/qian520ao/article/details/78074983)

AIDL从客户端(Client)发起请求至服务端(Server)的流程

下面我们对IBookManager.java这个文件简单分析一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: app/src/main/aidl/cf/android666/myapplication/IBookManager.aidl
*/
package cf.android666.myapplication;

public interface IBookManager extends
android.os.IInterface//IInterface接口,所有可以在Binder中传输的接口都要继承自该接口
{
/**
* Local-side IPC implementation stub class.
* 持有Binder对象
* 获取客户端传过来的数据,根据方法 ID 执行相应操作。
* 将传过来的数据取出来,调用本地写好的对应方法。
* 将需要回传的数据写入 reply 流,传回客户端。
*/
public static abstract class Stub extends android.os.Binder implements cf.android666.myapplication.IBookManager {
private static final java.lang.String DESCRIPTOR = "cf.android666.myapplication.IBookManager";//是Binder的唯一标识,一般为当前Binder的类目

/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);//将Binder和指定的接口绑定,这样当queryLocalInterface时会返回与DESCRIPTOR一致的IInterface
}

/**
* Cast an IBinder object into an cf.android666.myapplication.IBookManager interface,
* generating a proxy if needed.
* 将服务端的Binder转化为客户端需要的IInterface
* 如果是相同的进程,则直接返回服务端的Stub对象本身(没有跨进程);
* 如果是不同的进程,则返回的是Stub.Proxy代理类对象
*/
public static cf.android666.myapplication.IBookManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof cf.android666.myapplication.IBookManager))) {
return ((cf.android666.myapplication.IBookManager) iin);
}
return new cf.android666.myapplication.IBookManager.Stub.Proxy(obj);
}

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

/**
* 客户端远程请求经过系统封装后调用该方法,
* 生成 _data 和 _reply 数据流,并向 _data 中存入客户端的数据。
* 通过 transact() 方法将它们传递给服务端,并请求服务端调用指定方法。
* 接收 _reply 数据流,并从中取出服务端传回来的数据
*/
@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_getSth: {
data.enforceInterface(descriptor);//从data中可以读取参数
this.getSth();//注意,这里调用的是IBookManager的getSth(),也就是需要我们在使用该Binder时实现的方法
reply.writeNoException();//可以往reply中写入结果
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}

/**
* Proxy类持有IBinder的引用
*
*/
private static class Proxy implements cf.android666.myapplication.IBookManager {
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;
}

@Override
public void getSth() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getSth, _data, _reply, 0);//这里实际上是调用了远程的IBinder的transact()方法
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}

static final int TRANSACTION_getSth = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);//这个是我们在AIDL中定义的getSth()方法的标志,用于在onTransact中区分调用的是哪个方法
}

public void getSth() throws android.os.RemoteException;//这个是我们在AIDL中定义的方法,需要在服务端实现,并且会在客户端被调用
}

参考资料

Android 深入浅出AIDL(二)

Android Binder之应用层总结与分析