Binder學習之旅(二)

前段時間用AIDL模板寫了一個簡單的進程間通信demo,並且也成功完成了進程間通信,今天就順着demo來看看模板文件做了些什麼事兒。

Service

回顧demo,用了兩個app來進行實驗,ServiceApp和ClientApp。
ServiceApp啓動了一個BookService,ClientApp綁定Bookservice,進而進行進程間通信。在onServiceConnected回調中,可以拿到Ibinder,通過asInterface就可以獲取到ServiceApp中我們想要的東西,在代碼中如下:

@Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        bookManager = IBookManager.Stub.asInterface(service);
    }

這樣一來,就轉入到AIDL文件生成的模板類中了,來看看asInterface方法做了什麼:

public static com.example.myapplication.aidl.IBookManager asInterface(android.os.IBinder obj)
        {
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof com.example.myapplication.aidl.IBookManager))) {
                return ((com.example.myapplication.aidl.IBookManager)iin);
            }
            return new com.example.myapplication.aidl.IBookManager.Stub.Proxy(obj);
        }

首先根據DESCRIPTOR查詢進行本地,如果本地有就返回本地實現類,否則返回Proxy類。這裏返回本地實現類的話,說明客戶端和服務端在同一個進程,不需要通過進程間通信來訪問數據。在ClientApp中顯然是沒有的,所以返回了Proxy類。

private static class Proxy implements com.example.myapplication.aidl.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.example.myapplication.aidl.Book> getAllBooks() throws android.os.RemoteException
    {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.util.List<com.example.myapplication.aidl.Book> _result;
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            mRemote.transact(Stub.TRANSACTION_getAllBooks, _data, _reply, 0);
            _reply.readException();
            _result = _reply.createTypedArrayList(com.example.myapplication.aidl.Book.CREATOR);
        }
        finally {
            _reply.recycle();
            _data.recycle();
        }
        return _result;
    }
    @Override public void addBook(com.example.myapplication.aidl.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 實現了IBookManager 接口,先將需要傳輸的對象通過Parcel序列化,再調用mRemote的transact方法。通過Proxy的構造方法可以知道,這裏的mRemote就是onServiceConnected中的IBinder,也可以理解爲是ServiceApp中的BookService(不等價,先這麼理解)。
transact方法的四個參數分別是指令,入參的序列化內容,出參的序列化內容,flag。其中服務端通過指令值來判斷客戶端調用的是哪個方法,所以每個方法對應的指令不能相同。第四個參數flag的值是否等待的意思,如果是FLAG_ONEWAY值,則transact方法立馬返回,不會產生出參數據;如果是0,則會等待服務端處理完,並生成出參的序列化內容返回。可以理解爲FLAG_ONEWAY是異步,0是同步。
回到Client的onServiceConnected方法,這個方法會得到一個IBinder對象;與之對應的是Service的onBind方法,onBind方法會返回一個IBinder對象。所以來看看BookService中返回的IBinder是什麼。

	private IBookManager.Stub manager = new IBookManager.Stub(){
        @Override
        public List<Book> getAllBooks() throws RemoteException {
            return books;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            books.add(book);
        }
    };

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return manager;
    }

可以看到,onBind中返回的就是IBookManager.Stub。所以服務端也轉入到AIDL文件生成的模板類中了。

    public static abstract class Stub extends android.os.Binder implements com.example.myapplication.aidl.IBookManager {
        private static final java.lang.String DESCRIPTOR = "com.example.myapplication.aidl.IBookManager";
        /** 省略一些代碼. */
        public Stub(){
            this.attachInterface(this, DESCRIPTOR);
        }
        @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 {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code)
            {
                case INTERFACE_TRANSACTION:
                {
                    reply.writeString(descriptor);
                    return true;
                }
                case TRANSACTION_getAllBooks:
                {
                    data.enforceInterface(descriptor);
                    java.util.List<com.example.myapplication.aidl.Book> _result = this.getAllBooks();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                case TRANSACTION_addBook:
                {
                    data.enforceInterface(descriptor);
                    com.example.myapplication.aidl.Book _arg0;
                    if ((0!=data.readInt())) {
                        _arg0 = com.example.myapplication.aidl.Book.CREATOR.createFromParcel(data);
                    }
                    else {
                        _arg0 = null;
                    }
                    this.addBook(_arg0);
                    reply.writeNoException();
                    return true;
                }
                default:
                {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }
        static final int TRANSACTION_getAllBooks = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

很明顯能看到onTransact的寫法和Proxy的transact很相似,而且連參數都是一樣的。根據transact中的指令執行對應的操作,但是是將數據反序列化,跳轉到具體的實現類(即Service中的manager)中,然後再將返回值序列化,完成一次操作。
本例中,如果client和server在同一個進程時,onServiceConnected中asInterface得到的就是manager,方法調用就是普通的方法調用。
至此,ClientApp和ServiceApp中對AIDL模板類使用的全過程就分析完了,當然只分析了模板類,還沒有涉及到父類的操作,但是通過這個也能比較清晰的知道一次進程間通信在java類中的調用關係。
由此也可以看到Stub和Proxy的固有格式:Stub是IBinder的子類,並實現了IInterface;Proxy實現了IInterface,並持有了IBinder。客戶端和服務端數據傳遞時都是通過IBinder進行操作。
在這裏插入圖片描述
這是進程間通信的二小步,也是我學習binder的二大步。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章