Android source code--IPC related

A rookie, I studied the source code and found that I couldn't understand it, so I recorded what I could understand, memo.
A few articles about BInder, very good Android: Graphic and text explain the principle of Binder cross-process
communication The main android inter-process communication The methods used are AIDL, Intent, Binder, ContentProvider, Socket. The most important one is Binder, and Binder involves the following classes: IBinder, Binder, IInterface

IBinder.java

public interface IBinder {
    int FIRST_CALL_TRANSACTION  = 0x00000001;
    int LAST_CALL_TRANSACTION   = 0x00ffffff;
    int PING_TRANSACTION        = ('_'<<24)|('P'<<16)|('N'<<8)|'G';
    int DUMP_TRANSACTION        = ('_'<<24)|('D'<<16)|('M'<<8)|'P';
    int INTERFACE_TRANSACTION   = ('_'<<24)|('N'<<16)|('T'<<8)|'F';
    int TWEET_TRANSACTION   = ('_'<<24)|('T'<<16)|('W'<<8)|'T';
    int LIKE_TRANSACTION   = ('_'<<24)|('L'<<16)|('I'<<8)|'K';
    int SYSPROPS_TRANSACTION = ('_'<<24)|('S'<<16)|('P'<<8)|'R';
    int FLAG_ONEWAY             = 0x00000001;

    public String getInterfaceDescriptor() throws RemoteException;

    public boolean pingBinder();

    /**
     * 判断Binder所在进程是否存在.
     * 注意,Binder死亡这一现象.
     */
    public boolean isBinderAlive();

    /**
     * 检查Binder对象是否存在本地实现,如果没有,返回null.
     * 注意,一般实现stub类和stub类的proxy代理类的时候,会调用到asInterface(),
     * 在该方法中就会使用到queryLocalInterface,得到返回之后需要判断是否null.
     * 如果是null,就需要实现stub的代理类.
     * proxy代理类中,一般会有一个远程binder对象remote,该对象需要调用到transact()
     */
    public IInterface queryLocalInterface(String descriptor);

    public void dump(FileDescriptor fd, String[] args) throws RemoteException;

    public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException;

    /**
     * Perform a generic operation with the object.
     *
     * @param code  一般用该参数标示需要执行哪个方法 .
     *              该值的返回在{@link #FIRST_CALL_TRANSACTION}和{@link #LAST_CALL_TRANSACTION}之间
     * @param data  即需要发送的数据.不能为null,如果不发送,就new一个空的Parcel进去
     * @param reply 来自目标处的数据.不能为null,如果不发送,就new一个空的Parcel进去
     * @param flags 额外的操作标志.  只能是0或者 {@link #FLAG_ONEWAY}.具体作用未知,一般用0即可
     */
    public boolean transact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException;

    /**
     * 死亡代理的接口.
     *
     * @see #linkToDeath
     */
    public interface DeathRecipient {
        public void binderDied();
    }

    /**
     * 设置一个死亡代理对象.即在Binder链接断裂的时候(Binder死亡),自动调用
     * {@link DeathRecipient#binderDied DeathRecipient.binderDied()}
     *
     * @see #unlinkToDeath
     */
    public void linkToDeath(DeathRecipient recipient, int flags)
            throws RemoteException;

    /**
     * 移除之前设置的死亡代理.
     */
    public boolean unlinkToDeath(DeathRecipient recipient, int flags);
}

IInterface.java

public interface IInterface
{
    /**
     * 返回Binder的代理对象
     */
    public IBinder asBinder();
}

Manual AIDL implementation

The following content is read the book android development art exploration, and then typed it by myself

1. First create a class and implement the Parcelable interface

public class Book implements Parcelable {

    public int bookId;
    public String bookName;


    public Book(int bookId, String bookName) {
        this.bookId = bookId;
        this.bookName = bookName;
    }

    protected Book(Parcel in) {
        bookId = in.readInt();
        bookName = in.readString();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(bookId);
        dest.writeString(bookName);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    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];
        }
    };
}

2. First declare an interface of AIDL nature, this interface inherits the IInterface interface, the main purpose is to implement the asBinder() method.

public interface IBookManager extends IInterface {

    static final String DESCRIPTION = "hust.hhh.aidltest.IBookManager";


    //IBinder#transact() 的code参数,必须要在FIRST_CALL_TRANSACTION与LAST_CALL_TRANSACTION之间
    static final int TRANSACTION_GETBOOKLIST = IBinder.FIRST_CALL_TRANSACTION;
    static final int TRANSACTION_ADDBOOK = IBinder.FIRST_CALL_TRANSACTION + 1;

    //自定义两个方法
    List<Book> getBookList() throws RemoteException;

    void addBook(Book book) throws RemoteException;
}

3. Implement the Stub class and create a proxy class

public class BookManagerImpl extends Binder implements IBookManager {

    private final static String TAG = "AIDL";

    public BookManagerImpl() {
        //调用Binder#attachInterface,
        //传入自身和描述符,Binder内部会调用queryLocalInterface()方法
        //这样使得该类与描述符关联起来,方便在请求相应的描述符时返回对应的IInterface.
        //简单的说,就是别的地方传入描述符,就会返回BookManagerImpl对象(BookManagerImpl实现了IInterface接口)
        this.attachInterface(this, DESCRIPTION);
    }

    /**
     * 返回当前Binder对象,这里就是BookManagerImpl的实例
     */
    @Override
    public IBinder asBinder() {
        return this;
    }

    /**
     * 客户端调用
     */
    public static IBookManager asInterface(IBinder binder) {
        if (binder == null) {
            return null;
        }

        //查询本地是否有BookManagerImpl实例(Binder对象),如果有,说明服务器与客户端在同一个进程,直接返回该实例
        IInterface iInterface = binder.queryLocalInterface(DESCRIPTION);
        if (iInterface != null & iInterface instanceof IBookManager) {
            return (IBookManager) iInterface;
        }

        //服务器与客户端不在同一个进程,返回代理对象
        return new Proxy(binder);
    }

    /**
     * 运行在服务端的Binder线程池中
     *
     * @param code  确定所调用的方法
     * @param data  目标方法的参数.目标方法没有参数,data就没用
     * @param reply 返回值参数.目标方法执行完成后,把返回值写入replay中
     */
    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code) {
            //IBinder协议事务代码.不知道这个作用,待补充
            case INTERFACE_TRANSACTION:
                reply.writeString(DESCRIPTION);
                return true;
            case TRANSACTION_GETBOOKLIST:
                //此处时为了教研代理对象Proxy#getBookList()中的 data.writeInterfaceToken(DESCRIPTION);
                data.enforceInterface(DESCRIPTION);
                List<Book> bookList = this.getBookList();
                reply.writeNoException();
                reply.writeTypedList(bookList);
                return true;
            case TRANSACTION_ADDBOOK:
                data.enforceInterface(DESCRIPTION);
                Book book = Book.CREATOR.createFromParcel(data);
                this.addBook(book);
                reply.writeNoException();
                return true;
        }
        return super.onTransact(code, data, reply, flags);
    }

    @Override
    public List<Book> getBookList() throws RemoteException {
        return null;
    }

    @Override
    public void addBook(Book book) throws RemoteException {

    }

    /**
     * 远程服务的代理对象
     */
    private static class Proxy implements IBookManager {

        private IBinder mRemote;

        public Proxy(IBinder mRemote) {
            this.mRemote = mRemote;
        }

        @Override
        public IBinder asBinder() {
            return mRemote;
        }

        @Override
        public List<Book> getBookList() throws RemoteException {
            List<Book> result = null;
            Parcel data = Parcel.obtain();
            Parcel replay = Parcel.obtain();
            try {
                //验证
                data.writeInterfaceToken(DESCRIPTION);
                //调用远程对象的getBookList()方法,并获得结果
                mRemote.transact(TRANSACTION_GETBOOKLIST, data, replay, 0);
                //读取返回结果的数据内容,并形成一个List
                replay.readException();
                result = replay.createTypedArrayList(Book.CREATOR);
            } catch (Exception e) {
                Log.e(TAG, "Proxy#getBookList() : " + e.toString());
            } finally {
                replay.recycle();
                data.recycle();
            }
            return result;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel replay = Parcel.obtain();
            try {
                data.writeInterfaceToken(DESCRIPTION);
                data.writeInt(1);
                book.writeToParcel(data, 0);
                mRemote.transact(TRANSACTION_ADDBOOK, data, replay, 0);
                replay.readException();
            } catch (Exception e) {
                Log.e(TAG, "Proxy#addBook() : " + e.toString());
            } finally {
                data.recycle();
                replay.recycle();
            }
        }
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324661996&siteId=291194637