AIDL即Android Interface Definition Language,用于实现Android进程间通信(IPC)。

两个App间通信的代码实现

1.定义AIDL文件

由于进程之间的通信信息需要双向转换,所以android采用代理类在背后实现了信息的双向转换,代理类由android编译器生成,对开发人员来说是透明的。

1
2
3
4
5
6
7
// IRemoteService.aidl
package com.lcodecore.myapplication;
interface IRemoteService {
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}

对于非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。

1
2
3
4
interface IMyService {
void savePersonInfo(in Person person);
List<Person> getAllPerson();
}

编译后会自动生成IRemoteService.java文件。
AIDL定义规则:

  1. 接口名和aidl文件名相同。
  2. 接口和方法前不用加访问权限修饰符public,private,protected等,也不能用final,static。
  3. Aidl默认支持的类型包话java基本类型(int、long、boolean等)和(String、List、Map、CharSequence,使用这些类型时不需要import声明。对于List和Map中的元素类型必须是Aidl支持的类型。 如果使用自定义类型作为参数或返回值,自定义类型必须实现Parcelable接口。
  4. 自定义类型和AIDL生成的其它接口类型在aidl描述文件中,应该显式import,即便在该类和定义的包在同一个包中。
  5. 在aidl文件中所有非Java基本类型参数必须加上in、out、inout标记,
    以指明参数是输入参数、输出参数还是输入输出参数。
  6. Java原始类型默认的标记为in,不能为其它标记。

2.定义Service,在onBind方法中返回IRemoteService.Stub的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class DDService extends Service {
@Override
public void onCreate() {
super.onCreate();
System.out.println("DDService onCreate........" + "Thread: " + Thread.currentThread().getName());
}
@Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
System.out.println("Thread: " + Thread.currentThread().getName());
System.out.println("basicTypes aDouble: " + aDouble +" anInt: " + anInt+" aBoolean " + aBoolean+" aString " + aString);
}
};
}

Stub继承自Binder,即远程服务特别在返回了实现了AIDL接口的IBinder对象。
然后在manifest.xml文件中声明:

1
2
3
4
5
6
<service android:name=".DDService" android:process=":remote">
<intent-filter>
<action android:name="android.intent.action.AIDLService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>

android:process=”:remote”,代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process=”remote”,没有“:”号的,则创建全局进程,不同的应用程序共享该进程。

服务器端的代码就完成了。

3.新建客户端工程,定义一个与服务器端路径相同的IRemoteService.aidl文件

4.实现ServiceConnection并连接服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IRemoteService remoteService = IRemoteService.Stub.asInterface(service);
try {
remoteService.basicTypes(1,1,true,1f,1d,"测试");
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {}
};
Intent intent = new Intent(android.intent.action.AIDLService); //此处为隐式调用
bindService(conn);

内部原理

Android进程间通信需要使用Binder机制,Binder作为一种进程间通信机制,负责提供远程调用的功能(RPC),它的系统组件主要包括四种:Client, Server, ServiceManager, Binder Driver。

  • Client, Server, ServiceManager运行在系统的用户态,而Binder Driver运行在内核态。
  • 为了完成Client端到Server端的通信任务,用户空间的需要操作Binder Driver提供的/dev/binder文件来完成交互。
  • ServiceManager负责管理Server并向Client端提供一个Server的代理接口(proxy)。通过代理接口中定义的方法,Client端就可以使用Server端提供的服务了。

整个过程为:

  1. Client端调用代理接口的方法,将Client的参数打包为parcel对象发送给内核空间中BinderDriver;
  2. Server端读取到BinderDriver中的请求数据,将parcel对象解包并处理;
  3. 处理好后,将处理结果打包返回给BinderDriver,再交给Client端。

参考博客

从AIDL开始谈Android进程间Binder通信机制