当前位置:   article > 正文

IPC(五)——浅谈AIDL的架构原理_aidl架构设计

aidl架构设计

IPC(一)利用纯Binder通信(非aidl)中实现了,如何通过纯粹的Binder实现进程间的通信。然后在IPC(四)_Aidl的基本使用过程实现了如何通过Aidl实现进程间的通信。翻看代码的编写过程,其实大体上都差不多,而且也提到Aidl实质上就是对纯Binder通信进行了一次封装,毕竟IBinder中的transact()方法传递的参数不方便使用,大大增加了开发者的使用负担。于是Google就提供了Aidl来简化开发者的负担。简化对于开发者来说既好也不好,因为简化了使用方便了,但是却不容易看清楚内部的原理了。下面就来看一看,Aidl的架构设计。

为了了解清楚Aidl,首先需要理解的就是Binder跨进程通信机制。在IPC(二)初识进程和Binder IPC(三)浅析Binder进程通信和ServiceManager中讲解了Binder的跨进程通信机制。下面来一张图,更好的明确Binder过程
这里写图片描述

IPC(三)中说过,ServiceManager 首先把服务(实现IBinder接口)加载入BinderDriver,接着Bind服务的时候ServiceManager 会返回一个IBinder对象给客户端,其实就是BinderProxy。客户端调用IBinder接口中的Transact()方法通信。

但是Transact()方法毕竟是要传递Pracel对象来传递数据,这大大增加了开发者的负担,于是Aidl就出世了。Aidl为了减轻开发这的负担,在客户端和服务端采用proxy——stub分别对IBinder接口进行了封装,内部调用Transact(),给开发者调用自己定义接口里的方法。

这里写图片描述

上图就是Aidl的设计过程,在MyActivity和IBinder直接增加了Proxy模式,在MyBinder和Binder之间增加了Stub模式,这两个模式分别包装了IBinder接口,在客户端对数据打包,在服务端对数据进行解包。

说名了Aidl的工作过程。回到IPC(四)中回看AIDL的代码实现过程

public static abstract class Stub extends android.os.Binder implements com.example.server.aidl.IAdd
{
private static final java.lang.String DESCRIPTOR = "com.example.server.aidl.IAdd";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
 IAdd.Stub  add=new IAdd.Stub() {

        @Override
        public int add(int i, int j) throws RemoteException {
                int sum=i+j;
                Log.e("ethan", "sum=="+sum);
            return sum;
        }
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

上面两段代码分别是Aidl生成文件和MyService的实现代码,其中服务端通过stub返回一个IBinder类型的对象,该对象内部封装了IAdd(自己定义的接口)里的方法add()。

public static com.example.server.aidl.IAdd asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.server.aidl.IAdd))) {
return ((com.example.server.aidl.IAdd)iin);
}
return new com.example.server.aidl.IAdd.Stub.Proxy(obj);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
private static class Proxy implements com.example.server.aidl.IAdd
{
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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  ServiceConnection conn=new ServiceConnection() {        
        @Override
        public void onServiceDisconnected(ComponentName name) {     
        }   
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            add=IAdd.Stub.asInterface(service);     
        }
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

上面代码分别是Aidl的生成代码和客户端的实现方法。客户端通过asInterface 调用内部的proxy,继而返回一个IAdd接口类型的对象。
这时候就清楚了,服务端通过Aidl 的stub把一个IAdd接口对象打包成IBinder对象,通过Service的onBInder方法返回。客户端通过Aidl的asInterface 继而调用proxy 返回一个IAdd对象给客户端。这时候客户端就可以调用自己定义的IAdd接口里面的方法了。虽然Aidl的跨进程通信也是基于Binder的,但是Aidl通过封装了IBinder接口内的transact方法,继而提供给开发者自己定义的接口对象。大大减轻了开发者的负担。
回到 IPC(一)利用纯Binder通信(非aidl)
既然了解了Aidl的架构原理,那么就把IPC(一)中改一改,封装封装,自己实现。

public class MyProxy implements IEthan
{
    private IBinder iBinder;

    public MyProxy(IBinder iBinder) {
        this.iBinder = iBinder;
    }

    @Override
    public void add(int i, int j) {
        Parcel data=Parcel.obtain();
        int []a={i,j};
        data.writeIntArray(a);
        Parcel reply = Parcel.obtain();
        try {
            iBinder.transact(0,data,reply,1);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

首先是定义一个MyProxy 实现了IPC(一)中的IEthan接口,接着在MyProxy 的构造方法中把IBinder 类型的对象当参数传递进去。同时在add()方法中调用IBinder 接口的transact方法。接着就是调用了

  ServiceConnection conn=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            myProxy=new MyProxy(service);
            myProxy.add(6,8);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在MianActivity中myProxy=new MyProxy(service); 把传递回来的IBinder对象当做参数,实例化myProxy接着调用 myProxy.add(6,8);这样就完美的把Binder内部的transact给封装在内部了,提供给开发者自己定义的接口方法。

04-13 03:29:29.114 2477-2477/com.example.administrator.ui E/ethan: Service onCreate
04-13 03:29:29.118 2477-2489/com.example.administrator.ui E/ethan: onTransact执行了
04-13 03:29:29.118 2477-2489/com.example.administrator.ui E/ethan: add==14
  • 1
  • 2
  • 3

观察Log日志,发现add=14,证明了完美的实现了封装IBinder接口进行通信。由于懒服务端就不封装了。

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号