AIDL接口可以实现进程间通信,现在这个项目中也使用到了,activity通过AIDL接口调用下层MainService的方法。现在自己又研究了一把,今天把用法和其中的原理记录下来。
使用AIDL接口
实现一个从activity传值给service的功能,activity和service要在不同进程。
android studio新建project就有了MainActivity,然后创建一个AIDL文件,这是一个接口,要在其中申明方法:
IMyAidlInterface.aidl
// IMyAidlInterface.aidl
package acxingyun.cetcs.com.binder;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int a);
}
参数a就是要传的值。下面build一下project,然后新建service,创建一个AIDL.stub类:
MyService1.java
public class MyService1 extends Service {
private IMyAidlInterface.Stub iMyAidlInterface = new IMyAidlInterface.Stub() {
@Override
public void basicTypes(int a) throws RemoteException {
Log.i("MyService1", "basicTypes called,a:" + a);
}
};
public MyService1() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return iMyAidlInterface;
}
@Override
public void onCreate() {
Log.i(getClass().getSimpleName(), "onCreate...");
super.onCreate();
}
}
在onBind中返回AIDL.stub给activity,activity通过bindservice得到AIDL.stub:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private final String TAG = getClass().getSimpleName();
private Button bt1;
private Button bt2;
private IMyAidlInterface iMyAidlInterface;
private static final ComponentName SERVICE_COMPONENT = new ComponentName(
"acxingyun.cetcs.com.binder", "acxingyun.cetcs.com.binder.MyService1");
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("MainActivity", "onServiceConnected...");
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt1 = (Button) findViewById(R.id.bt1);
bt2 = (Button) findViewById(R.id.bt2);
bt1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("MainActivity", "bt1 clicked...");
Intent intent = new Intent();
intent.setComponent(SERVICE_COMPONENT);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
});
bt2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("MainActivity", "bt2 clicked...");
if (iMyAidlInterface != null){
try {
iMyAidlInterface.basicTypes(100);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}
}
由于service和activity要在不同进程,在manifest中配置service:
<service
android:name=".MyService1"
android:enabled="true"
android:exported="true"
android:process=":MyService" />
点击button1:
06-05 05:15:43.913 2630-2630/acxingyun.cetcs.com.binder I/MainActivity: bt1 clicked...
06-05 05:15:43.942 1018-1508/system_process I/ActivityManager: Start proc 2654:acxingyun.cetcs.com.binder:MyService/u0a72 for service acxingyun.cetcs.com.binder/.MyService1
06-05 05:15:43.977 2654-2654/acxingyun.cetcs.com.binder:MyService I/MyService1: onCreate...
06-05 05:15:43.978 2630-2630/acxingyun.cetcs.com.binder I/MainActivity: onServiceConnected...
MainActivity和service在不同进程,点击bt2调用aidl接口:
06-05 05:18:46.332 2630-2630/acxingyun.cetcs.com.binder I/MainActivity: bt2 clicked...
06-05 05:18:46.333 2654-2670/acxingyun.cetcs.com.binder:MyService I/MyService1: basicTypes called,a:100
service得到了activity传的参数。
AIDL通信原理浅析
service端是一个AIDL.stub类:
private IMyAidlInterface.Stub iMyAidlInterface = new IMyAidlInterface.Stub() {
@Override
public void basicTypes(int a) throws RemoteException {
Log.i("MyService1", "basicTypes called,a:" + a);
}
};
这个stub类通过onBind返回:
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return iMyAidlInterface;
}
发现stub实际上是一个IBinder对象,activity端得到之后做了转换:
private IMyAidlInterface iMyAidlInterface;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("MainActivity", "onServiceConnected...");
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
通过IMyAidlInterface.Stub.asInterface(service)变成了之前定义的AIDL接口,于是通过这个AIDL接口就可以调用service端的方法:
iMyAidlInterface.basicTypes(100);
build工程后会自动生成一个IMyAidlInterface.java文件,里面包含了activity端和service端数据传递的代码,先贴出来慢慢说:
public interface IMyAidlInterface extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements acxingyun.cetcs.com.binder.IMyAidlInterface
{
private static final java.lang.String DESCRIPTOR = "acxingyun.cetcs.com.binder.IMyAidlInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an acxingyun.cetcs.com.binder.IMyAidlInterface interface,
* generating a proxy if needed.
*/
public static acxingyun.cetcs.com.binder.IMyAidlInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof acxingyun.cetcs.com.binder.IMyAidlInterface))) {
return ((acxingyun.cetcs.com.binder.IMyAidlInterface)iin);
}
return new acxingyun.cetcs.com.binder.IMyAidlInterface.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
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_basicTypes:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
this.basicTypes(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements acxingyun.cetcs.com.binder.IMyAidlInterface
{
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 a) 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(a);
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public void basicTypes(int a) throws android.os.RemoteException;
}
这排版看的蛋疼,大致梳理下,最外层是aidl接口,申明了一个方法basicTypes(int a),stub是aidl的一个内部类,继承Binder实现了aidl接口,因此可以以IBinder形式返回给activity,它包含了三个方法:asInterface(),asBinder(),onTransact(),stub还有一个内部类Proxy。
先从service创建开始,定义了一个stub对象:
private IMyAidlInterface.Stub iMyAidlInterface = new IMyAidlInterface.Stub() {
@Override
public void basicTypes(int a) throws RemoteException {
Log.i("MyService1", "basicTypes called,a:" + a);
}
};
stub类要在service端实现aidl接口的方法。在onBind()中返回:
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return iMyAidlInterface;
}
activity中得到stub对象并转换成aidl对象:
private IMyAidlInterface iMyAidlInterface;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("MainActivity", "onServiceConnected...");
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
用到了IMyAidlInterface.Stub.asInterface(service),回到源码中:
public static acxingyun.cetcs.com.binder.IMyAidlInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof acxingyun.cetcs.com.binder.IMyAidlInterface))) {
return ((acxingyun.cetcs.com.binder.IMyAidlInterface)iin);
}
return new acxingyun.cetcs.com.binder.IMyAidlInterface.Stub.Proxy(obj);
}
iin是调用IBinder.queryLocalInterface()得到的:
public IInterface queryLocalInterface(String descriptor) {
if (mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
queryLocalInterface结果又和 mDescriptor有关,mDescriptor是在stub的构造函数中赋值:
private static final java.lang.String DESCRIPTOR = "acxingyun.cetcs.com.binder.IMyAidlInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
进去看:
public void attachInterface(IInterface owner, String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
传进去的descriptor和mDescriptor 都是一样的,关键是queryLocalInterface返回的对象mOwner,是stub类的this,也就是stub对象,不是一个IMyAidlInterface实例,所以最后会返回:
acxingyun.cetcs.com.binder.IMyAidlInterface.Stub.Proxy(obj);
Proxy(obj)是一个proxy类:
private static class Proxy implements acxingyun.cetcs.com.binder.IMyAidlInterface
{
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 a) 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(a);
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
activity调用aidl方法也就是在proxy类中调用aidl的方法basicTypes(),由于obj实际上是aidl.stub对象,也就是把service传来的stub对象给了mRemote,mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0),就是stub.transact()方法,就是Binder.transact(),里面又会调用Binder.onTransact(),而Binder.onTransact()又在stub继承Binder的时候被override了:
@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();
this.basicTypes(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
于是,根据传的参数code,进入case TRANSACTION_basicTypes,调用this.basicTypes(_arg0),也就是当前IMyAidlInterface.java申明的方法basicTypes(int a),实现又是在service中,最后实现了activity对service方法的调用。