使用AIDL分析Binder的工作机制

在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文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>