aidl涉及的Binder框架流程简单分析

来源:互联网 发布:淘宝账号名称怎么改 编辑:程序博客网 时间:2024/05/16 14:26

  • 预备的所有文件
  • 分析IBookManagerinterafacejava

前言:IPC机制必然会碰到AIDL,网上相关的博客很多,但总不如自己走一边来的印象深刻。

预备的所有文件

关于如何使用AIDL,网上很多也比较简单,不赘述了。

Book.aidl

// Book.aidlpackage com.lct.zyw.serviceaidl;parcelable Book;

Book.java

package com.lct.zyw.serviceaidl;import android.os.Parcel;import android.os.Parcelable;/** * Created by zhangyawen on 2016/9/14. */public class Book implements Parcelable{    private int id;    private String name;    public Book() {    }    public Book(int id, String name) {        this.id = id;        this.name = name;    }    protected Book(Parcel in) {        id = in.readInt();        name = in.readString();    }    public static final Creator<Book> CREATOR = new Creator<Book>() {        @Override        public Book createFromParcel(Parcel in) {            return new Book(in);        }        @Override        public Book[] newArray(int size) {            return new Book[size];        }    };    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    /**     * Describe the kinds of special objects contained in this Parcelable's     * marshalled representation.     *     * @return a bitmask indicating the set of special object types marshalled     * by the Parcelable.     */    @Override    public int describeContents() {        return 0;    }    /**     * Flatten this object in to a Parcel.     *     * @param dest  The Parcel in which the object should be written.     * @param flags Additional flags about how the object should be written.     *              May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.     */    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeInt(id);        dest.writeString(name);    }    /**     * 用于AIDL接口方法中Book类型的参数的tag为out,inout。     * 如果该方法改成空实现,则服务端对参数的任何修改不会改变客户端传入的参数,其实最关键的是搞懂IBookManagerInterface.java的流程,就能知其所以然了。     * @param source     */    public void readFromParcel(Parcel source) {        id = source.readInt();        name = source.readString();    }    @Override    public String toString() {        return "Book { id: "+this.id+", name: "+this.name+"}";    }}

IBookManagerinterface.aidl

// IBookManagerInterface.aidl// android studio 不会自动生成对应aidl文件的java文件,具体做法是在aidl文件下Ctrl+ F9(Make Project)// build成功之后在对应项目文件路径下的\build\generated\source\aidl\debug中就会生成aidl文件的对应的java文件package com.lct.zyw.serviceaidl;//需要手动导入(即使在同一个包下)import com.lct.zyw.serviceaidl.Book;interface IBookManagerInterface {    void doSomething(int x,int y);    List<Book> getBooks();    //关于定向Tag,在对应的java文件中需要深入分析    Book addBookIn(in Book book);    Book addBookOut(out Book book);    Book addBookInout(inout Book book);}

分析IBookManagerinteraface.java

网上很多时从服务端代码往客户端代码分析的,我是从客户端代码往服务端代码分析的,其实都差不多,个人习惯而已

IBookManagerInterface.java

/* * This file is auto-generated.  DO NOT MODIFY. * Original file: D:\\ServiceAIDL\\serviceprot\\src\\main\\aidl\\com\\lct\\zyw\\serviceaidl\\IBookManagerInterface.aidl *//* * * Binder的框架: * 1.Android Binder框架分为服务器接口、Binder驱动、以及客户端接口;简单想一下,需要提供一个全局服务, *   那么全局服务那端即是服务器接口,任何程序即客户端接口,它们之间通过一个Binder驱动访问。 * 2.服务器端接口:实际上是Binder类的对象,该对象一旦创建,内部则会启动一个隐藏线程,会接收Binder驱动发送的消息, *   收到消息后,会执行Binder对象中的onTransact()函数,并按照该函数的参数执行不同的服务器端代码。 * 3.Binder驱动:该对象也为Binder类的实例,客户端通过该对象访问远程服务。 * 4.客户端接口:获得Binder驱动,调用其transact()发送消息至服务器 * */package com.lct.zyw.serviceaidl;/** * 1.接口的继承仍然用[extends]关键字 * 2.所有可以在Binder中传输的接口都需要继承IInterface接口 * 3.虽然该Java文件时根据对应的aidl文件由android studio自动生成的,在理解细节实现之后,就可以不依赖aidl文件, *   直接手写IBookManagerInterface.java,甚至将该java文件中的代码拆分到服务端和客户端中去。 * */public interface IBookManagerInterface extends android.os.IInterface {    /**     * Local-side IPC implementation stub class.     * 声明了一个Stub的静态抽象内部类,继承了Binder,即使一个Binder的子类,实现IBookManagerInterface接口     * 说明:1.抽象类实现接口,则接口中的抽象方法可以不在抽象方法中实现,交由继承该抽象类的实现类(非抽象类)来实现,此时就必须实现。     *      2.若抽象类中实现了接口中的抽象方法,那么实现类(继承自抽象类)就可以不实现,也可以实现(方法的重写)。     */    public static abstract class Stub extends android.os.Binder implements com.lct.zyw.serviceaidl.IBookManagerInterface {        //Binder类(Stub)的唯一标识,一般以类名表示        private static final java.lang.String DESCRIPTOR = "com.lct.zyw.serviceaidl.IBookManagerInterface";        /**         * Construct the stub at attach it to the interface.         */        public Stub() {            this.attachInterface(this, DESCRIPTOR);        }        /**         * Cast an IBinder object into an com.lct.zyw.serviceaidl.IBookManagerInterface interface,         * generating a proxy if needed.         * 将服务端的Binder对象转换成客户端所需的AIDL接口类型的对象         * obj:客户端绑定服务端成功后,ServiceConnection中的onServiceConnected方法被调用,返回的service(Ibinder接口)         */        public static com.lct.zyw.serviceaidl.IBookManagerInterface asInterface(android.os.IBinder obj) {            if ((obj == null)) {                return null;            }            //通过标识,检验obj是否属于本进程(客户端)中的Ibinder            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin != null) && (iin instanceof com.lct.zyw.serviceaidl.IBookManagerInterface))) {                return ((com.lct.zyw.serviceaidl.IBookManagerInterface) iin);            }            //进程间通信最终返回客户端的是Stub类中的内部代理类Proxy对象,那么在客户端的任何服务端方法调用都是Proxy类中对应方法的调用。            return new com.lct.zyw.serviceaidl.IBookManagerInterface.Stub.Proxy(obj);        }        /**         * IInterface接口中的方法 一个Binder类返回一个Ibinder接口(Binder实现了Ibinder接口),         * 这其实是一种向上转型。         * @return         */        @Override        public android.os.IBinder asBinder() {            return this;        }        /**         * 该方法时通过Proxy类中的transact方法发起的         * @param code 方法ID:和Proxy类中的transact方法中的一一对应         * @param data 客户端传递过来的参数         * @param reply 服务器返回回去的值         * @param flags 标明是否有返回值,0为有(双向),1为没有(单向)         * @return         * @throws android.os.RemoteException         */        @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_doSomething: {                    data.enforceInterface(DESCRIPTOR);                    int _arg0;                    _arg0 = data.readInt();                    int _arg1;                    _arg1 = data.readInt();                    this.doSomething(_arg0, _arg1);                    reply.writeNoException();                    return true;                }                case TRANSACTION_getBooks: {                    data.enforceInterface(DESCRIPTOR);                    java.util.List<com.lct.zyw.serviceaidl.Book> _result = this.getBooks();                    reply.writeNoException();                    reply.writeTypedList(_result);                    return true;                }                case TRANSACTION_addBookIn: {                    //与客户端的writeInterfaceToken对用,标识远程服务的名称                    data.enforceInterface(DESCRIPTOR);                    //将data转换成Book类                    com.lct.zyw.serviceaidl.Book _arg0;                    if ((0 != data.readInt())) {                        _arg0 = com.lct.zyw.serviceaidl.Book.CREATOR.createFromParcel(data);                    } else {                        _arg0 = null;                    }                    //调用服务端 new IBookManagerInterface.Stub()实现类的具体方法                    com.lct.zyw.serviceaidl.Book _result = this.addBookIn(_arg0);                    //将返回值_result转换成 reply,返回给客户端                    reply.writeNoException();                    if ((_result != null)) {                        reply.writeInt(1);                        _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);                    } else {                        reply.writeInt(0);                    }                    return true;                }                case TRANSACTION_addBookOut: {                    data.enforceInterface(DESCRIPTOR);                    com.lct.zyw.serviceaidl.Book _arg0;                    /**                     * 相比tag为in,服务端仅仅自己new一个Book类的对象,参数_data并没有对book对象进行赋值操作                     *              而tag为in的方法是有赋值操作的                     */                    _arg0 = new com.lct.zyw.serviceaidl.Book();                    com.lct.zyw.serviceaidl.Book _result = this.addBookOut(_arg0);                    reply.writeNoException();                    /**                     * 此处将服务端返回的_result(Book)赋值给reply(Parcel)(不管定向Tag是什么,操作都是一样的,不解释)                     */                    if ((_result != null)) {                        reply.writeInt(1);                        _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);                    } else {                        reply.writeInt(0);                    }                    /**                     * Note:                     * 相比tag为in,此处代码是多出来的,这里是将服务端的入参_arg0赋值给reply,那就说服务端方法的入参就是返回值,                     *              如果服务端方法中不对入参_arg0做任何操作,那么返回的将是一个新new出来的Book对象,需注意。                     */                    if ((_arg0 != null)) {                        reply.writeInt(1);                        _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);                    } else {                        reply.writeInt(0);                    }                    return true;                }                case TRANSACTION_addBookInout: {                    data.enforceInterface(DESCRIPTOR);                    com.lct.zyw.serviceaidl.Book _arg0;                    if ((0 != data.readInt())) {                        _arg0 = com.lct.zyw.serviceaidl.Book.CREATOR.createFromParcel(data);                    } else {                        _arg0 = null;                    }                    com.lct.zyw.serviceaidl.Book _result = this.addBookInout(_arg0);                    reply.writeNoException();                    if ((_result != null)) {                        reply.writeInt(1);                        _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);                    } else {                        reply.writeInt(0);                    }                    if ((_arg0 != null)) {                        reply.writeInt(1);                        _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);                    } else {                        reply.writeInt(0);                    }                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }        /**         * 客户端绑定服务端成功后,执行的直接方法都是内部代理Proxy类中对应的方法         */        private static class Proxy implements com.lct.zyw.serviceaidl.IBookManagerInterface {            private android.os.IBinder mRemote;            //mRemote被赋值:客户端的传进来的service(Ibinder接口类型)            Proxy(android.os.IBinder remote) {                mRemote = remote;            }            @Override            public android.os.IBinder asBinder() {                return mRemote;            }            public java.lang.String getInterfaceDescriptor() {                return DESCRIPTOR;            }            @Override            public void doSomething(int x, int y) throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    _data.writeInt(x);                    _data.writeInt(y);                    mRemote.transact(Stub.TRANSACTION_doSomething, _data, _reply, 0);                    _reply.readException();                } finally {                    _reply.recycle();                    _data.recycle();                }            }            @Override            public java.util.List<com.lct.zyw.serviceaidl.Book> getBooks() throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                java.util.List<com.lct.zyw.serviceaidl.Book> _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    mRemote.transact(Stub.TRANSACTION_getBooks, _data, _reply, 0);                    _reply.readException();                    _result = _reply.createTypedArrayList(com.lct.zyw.serviceaidl.Book.CREATOR);                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }            @Override            public com.lct.zyw.serviceaidl.Book addBookIn(com.lct.zyw.serviceaidl.Book book) throws android.os.RemoteException {                /**                 * _data: 输入型Parcel对象                 * _reply: 输出型Parcel对象                 * _result: 返回值对象(类型根据返回值类型而定)                 */                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                com.lct.zyw.serviceaidl.Book _result;                try {                    //服务器端的enforceInterfac对应                    _data.writeInterfaceToken(DESCRIPTOR);                    //将写入参数到_data中去(此处也证明了关于进程间通信的自定义类型的参数对象(Book),必须是实现Parcelable接口的)                    if ((book != null)) {                        _data.writeInt(1);                        book.writeToParcel(_data, 0);                    } else {                        _data.writeInt(0);                    }                    /**                     * transact(int code, Parcel data, Parcel reply, int flags)方法对应的参数及自身说明                     *                     * code: 方法ID,唯一性,一一对应,服务端onTransact方法会根据客户端传过来的方法ID来确定调用具体的方法                     * data: 用来存储客户端传递给服务端的Parcel类型的数据                     * reply: 用来存储客户端传回给客户端的Parcel类型的数据                     * flags: 是否有返回值:为 0 表示数据可以双向流通,即 _reply 流可以正常的携带数据回来,                     *                     为 1 的话那么数据将只能单向流通,从服务端回来的 _reply 流将不携带任何数据                     *        Note:默认为0,不解释。                     *                     * 调用该方法来发起RPC(远程过程调用)请求,同时当前线程挂起;然后服务端的onTransact方法会被调用,                     * 直到RPC过程返回后,当前线程继续执行                     * Note:此处提到了线程挂起,说明RPC请求很可能是耗时操作,那么在客户端调用服务端的方法时,最好避免直接在UI                     *       线程中直接调用,以免引起ANR,另起线程更安全                     */                    mRemote.transact(Stub.TRANSACTION_addBookIn, _data, _reply, 0);                    //_reply接受到服务端的数据,转换成返回值的数据类型(Book)返回给客户端                    _reply.readException();                    if ((0 != _reply.readInt())) {                        _result = com.lct.zyw.serviceaidl.Book.CREATOR.createFromParcel(_reply);                    } else {                        _result = null;                    }                } finally {                    /**                     * Recycle 机制(Note: 并不是java虚拟机的垃圾回收机制)                     * 简释:                     * 当一个对象不再使用时把它储藏起来,不让虚拟机回收,需要的时候再从仓库里拿出来重新使用,                     * 这就避免了对象被回收后再重分配的过程。对于在应用的生命周期内(或者在循环中)需要频繁                     * 创建的对象来说这个机制特别实用,可以显著减少对象创建的次数,从而减少 GC 的运行时间。                     * 运用得当便可改善应用的性能。唯一的不足只是需要手动为废弃对象调用 recycle 方法。                     * 文/TiouLims(简书作者)                     * 原文链接:http://www.jianshu.com/p/5cba251c7fd9                     */                    _reply.recycle();                    _data.recycle();                }                return _result;            }            /**             * 关于定向Tag(in out inout)的分析(Note:在aidl文件中方法的传入参数设置定向Tag,最根本的还是android studio会根据Tag             *                                      在对应java代码中方法的实现上有区别)             * 该方法的传入参数的定向tag在aidl文件中定义为out。             * @param book             * @return             * @throws android.os.RemoteException             */            @Override            public com.lct.zyw.serviceaidl.Book addBookOut(com.lct.zyw.serviceaidl.Book book) throws android.os.RemoteException {                /**                 * _data: 输入型Parcel对象                 * _reply: 输出型Parcel对象                 * _result: 返回值对象(类型根据返回值类型而定)                 */                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                com.lct.zyw.serviceaidl.Book _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    /**                     * 相比tag为in,该方法的入参book并没有转化成_data,通过transcat方法传递给服务端,那就是说,参数定向tag为out的方法                     * 服务端将不接受的_data参数(Ontransact方法中说明)                     */                    mRemote.transact(Stub.TRANSACTION_addBookOut, _data, _reply, 0);                    _reply.readException();                    /**                     * 此处将服务端返回的_reply转化成Book对象,并返回给客户端(不管定向Tag是什么,操作都是一样的,不解释)                     */                    if ((0 != _reply.readInt())) {                        _result = com.lct.zyw.serviceaidl.Book.CREATOR.createFromParcel(_reply);                    } else {                        _result = null;                    }                    /**                     * 相比tag为in,客户端的入参book被重新赋值,关键在Book.java中需要额外的实现readFromParcel方法,                     *              那么客户端的入参book到底会有什么变化,主要看readFromParcel方法的具体实现:                     *              1.参照Book.java中的构造函数Book(Parcel in)实现,那么入参将和返回值相同                     *              2.readFromParcel是空实现,那么入参没有任何变化                     */                    if ((0 != _reply.readInt())) {                        book.readFromParcel(_reply);                    }                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }            /**             * 定向Tag为inout,则方法实现是同时拥有in和out的并集效果,相对的底层的开销也会比较大,没有必要就不要这么做了。             * @param book             * @return             * @throws android.os.RemoteException             */            @Override            public com.lct.zyw.serviceaidl.Book addBookInout(com.lct.zyw.serviceaidl.Book book) throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                com.lct.zyw.serviceaidl.Book _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    if ((book != null)) {                        _data.writeInt(1);                        book.writeToParcel(_data, 0);                    } else {                        _data.writeInt(0);                    }                    mRemote.transact(Stub.TRANSACTION_addBookInout, _data, _reply, 0);                    _reply.readException();                    if ((0 != _reply.readInt())) {                        _result = com.lct.zyw.serviceaidl.Book.CREATOR.createFromParcel(_reply);                    } else {                        _result = null;                    }                    if ((0 != _reply.readInt())) {                        book.readFromParcel(_reply);                    }                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }        }        //在aidl中定义的方法都会在此得到唯一的ID        static final int TRANSACTION_doSomething = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);        static final int TRANSACTION_getBooks = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);        static final int TRANSACTION_addBookIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);        static final int TRANSACTION_addBookOut = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);        static final int TRANSACTION_addBookInout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);    }    public void doSomething(int x, int y) throws android.os.RemoteException;    public java.util.List<com.lct.zyw.serviceaidl.Book> getBooks() throws android.os.RemoteException;    public com.lct.zyw.serviceaidl.Book addBookIn(com.lct.zyw.serviceaidl.Book book) throws android.os.RemoteException;    public com.lct.zyw.serviceaidl.Book addBookOut(com.lct.zyw.serviceaidl.Book book) throws android.os.RemoteException;    public com.lct.zyw.serviceaidl.Book addBookInout(com.lct.zyw.serviceaidl.Book book) throws android.os.RemoteException;}

结语:好记性不如烂笔头,写下来,方便以后查找。

0 0
原创粉丝点击