Android的Binder的框架

Android Binder框架分为服务器接口、Binder驱动、以及客户端接口;

服务器端接口:实际上是Binder类的对象,该对象一旦创建,内部则会启动一个隐藏线程,会接收Binder驱动发送的消息,收到消息后,会执行Binder对象中的onTransact()函数,并按照该函数的参数执行不同的服务器端代码。

Binder驱动:该对象也为Binder类的实例,客户端通过该对象访问远程服务。(即服务端与客户端连接的桥梁)

客户端接口:获得Binder驱动,调用其transact()发送消息至服务器

下面举例说明

创建ICalcAIDL.aidl文件:

package com.zhy.calc.aidl;  
interface ICalcAIDL  
{  
    int min(int x , int y );  
}

先看服务端的代码,可以看到我们服务端提供的服务是由

private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub()  
    {  
  
        @Override  
        public int min(int x, int y) throws RemoteException  
        {  
            return x - y;  
        }  
  
    };

ICalcAILD.Stub来执行的,让我们来看看Stub这个类:

public static abstract class Stub extends android.os.Binder implements com.zhy.calc.aidl.ICalcAIDL
{
@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_min:  
{  
data.enforceInterface(DESCRIPTOR);  
int _arg0;  
_arg0 = data.readInt();  
int _arg1;  
_arg1 = data.readInt();  
int _result = this.min(_arg0, _arg1);  
reply.writeNoException();  
reply.writeInt(_result);  
return true;  
}  
}  
return super.onTransact(code, data, reply, flags);  
}    
   
}

文章开头也说到服务端的Binder实例会根据客户端依靠Binder驱动发来的消息,执行onTransact方法,然后由其参数决定执行服务端的代码。

可以看到onTransact有四个参数 code , data ,replay , flags

code 是一个整形的唯一标识,用于区分执行哪个方法,客户端会传递此参数,告诉服务端执行哪个方法

data客户端传递过来的参数

replay服务器返回回去的值

flags标明是否有返回值,0为有(双向),1为没有(单向)

我们仔细看case TRANSACTION_min中的代码

data.enforceInterface(DESCRIPTOR);与客户端的writeInterfaceToken对用,标识远程服务的名称

int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();

接下来分别读取了客户端传入的两个参数

int _result = this.min(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);

然后执行this.min,即我们实现的min方法;返回result由reply写回。

客户端主要通过ServiceConnected与服务端连接

private ServiceConnection mServiceConn = new ServiceConnection()  
    {  
        @Override  
        public void onServiceDisconnected(ComponentName name)  
        {  
            Log.e("client", "onServiceDisconnected");  
            mCalcAidl = null;  
        }  
  
        @Override  
        public void onServiceConnected(ComponentName name, IBinder service)  
        {  
            Log.e("client", "onServiceConnected");  
            mCalcAidl = ICalcAIDL.Stub.asInterface(service);  
        }  
    };

这个onServiceConnected中的IBinder实例,其实就是我们文章开通所说的Binder驱动,也是一个Binder实例

在ICalcAIDL.Stub.asInterface中最终调用了:

return new com.zhy.calc.aidl.ICalcAIDL.Stub.Proxy(obj);

这个Proxy实例传入了我们的Binder驱动,并且封装了我们调用服务端的代码,文章开头说,客户端会通过Binder驱动的transact()方法调用服务端代码

直接看Proxy中的min方法

@Override public int min(int x, int y) 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(x);  
_data.writeInt(y);  
mRemote.transact(Stub.TRANSACTION_min, _data, _reply, 0);  
_reply.readException();  
_result = _reply.readInt();  
}  
finally {  
_reply.recycle();  
_data.recycle();  
}  
return _result;  
}

首先声明两个Parcel对象,一个用于传递数据,一个用户接收返回的数据

_data.writeInterfaceToken(DESCRIPTOR);与服务器端的enforceInterfac对应 _data.writeInt(x);

_data.writeInt(y);写入需要传递的参数

mRemote.transact(Stub.TRANSACTION_min, _data, _reply, 0);

终于看到了我们的transact方法,第一个对应服务端的code,_min,_repay分别对应服务端的data,reply,0表示是双向的

_reply.readException();

_result = _reply.readInt();

最后读出我们服务端返回的数据,然后return。可以看到和服务端的onTransact基本是一行一行对应的。

到此,我们已经通过AIDL生成的代码解释了Android Binder框架的工作原理。Service的作用其实就是为我们创建Binder驱动,即服务端与客户端连接的桥梁。