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

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方法的调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值