您的位置:首页 > 大数据 > 人工智能

使用AIDL分析Binder的工作机制

2016-05-06 10:21 549 查看
在aidl中也可以自定义类型。

写两个aidl文件:

IBookManager.aidl

interface IBookManager {
void add(in Book book);
List<Book> getBookList();
}


在aidl中声明Book,Book.aidl

parcelable Book;


在服务端,通过Binder返回远程服务对象Stub。而这个Stub实现了aidl接口中的内容并继承Binder。

而在客户端,通过绑定一个远程服务,在服务连接成功后,得到这个远程服务对象Stub。用一个aidl接口去引用。

这就是利用Service进行IPC的大概内容。

观察aidl文件编译后的java文件的内容:

package com.asule.cn;
public interface IBookManager extends android.os.IInterface{

//我们在aidl接口
public java.util.List<com.asule.cn.Book> getBookList() throws android.os.RemoteException;
public void add(com.asule.cn.Book book) throws android.os.RemoteException;

//-----------------Stub----------------------->
public static abstract class Stub extends android.os.Binder implements com.asule.cn.IBookManager{

static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

//binder的唯一标识
private static final java.lang.String DESCRIPTOR = "com.asule.cn.IBookManager";

public Stub(){
this.attachInterface(this, DESCRIPTOR);
}

public static com.asule.cn.IBookManager asInterface(android.os.IBinder obj){
if ((obj==null)) {
return null;
}

android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.asule.cn.IBookManager))) {
return ((com.asule.cn.IBookManager)iin);
}
return new com.asule.cn.IBookManager.Stub.Proxy(obj);
}

//返回Stub句柄
@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_getBookList:{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.asule.cn.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook:{
data.enforceInterface(DESCRIPTOR);
com.asule.cn.Book _arg0;
if ((0!=data.readInt())) {
_arg0 = com.asule.cn.Book.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}

//-----------------Proxy----------------------->
//Stub的内部类Proxy
private static class Proxy implements com.asule.cn.IBookManager{
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 java.util.List<com.asule.cn.Book> getBookList() throws android.os.RemoteException{
//
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.asule.cn.Book> _result;

try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.asule.cn.Book.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}

@Override
public void add(com.asule.cn.Book book) throws android.os.RemoteException{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book!=null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}

mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
//<-----------------Proxy-----------------------
}
//<-----------------Stub-----------------------
}


aidl接口和aidl文件中的内容一致。有两个抽象方法,这就是在aidl文件中定义的方法。

可以发现Stub实现了aidl接口,继承自Binder。

Stub中的两个final类型的静态变量

TRANSACTION_getBookList和TRANSACTION_add

DESCRIPTOR:Stub的唯一标识

先前说,在客户端通过asInterface,把获取的Binder对象转换为Stub远程服务实例,通过一个aidl的接口引用。

但asInterface返回的却不一定是Stub。

在此方法中,会判断客户端和服务端是否位于同一个进程,如果是,返回的是stub对象本身,否则返回的是Stub的Proxy。

在代理模式中,代理Proxy和真实对象往往实现同一个接口,代理对象握有真实对象的引用,以便操作真实对象。

Proxy同样实现了aidl接口,把Stub对象实例传递到Proxy中。

当客户端调用getBookList,实际调用的是Proxy中的getBookList。在方法中,

声明了Parcel的输入对象_data,Parcel的输出对象_reply。

调用transact方法来发起RPC(远程过程调用)请求,同时当前线程挂起,然后服务端的Stub的onTransact执行。(onTransact运行在Binder线程池中)

在onTransact中通过code判断是哪个方法执行,然后就会执行Stub的getBookList方法。当方法执行完毕后,会把结果写入到reply中,返回true表示客户端的远程调用成功,否则失败。

而直到RPC结束,客户端的线程才继续执行,从_reply中取出RPC的返回结果,最后返回_reply中的数据。

当足够了解了Binder,其实也可以不借助aidl工具。写aidl的目的只是为了更方便更快速的实现Binder。

不写aidl的话,需要手写接口,Stub,Proxy。在客户端同样也不需要写aidl,直接拷贝手写的java文件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: