Android source code--IPC related

A rookie, I studied the source code and found that I couldn't understand it, so I wrote down what I could understand, a memo.
A few articles about BInder, very good Android: Detailed explanation of Binder cross-process communication principle
with pictures and texts The main communication between android processes 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=324661857&siteId=291194637