Android 通过 AIDL 实现进程间通信

AIDL(Android Interface Definition Language) 是 Android 系统提供的进程间通信方式,底层是根据 Binder 机制实现,是对上层代码的封装。
Android 的系统服务基本上都是通过 AIDL 实现的,比如 AMS 通过 IApplicationThread.aidl 实现,WMS 通过 IWindowManager.aidl 实现。

示例代码

源码请看 Github

1. 在 app/src/main/aidl/com.app.aidlsample 目录下创建 IRemoteService.aidl 文件,声明服务方法:

1
2
3
4
5
6
// 注意写上包名,不然会找不到生成的 IRemoteAidl 类
package com.app.aidlsample;

interface IRemoteAidl{
String search(String key);
}

点击 Build > Rebuild Project 后,会在 build/generated/aidl_source_output_dir/debug/out/com.app.aidlsample 文件夹下生成和 IRemoteAidl.aidl 文件对应的 IRemoteAidl.java 文件。该文件是通过 Gradle 的 Task :app:compileDebugAidl 任务生成的。

2. 创建服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class RemoteAidlService extends Service {
public static final String TAG = "IRemoteAidl";

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

private static class AAA extends IRemoteAidl.Stub {
@Override
public String search(String key) throws RemoteException {
Log.i(TAG, "search。Key: " + key + ", Thread: " + Thread.currentThread());
SystemClock.sleep(2000);
return "Hello, " + key;
}
}
}

在 AndroidManifest.xml 配置:

1
2
3
<service
android:name=".RemoteAidlService"
android:process=":remote" />

android:process=":remote" 说明 RemoteAidlService 服务运行在子进程。

3. 绑定服务,调用远程服务:

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
public class MainActivity extends AppCompatActivity {
public static final String TAG = "IRemoteAidl";
private IRemoteAidl mRemoteAidlService;

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

Intent intent = new Intent(this, RemoteAidlService.class);
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.i(TAG, "onServiceConnected. componentName: " + componentName + " iBinder: " + iBinder);
mRemoteAidlService = IRemoteAidl.Stub.asInterface(iBinder);
}

@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.i(TAG, "onServiceDisconnected. componentName: " + componentName);

}
}, Context.BIND_AUTO_CREATE);

findViewById(R.id.tv_search).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mRemoteAidlService != null) {
try {
String result = mRemoteAidlService.search("World!");
Log.i(TAG, "From Remote Service: " + result + ", Thread: " + Thread.currentThread());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}
}

Log 如下:

1
2
3
16:11:18.573 I/IRemoteAidl: onServiceConnected. componentName: ComponentInfo{com.app.aidlsample/com.app.aidlsample.RemoteAidlService} iBinder: android.os.BinderProxy@f4e8c9e
16:11:20.563 I/IRemoteAidl: search。Key: World!, Thread: Thread[Binder:18797_1,5,main]
16:11:22.565 I/IRemoteAidl: From Remote Service: Hello, World!, Thread: Thread[main,5,main]

源码分析

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
package com.app.aidlsample;

public interface IRemoteAidl extends android.os.IInterface {
public static class Default implements com.app.aidlsample.IRemoteAidl {
/** Default implementation for IRemoteAidl. */
@Override public java.lang.String search(java.lang.String key) throws android.os.RemoteException {
return null;
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.app.aidlsample.IRemoteAidl {
private static final java.lang.String DESCRIPTOR = "com.app.aidlsample.IRemoteAidl";

public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.app.aidlsample.IRemoteAidl interface,
* generating a proxy if needed.
*/
public static com.app.aidlsample.IRemoteAidl asInterface(android.os.IBinder obj) {
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.app.aidlsample.IRemoteAidl))) {
return ((com.app.aidlsample.IRemoteAidl)iin);
}
return new com.app.aidlsample.IRemoteAidl.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_search: {
data.enforceInterface(descriptor);
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _result = this.search(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}

private static class Proxy implements com.app.aidlsample.IRemoteAidl {
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 java.lang.String search(java.lang.String key) 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.writeString(key);
boolean _status = mRemote.transact(Stub.TRANSACTION_search, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().search(key);
}
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public static com.app.aidlsample.IRemoteAidl sDefaultImpl;
}

static final int TRANSACTION_search = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);

public static boolean setDefaultImpl(com.app.aidlsample.IRemoteAidl impl) {
if (Stub.Proxy.sDefaultImpl != null) {
throw new IllegalStateException("setDefaultImpl() called twice");
}
if (impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static com.app.aidlsample.IRemoteAidl getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}

public java.lang.String search(java.lang.String key) throws android.os.RemoteException;
}
  • IBinder : IBinder 是一个接口,代表了一种跨进程通信的能力。只要实现了这个借口,这个对象就能跨进程传输。
  • IInterface : IInterface 代表的就是 Server 进程对象具备什么样的能力(能提供哪些方法,其实对应的就是 AIDL 文件中定义的接口)
  • Binder : Java 层的 Binder 类,代表的其实就是 Binder 本地对象,BinderProxy 代表远程进程的 Binder 对象的本地代理;这两个类都继承自 IBinder, 因而都具有跨进程传输的能力;实际上,在跨越进程的时候,Binder 驱动会自动完成这两个对象的转换。
  • Stub : 是一个抽象类,类继承了 Binder, 说明它是一个 Binder 本地对象,它实现了 IInterface 接口,表明它具有 Server 承诺给 Client 的能力;具体的 IInterface 的相关实现需要服务端实现。
  • Default:服务的默认实现。

AIDL 总是那么一种固定的模式:一个需要跨进程传递的对象一定继承自 IBinder,如果是 Binder 本地对象,那么一定继承 Binder 实现 IInterface,如果是代理对象,那么就实现了 IInterface 并持有了 IBinder 引用;

跨进程通信流程如下:

  1. Client 通过 Binder 代理对象调用远程服务,Client 线程挂起阻塞;
  2. Binder 代理对象将请求派发给 Binder 驱动;
  3. Binder 驱动再将请求派发给 Server 端,Server 端处理后将结果返回给 Binder 驱动;
  4. 唤醒 Client 线程,返回结果给 Client;

总结

AIDL 通过 aidl 文件生成了一个接口,接口中的 Stub 类用于服务端Proxy 类用于服务代理 。通过继承 Stub 实现服务端,很大程度上简化 Android 进程间通信。

参考

[1] Android 接口定义语言 (AIDL)
[2] 写给 Android 应用工程师的 Binder 原理剖析