從AIDL一窺Android Binder機制

Binder機制在Android系統中地位毋庸置疑,system_server就經過Binder來實現進程間的通訊,從而達到管理、調用一系列系統服務的能力。本文就AIDL來解讀一下Binder機制的。 先了解一下以下幾個概念:java

IBinder 、 Binder 、 BinderProxy 、 IInterface

  1. IBinder : 根據官方的說明文檔IBinder定義的是一種使對象具有遠程通訊能力的接口,他的子類是Binder。IBinder內部預先定義了一些IPC須要用到的接口,實現IBinder的對象能夠被Binder Drivder在IPC過程當中傳遞;
  2. Binder : 實現了IBinder,具有IPC通訊的能力。在IPC通訊過程當中,Binder表明的是Server的本地對象;
  3. BinderProxy : BinderProxy是Binder的內部類,一樣實現了IBinder,不一樣於Binder的是,BinderProxy是Binder對象在Client端的一個代理,Client經過BinderProxy間接跟Server進行通訊;
  4. IInterface : 表明的是Server所具有的接口;

還有一點須要說明一下:當一個Service向AMS進行註冊時,傳遞的過去的以及保存在AMS中的是一個Binder對象。當Client須要跟Service進行通訊,經過AMS查詢到實際上是一個BinderProxy,由於能夠有多個Client同時跟Service進行通訊。固然若是Service和Client在同一進程,AMS返回的仍是一個Binder對象,畢竟沒有必要進行IPC。在進行IPC時,Binder Drivder會在中間幫忙轉換Binder和BinderProxy。android

AIDL

仍是按照Android Service詳解(二)的例子來解釋app

如今咱們來看一下系統自動生成的aidl文件具體有些什麼:ide

/* * This file is auto-generated. DO NOT MODIFY. * Original file: /Users/lebens/Development/WorkSpace/jxx_workspace/Server/app/src/main/aidl/jxx/com/server/aidl/IServerServiceInfo.aidl */
package jxx.com.server.aidl;
public interface IServerServiceInfo extends android.os.IInterface {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements jxx.com.server.aidl.IServerServiceInfo {
        private static final java.lang.String DESCRIPTOR = "jxx.com.server.aidl.IServerServiceInfo";
        /** Construct the stub at attach it to the interface. */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }
        /** * Cast an IBinder object into an jxx.com.server.aidl.IServerServiceInfo interface, * generating a proxy if needed. */
        public static jxx.com.server.aidl.IServerServiceInfo asInterface(android.os.IBinder obj) {
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof jxx.com.server.aidl.IServerServiceInfo))) {
                return ((jxx.com.server.aidl.IServerServiceInfo)iin);
            }
            return new jxx.com.server.aidl.IServerServiceInfo.Stub.Proxy(obj);
        }
        @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_getServerInfo:
                {
                    data.enforceInterface(descriptor);
                    jxx.com.server.aidl.ServerInfo _result = this.getServerInfo();
                    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_setServerInfo:
                {
                    data.enforceInterface(descriptor);
                    jxx.com.server.aidl.ServerInfo _arg0;
                    if ((0!=data.readInt())) {
                        _arg0 = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(data);
                    }
                    else {
                        _arg0 = null;
                    }
                    this.setServerInfo(_arg0);
                    reply.writeNoException();
                    if ((_arg0!=null)) {
                        reply.writeInt(1);
                        _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    }
                    else {
                        reply.writeInt(0);
                    }
                    return true;
                }
                default:
                {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }
        private static class Proxy implements jxx.com.server.aidl.IServerServiceInfo {
            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 jxx.com.server.aidl.ServerInfo getServerInfo() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                jxx.com.server.aidl.ServerInfo _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getServerInfo, _data, _reply, 0);
                    _reply.readException();
                    if ((0!=_reply.readInt())) {
                        _result = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(_reply);
                    }
                    else {
                        _result = null;
                    }
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
            @Override public void setServerInfo(jxx.com.server.aidl.ServerInfo serverinfo) 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 ((serverinfo!=null)) {
                        _data.writeInt(1);
                        serverinfo.writeToParcel(_data, 0);
                    }
                    else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_setServerInfo, _data, _reply, 0);
                    _reply.readException();
                    if ((0!=_reply.readInt())) {
                        serverinfo.readFromParcel(_reply);
                    }
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }
        static final int TRANSACTION_getServerInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_setServerInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }
    public jxx.com.server.aidl.ServerInfo getServerInfo() throws android.os.RemoteException;
    public void setServerInfo(jxx.com.server.aidl.ServerInfo serverinfo) throws android.os.RemoteException;
}
複製代碼
  1. 這個文件中,咱們看到IServerServiceInfo實現了IInterface,說明IServerServiceInfo具有了IPC通訊須要的接口,最底下咱們也能夠看到定義的getServerInfo()、setServerInfo()兩個方法;
  2. 接着來看Stub這個對象,它是IServerServiceInfo的靜態內部類,繼承了Binder同時實現了IServerServiceInfo。這意味着Stub能夠經過Binder Driver進行進程間傳遞,同時又具有了IPC所須要的接口,實際咱們在Service中asBinder()返回的就是這個對象;
  3. Proxy對象,這又是一個代理對象,不過代理的是BinderProxy。這個對象存在的意思就是代理BinderProxy,將Client的操做轉化成BinderProxy去跟Server通訊。
  4. Proxy 和 Stub 的區別在於,Stud自己就是一個Binder對象,能夠直接被Binder Driver傳遞,而Proxy只是表明Service提供的IPC接口,實際使用內部的被代理的mRemote來實現IPC。

Stub

關於Stub再來看幾點:post

  1. DESCRIPTOR : 這是用來惟一表示Stub的,當Stub被實例化時會經過DESCRIPTOR來保存owner對象,也就是Stub所表明的IInterface,同時在queryLocalInterface若是是在同一進程查詢的話就是返回的Stub;
  2. TRANSACTION_getServerInfo 、 TRANSACTION_setServerInfo : 這兩個用來標識Client操做的接口方法。
  3. asInterface : 這個方法就是將Binder,轉換成Client須要的接口對象,若是Binder Driver返回的是一個BinderProxy對象,則建立一個Proxy返回給Client。
  4. onTransact : 這個方法跟下面的Proxy對象一同分析。

Proxy

  1. mRemote : 這是一個BinderProxy對象,由Binder Driver傳遞而來。Proxy的IPC都是經過mRemote來實現的;
  2. 這裏咱們還看到的了咱們定義的接口方法,這些方法都是提供給Client使用的,用於跟Server通訊;
  3. mRemote的transact() : 在Binder Driver的幫助下,最終會調用到Stub的onTransact()中。

onTransact()

以getServerInfo()爲例來分析一下onTransact傳遞過程。 首先咱們在Proxy的實現是這樣的this

@Override public jxx.com.server.aidl.ServerInfo getServerInfo() throws android.os.RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        jxx.com.server.aidl.ServerInfo _result;
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            mRemote.transact(IServerServiceInfo.Stub.TRANSACTION_getServerInfo, _data, _reply, 0);
            _reply.readException();
            if ((0!=_reply.readInt())) {
                _result = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(_reply);
            }
            else {
                _result = null;
            }
        }
        finally {
            _reply.recycle();
            _data.recycle();
        }
        return _result;
    }
複製代碼
  1. _data 、 _reply 分別用於Client向Server傳遞參數和Server向Client返回結果,這2個內的參數都是要序列化的,畢竟IPC;
  2. 經過mRemote.transact開始調用Server的方法;
  3. 經過_reply讀取Server返回的數據,並反序列化結果,將之返回;

從上面的分析能夠知道,這裏的mRemote實際上是一個BinderProxy對象,咱們去看一下這個方法spa

/** * Default implementation rewinds the parcels and calls onTransact. On * the remote side, transact calls into the binder to do the IPC. */
    public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
        if (false) Log.v("Binder", "Transact: " + code + " to " + this);

        if (data != null) {
            data.setDataPosition(0);
        }
        boolean r = onTransact(code, data, reply, flags);
        if (reply != null) {
            reply.setDataPosition(0);
        }
        return r;
    }
複製代碼

最終調用的是Binder內的onTransact(),也就是Stub的onTransact(),咱們來看一下線程

@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_getServerInfo:
                {
                    data.enforceInterface(descriptor);
                    jxx.com.server.aidl.ServerInfo _result = this.getServerInfo();
                    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_setServerInfo:
                {
                    data.enforceInterface(descriptor);
                    jxx.com.server.aidl.ServerInfo _arg0;
                    if ((0!=data.readInt())) {
                        _arg0 = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(data);
                    }
                    else {
                        _arg0 = null;
                    }
                    this.setServerInfo(_arg0);
                    reply.writeNoException();
                    if ((_arg0!=null)) {
                        reply.writeInt(1);
                        _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    }
                    else {
                        reply.writeInt(0);
                    }
                    return true;
                }
                default:
                {
                    return super.onTransact(code, data, reply, flags);
                }
            }
複製代碼

在內部能夠看到case TRANSACTION_getServerInfo 下的操做其實也是很簡單,就是把Client須要的結果經過reply傳遞迴Client代理

總結

經過上面的代碼分析,AIDL咱們能夠快速實現IPC,咱們來總結一下:code

  1. Server須要定義提供給Client的接口,也即實現IInterface,同時還要提供一個Binder用來供Binder Driver找到Server,經過DESCRIPTOR肯定;
  2. Client在跟Server通訊以前須要得到一個Binder或者BinderProxy對象,經過Binder Driver跟Server創建聯繫;
  3. Binder Driver在通訊過程當中自動轉換了BinderProxy 和 Binder;

經過這個例子的分析,其實系統的AMS管理各類系統服務也是一樣的套路,經過2個Binder創建通訊。

還有一點須要注意: Binder或者BinderProxy都是運行在他們本身的Binder池中的,也就是直接經過Binder通訊的話,須要注意線程切換

相關文章
相關標籤/搜索