Android中使用AIDL接口实现进程间通信

来源:互联网 发布:大数据解决方案 ppt 编辑:程序博客网 时间:2024/06/04 19:43
AIDL接口可以实现进程间通信,现在这个项目中也使用到了,activity通过AIDL接口调用下层MainService的方法。现在自己又研究了一把,今天把用法和其中的原理记录下来。

使用AIDL接口

实现一个从activity传值给service的功能,activity和service要在不同进程。android studio新建project就有了MainActivity,然后创建一个AIDL文件,这是一个接口,要在其中申明方法:

IMyAidlInterface.aidl

// IMyAidlInterface.aidlpackage acxingyun.cetcs.com.binder;// Declare any non-default types here with import statementsinterface 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/.MyService106-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方法的调用。