比较浅显易懂的AIDL

Binder是Android中的一种跨进程通信方式,Android的四大组件、各种Manager 和其对应ManagerService等无不与Binder挂钩。从Android Framework角度来说,Binder是ServiceManager连接ActivityManager、WindowManager等Manager和他们相应ManagerService的桥梁; 从Android 应用层来说,Binder是客户端和服务端进行通信的媒介,正如我们在使用Service时bindService时, Service的onBind方法会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取Service中提供的服务或数据,这里的服务包括普通服务和基于AIDL的服务。

Binder单词翻译过来叫“粘合剂”,它的机制是将Client、Server、ServiceManager和Binder驱动粘合起来。其中Client、Server和Service Manager运行在用户空间,Binder驱动运行在内核空间。Service Manager和Binder驱动已经在Android平台中实现好,我们在开发过程中只要按照规范实现自己的Client和Server组件就可以了。

了解内核空间 和 用户空间
Linux内核独立于普通的应用程序,它可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。内核和上层的应用程序抽像隔离开,分别称之为内核空间和用户空间。

ServiceManager
ServiceManager是整个Binder IPC通信过程中的守护进程,本身也是一个Binder服务,它的主要就两个工作就是查询和注册Service。

Binder驱动 内核模块
linux进程间通信有很多种比如信号量、通道、socket等,但是android是用的binder。用户空间可以通过系统提供的方法调用访问内核空间,而一个用户空间想与另外一个用户空间进行通信的话,就得使用Linux的动态可加载内核模块机制(Loadable Kernel Module,LKM),因为Android系统可以通过添加一个内核模块运行在内核空间,用户进程之间通过这个模块作为桥梁,就可以完成通信了,而这个负责各个用户进程通过Binder通信的内核模块程序叫做Binder驱动。

通信过程
我们通过例子来讲述Binder的通信过程,当你想给你的朋友打电话时,那么你就是Client,而你的朋友就是Server,而电话公司就是ServiceManager,它系统里注册了很多人的电话号码。当你在拔打你朋友电话时,若你朋友电话号码是没有在电话公司注册过,就会返回空号的错误,也就是Server没有在ServiceManager中注册,否则就能拔打电话,在这个拔过电话过程中,是要通过基站来完成接线的,而基站就是Binder驱动。

划重点 AIDL原理
AIDL是Binder的延伸,我们知道,当新建一个aidl文件后执行编译后,便会在app\build\generated\source\aidl\debug\目录下生成对应的同名的类文件。我们在日常开发中,大可不必理会此文件,也正因为此文件是自动生成和格式错乱使很多人对其望而止步。其实只要将该Java文件格式化后,就会清晰多了,这个类的结构其实很简单的。只要读懂该类,基本上就会明白AIDL的工作原理了。

首先创建一个IMyAidl.aidl文件,内容如下:

interface IMyAidl {
    int sum(int a, int b);
}

在执行编译后,就会在app\build\generated\source\aidl\debug目录下生成IMyAidl.java文件。在介绍IMyAidl.java文件前,先来创建 Client端和Server端的调用代码。

Client端的MainActivity.Java代码:

public class MainActivity extends Activity {
 
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
 
            IMyAidl myaidl = IMyAidl.Stub.asInterface(iBinder);
            try {
                myaidl.sum(1, 2);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        public void onServiceDisconnected(ComponentName className) {
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        Intent intent = new Intent(this, MyService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }
    @Override
    protected void onDestroy() {
        unbindService(mConnection);
        super.onDestroy();
    }
}

Server端的MyService.Java代码:

public class MyService extends Service {
    private Binder mBinder = new IMyAidl.Stub() {
        @Override
        publicint sum(int a, int b) throws RemoteException {
            return a + b;
        }
    };
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}

IMyAidl.java内容部分是这样:

 
public interface IMyAidl extends android.os.IInterface {
    public static abstract class Stub extends android.os.Binder implements com.***.IMyAidl {
        ……
    }
    public void sum(int a, int b) throws android.os.RemoteException;
}

IMyAidl.java文件中,存在一个继承自己的内部类Stub和我们在aidl中定义的sum方法。Stub就是一个Binder类。可以看出,它就是MyService中onBind方法return的mBinder对象的类。再来细看下Stub类的代码:

public static abstract class Stub extends android.os.Binder implements com***.IMyAidl {
    private static final java.lang.String DESCRIPTOR = "com.***.IMyAidl";
 
    public Stub() {
        this.attachInterface(this, DESCRIPTOR);
    }
 
    public static ***.IMyAidl asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) && (iin instanceof ***.IMyAidl))) {
            return ((com.***.IMyAidl) iin);
        }
        return new com.***.IMyAidl.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 {
        java.lang.String descriptor = DESCRIPTOR;
        switch (code) {
            case INTERFACE_TRANSACTION: {
                reply.writeString(descriptor);
                return true;
            }
            case TRANSACTION_sum: {
                data.enforceInterface(descriptor);
                int _arg0;
                _arg0 = data.readInt();
                int _arg1;
                _arg1 = data.readInt();
                int _result = this.sum(_arg0, _arg1);
                reply.writeNoException();
                reply.writeInt(_result);
                return true;
            }
            default: {
                return super.onTransact(code, data, reply, flags);
            }
        }
    }
 
    private static class Proxy implements com***.IMyAidl {
        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;
        }
 
        @Override
        public int sum(int a, int b) throws android.os.RemoteException {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            int _result;
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
                _data.writeInt(a);
                _data.writeInt(b);
                mRemote.transact(Stub.TRANSACTION_sum, _data, _reply, 0);
                _reply.readException();
                _result = _reply.readInt();
            } finally {
                _reply.recycle();
                _data.recycle();
            }
            return _result;
        }
    }
 
    static final int TRANSACTION_sum = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}

下面我们来看看Stub类的变量和方法的含义:

DESCRIPTOR

DESCRIPTOR是Binder的唯一标识,一般用当前Binder的类名表示

asInterface

asInterface方法用于将Server端的Binder对象转换成Client端所需的AIDL接口类型的对象,正如我们可以看到asInterface方法就是我们在Client端中代码:

IMyAidl myaidl = IMyAidl.Stub.asInterface(iBinder);
try {
    myaidl.sum(1, 2);
} catch (Exception e) {
    e.printStackTrace();
}

asInterface方法它的参数是接收由服务绑定成功后返回的一个IBinder对象,返回值一个AIDL接口类型的对象,从代码中可以发现,该对象有三种情况返回值,第一种因为参数输入错误所以返回了null; 接着判断了Client端和Server端是否位于同一进程,如果是同一进程,则是第二情况,返回就是Server端中的Stub对象本身,也就是本示例中就是MyService中的mBinder对象; 如果Client端和Server端不是同一进程,那么就是第三种情况,返回的是Stub类的内部代理类Proxy对象。而Client端中代码:myaidl.sum(1, 2);调用的就是Proxy类的sum方法。

Proxy

Proxy类是内部类Stub的内部代理类,同样也是继承于IMyAidl.java。它的sum方法会使用Parcelable来准备数据,把参数都写入_data,让_reply接收方法返回值。最后使用IBinder的transact方法把数据传给Binder的Server端去。代码中mRemote就是asInterface方法接收的参数obj。这时当前线程挂起,Server端的onTransact方法会被调用。

onTransact

onTransact方法是运行在Server中的Binder线程池中的,当Client端发起跨进程请求时,远程请求会通过系统底层封装后交由onTransact方法来处理。通过TRANSACTION_sum找到对应的方法sum,接着从data中取出从Client端进程传递过来的参数,然后执行目标方法sum,在执行完毕后就向reply中写入返回值。此时,Proxy中的sum方法线程恢复执行。

你可能感兴趣的:(比较浅显易懂的AIDL)