Binder 驅動詳解(上)

前言

咱們知道 Binder 驅動主要用於跨進程的通訊, 它的身影出如今 Androrid 系統方方面面, 是 Android 系統框架中很是重要, 又很是難懂以搞懂的一部分
關於 Binder 驅動, 之前看別人分享文章的時候, 不少都會在前面寫上 "關於 Binder 驅動相關的知識, 我有些難如下筆", 今天產生整理這篇文章的時候, 筆者突然之間感受, 前輩們說的真是太有道理了, 突然之間, 我也有些難如下筆, 由於它覆蓋面太過於龐大了, 牽扯到了 應用開發層, Java 應用框架層, 運行時庫層, HAL 層, 以及 Linux 內核層, 想要將之闡述清楚, 可真是否是一篇文章可以搞定的, 不過這裏仍是嘗試寫一寫
java

本文主要從如下幾個方面闡述android

  • Java 層通訊實例
  • Binder 代理對象的建立
  • Binder 實體對象的建立

一. Java 層的通訊實例

熟悉 Android 開發的咱們都知道, 在 Android 項目中進行跨進程通訊可使用 AIDL 接口定義語言, 快捷生成相應的代碼進行跨進程通訊, 這裏爲了弄清楚代碼生成背後故事, 咱們手動實現一下緩存

服務提供接口

/**
 * 定義一個服務的提供的功能接口
 *
 * @author Sharry <a href="SharryChooCHN@Gmail.com">Contact me.</a>
 * @version 1.0
 * @since 2018/9/29 16:29
 */
public interface IRemoteService extends IInterface {

    /*
      跨進程提供服務的接口描述
     */
    String DESCRIPTOR = IRemoteService.class.getName();
    /*
      跨進程提供服務的接口中 getServiceName 這個方法 Transaction id.
     */
    int TRANSACTION_getServiceName = (IBinder.FIRST_CALL_TRANSACTION + 0);

    String getServiceName() throws RemoteException;

}
複製代碼

服務實現類 和 Binder 實體對象

/**
 * 接口 IRemoteService 在服務端的實現類
 * {@link #mBinder } 這個對象是讓 IRemoteService 擁有跨進程提供數據能力的 Binder 本地實現類
 *
 * @author Sharry <a href="SharryChooCHN@Gmail.com">Contact me.</a>
 * @version 1.0
 * @since 2018/9/29 17:48
 */
public class RemoteServiceImpl implements IRemoteService {

    private IBinder mBinder;

    public RemoteServiceImpl(IBinder binder) {
        this.mBinder = binder;
    }

    @Override
    public String getServiceName() {
        return "This this RemoteService support function.";
    }

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

}

/**
 * Service 端 Binder 實體對象實現類
 * 其向外提供的功能接口爲 {@link IRemoteService}
 *
 * @author Sharry <a href="SharryChooCHN@Gmail.com">Contact me.</a>
 * @version 1.0
 * @since 2018/9/28 20:50
 */
public class RemoteServiceBinder extends Binder {

    /*
      持有其對應接口實現類的引用
     */
    private IRemoteService mImpl;

    public RemoteServiceBinder() {
        mImpl = new RemoteServiceImpl(this);
        // 調用了 attachInterface 以後, 父類 Binder 將會持有當前 IInterface 接口的描述
        // 在 onTransact 中 會自動處理 INTERFACE_TRANSACTION 類型的事務
        // 在 queryLocalInterface 中能夠找到本地接口
        this.attachInterface(mImpl, mImpl.DESCRIPTOR);
    }

    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code) {
            // 調用了 attachInterface 以後, 父類會處理該類型的 code.
//            case INTERFACE_TRANSACTION: {
//                reply.writeString(DESCRIPTOR);
//                return true;
//            }
            case IRemoteService.TRANSACTION_getServiceName: {
                data.enforceInterface(mImpl.DESCRIPTOR);
                reply.writeNoException();
                reply.writeString(mImpl.getServiceName());
                return true;
            }
            default:
                return super.onTransact(code, data, reply, flags);
        }
    }

}
複製代碼

好的, 能夠看到這裏定義了兩個類, 它們分別是bash

  • RemoteServiceImpl: 遠程服務的實現類
  • RemoteServiceBinder: IRemoteService 服務的 Binder 驅動

能夠發現 RemoteServiceImpl 與 RemoteServiceBinder 內部是相互持有對方引用的框架

  • RemoteServiceImpl 若未持有 IBinder 對象, 它僅僅是一個接口的實現類而已, 正是這個 IBinder 對象讓它提供了跨進程通訊的可能
  • 這裏的 RemoteServiceBinder 對象它做用於服務端的實現接口, 咱們稱之爲 Binder 實體對象

實現客戶端接口的代理實現類

/**
 * 接口 IRemoteService 在客戶端的代理實現類
 * {@link #mBinderProxy } 這個對象即 BinderProxy {@link android.os.Binder#BinderProxy} 實例的引用
 *
 * @author Sharry <a href="SharryChooCHN@Gmail.com">Contact me.</a>
 * @version 1.0
 * @since 2018/9/29 16:36
 */
public class RemoteServiceProxyImpl implements IRemoteService {

    private IBinder mBinderProxy;

    public RemoteServiceProxyImpl(IBinder binder) {
        mBinderProxy = binder;
    }

    @Override
    public String getServiceName() throws RemoteException {
        String result = null;
        Parcel data = Parcel.obtain();
        Parcel replay = Parcel.obtain();
        try {
            // 1. 寫入調用方法所對應接口的描述
            data.writeInterfaceToken(DESCRIPTOR);
            // 2. 向 Service 端發起 invocation 請求
            mBinderProxy.transact(IRemoteService.TRANSACTION_getServiceName, data, replay, 0);
            // 3. 讀取 Service 端扔出來的異常信息
            replay.readException();
            // 4. 讀取異常結果
            result = replay.readString();
        } finally {
            replay.recycle();
            data.recycle();
        }
        return result;
    }

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

}
複製代碼

好的, 能夠看到這裏咱們也建立了一個 IRemoteService 的實現類 RemoteServiceProxyImpl 從名字咱們就能夠知道它是 IRemoteService 接口的代理實現類, 相同的它內部也持有一個 IBinder 對象, 不過這裏咱們沒有本身建立這個 IBinder 的實現類, **那這個 IBinder 實現類是誰呢? **, 其實咱們無需爲代理接口對象建立其特定的 BinderProxy 實現類, 由於系統給咱們提供了, 這個 IBinder 的實現類實際上是 android.os.BinderProxy: IBinderide

用於將 IBinder 轉爲接口的工具類

/**
 * 用於將一個 Binder 對象轉爲對應的接口
 *
 * @author Sharry <a href="SharryChooCHN@Gmail.com">Contact me.</a>
 * @version 1.0
 * @since 2018/9/29 16:35
 */
public class RemoteServiceUtils {

    /**
     * Cast an IBinder object into an com.frank.aidldemo.IServiceInteraction interface,
     * generating a proxy if needed.
     */
    public static IRemoteService asInterface(IBinder obj) {
        if (null == obj) {
            return null;
        }
        // 若想獲取 Service 端 RemoteServiceImpl 對象, 須要在 Binder 本地對象構建時, 調用 attachInterface
        IInterface iin = obj.queryLocalInterface(IRemoteService.DESCRIPTOR);
        if (null != iin && iin instanceof IRemoteService) {
            return ((IRemoteService) iin);
        }
        return new RemoteServiceProxyImpl(obj);
    }

}
複製代碼

UML 圖解析

Binder 依賴類圖.png

二. Binder 實體對象的建立

Binder(android.os.Binder: IBinder) 是 Binder 本地對象 Java 層的實現, 在 Server 端實例化, 對應咱們上面的 RemoteServiceBinder, 它的做用是在 onTransact 中接收 Client 端經過 Binder 驅動傳來的 IPC 請求, 並將請求結果經過 Binder 驅動返回給 Client 端函數

接下來咱們就看看如何實例化一個 Binder 實體對象工具

建立一個 Binder 對象

使用過 Service 的都知道, 在 onBind 中會 new 一個咱們實現好的 Binder 對象ui

public class RemoteService extends Service {

    public IBinder onBind(Intent intent) {
        return new RemoteServiceBinder();
    }
    
}
複製代碼

這個樣子咱們就建立了一個 Binder 本地對象, 咱們看看他的構造方法this

public class Binder implements IBinder {

    private final long mObject;//
    
    /**
     * Binder.constructor
     */
    public Binder() {
        // 調用了 getNativeBBinderHolder 方法, 獲取一個 Native 層的 BBinderHolder 對象句柄值
        mObject = getNativeBBinderHolder();
        ......
    }
    
    private static native long getNativeBBinderHolder();
    
}
複製代碼

能夠看見 Binder 中主要調用了 native 方法, 獲取了一個句柄值, 固然這個 mObject 句柄值也很是重要, 由於 Binder 類內部不少方法都是由它代理實現的

getNativeBBinderHolder

// frameworks/base/core/jni/android_util_Binder.cpp
static jlong android_os_Binder_getNativeBBinderHolder(JNIEnv* env, jobject clazz)
{
    // new 了一個 JavaBBinderHolder 這個對象
    JavaBBinderHolder* jbh = new JavaBBinderHolder();
    return (jlong) jbh;
}
複製代碼

很是簡單的實現 new 了一個 JavaBBinderHolder 這個對象, 而後將它的句柄返回給 Java 中 Binder 對象的 mObject 屬性, 接下來咱們看看這個 JavaBBinderHolder 的構造函數中作了哪些操做

// frameworks/base/core/jni/android_util_Binder.cpp
class JavaBBinderHolder
{
public:
    // 獲取 JavaBBinder 對象
    sp<JavaBBinder> get(JNIEnv* env, jobject obj)
    {
        AutoMutex _l(mLock);
        // 嘗試將 mBinder 這個若指針升級爲強指針
        sp<JavaBBinder> b = mBinder.promote();
        // 升級失敗則從新建立 JavaBBinder 對象
        if (b == NULL) {
            b = new JavaBBinder(env, obj);
            mBinder = b;
        }
        // 返回一個 JavaBinder
        return b;
    }

private:
    Mutex           mLock;   // 互斥鎖
    wp<JavaBBinder> mBinder; // 一個 JavaBBinder 的弱指針
};
複製代碼

能夠看到 JavaBBinderHolder 顧名思義果然持有了一個 JavaBBinder 的對象, 而且能夠經過 get 方法獲取到, 結下來看看這個 JavaBinder

// frameworks/base/core/jni/android_util_Binder.cpp
class JavaBBinder : public BBinder
{
public:
    // 構造函數
    JavaBBinder(JNIEnv* env, jobject /* Java Binder */ object)
        : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object))
    {
        ......
    }

    // 獲取咱們 Java 中實例化的 Binder 對象
    jobject object() const
    {
        return mObject;
    }

protected:
    // Native 層 JavaBBinder 的 onTransact 函數
    virtual status_t onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
    {   
        // 將 JavaVM convert2 JNIEnv
        JNIEnv* env = javavm_to_jnienv(mVM);
        // 回調 java 中 Binder 對象的 execTransact 方法
        jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
            code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
        
        // ......
        if (code == SYSPROPS_TRANSACTION) {
            // 回調父類的 onTransact 函數
            BBinder::onTransact(code, data, reply, flags);
        }
        
        return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
    }

private:
    JavaVM* const   mVM;      // JavaVM 指針對象, 用於轉爲 JNIEnv*
    jobject const   mObject;  // Java 中的 Binder 對象, 即咱們在 Java 中建立的實例
};
複製代碼

看到 JavaBBinder 的實現, 一切就變得很明瞭了

  • JavaBBinder 繼承了 BBinder , 它便是應用框架中的 Binder 本地對象
  • 能夠看到構造函數中將咱們 Java 中實例化的 Binder 對象傳了近來, 保存在 JavaBBinder 的成員變量中

如此一來, Binder 驅動發送的 IPC 請求, 就能夠經過 JavaBBinder 的 onTransact 函數回溯到 Java 的 Binder 方法中了

三. Binder 代理對象的建立

BinderProxy(android.os.BinderProxy: IBinder) 是 Binder 代理對象 Java 層代理對象, 實現了 IBinder 接口, 它在 Client 進程實例化, 它的做用是讓 Client 端調用 transact 方法經過 Binder 驅動向 Server 端發起 IPC 請求, 並等待 Server 端返回的結果, 接下來咱們就看看它實例化的過程

構造函數

/**
     * BinderProxy.getInstance 是私有化的
     */
    private static BinderProxy getInstance(long nativeData, long iBinder) {
        BinderProxy result;
        ......
        result = new BinderProxy(nativeData);
        ......
        return result;
    }

    /**
     * BinderProxy 的構造方法也是私有化的
     */
    private BinderProxy(long nativeData) {
        mNativeData = nativeData;
    }
複製代碼

能夠看到 BinderProxy 這個 java 的 Class 兩個獲取實例的方式都是私有化的, 並且其構造方法的形參是一個 Native 指針的句柄值, 那麼只有一種可能性, BinderProxy 這個對象是在 Native 層使用 JNI 實例化再返回 java 層的, 帶着這個疑問咱們去探究一下

BinderProxy 對象的獲取方式

瞭解 Binder 驅動相關知識的小夥伴都知道, BinderProxy 通常能夠經過兩種方式來獲取

方式一

咱們在 Client 進程, 經過調用 Context.bindService(), 啓動一個遠程的 Service, 這時候須要須要傳入一個 ServiceConnection 參數對象, 在其 onServiceConnected 方法中會收到一個 IBinder 對象的回調, 這個對象即爲 BinderProxy, 以下圖

private val connect: ServiceConnection = object : ServiceConnection {

        override fun onServiceDisconnected(name: ComponentName?) {

        }

        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            // 這個 service 即一個 BinderProxy 的實例對象
        }
        
    }
複製代碼

由於這裏還會牽扯到 Service 的啓動流程, 因此咱們使用方式二的思路往下解析

方式二

經過 ServiceManager 獲取一個系統註冊好的服務, Activity 啓動流程中的 AMS 相信你們再熟悉不過了, 看看它是如何獲取的

private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };
複製代碼

能夠看到第二種方式是經過 ServiceManager.getService(Context.ACTIVITY_SERVICE) 獲取的, 咱們繼續往下剖析

/**
     * ServiceManager.getService 獲取服務的 IBinder 對象
     */
    public static IBinder getService(String name) {
        try {
            // 嘗試從緩存中獲取
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                // 關注一下這個地方
                // 1. getIServiceManager() 獲取 IServiceManager 服務提供對象
                // 2. 調用 IServiceManager.getService(name) 獲取服務
                return Binder.allowBlocking(getIServiceManager().getService(name));
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }
複製代碼

能夠看到 ServiceManager 實際上是一個殼, 其方法的主要實現是經過 IServiceManager 實現的, 接下來咱們看看 getIServiceManager 是如何獲取 IServiceManager 對象的

/**
     * ServiceManager.getIServiceManager
     */
    private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }
        // 關注這裏
        // 1. 這裏經過 BinderInternal.getContextObject() 這個方法獲取到了 BinderProxy 對象
        // 2. 經過 asInterface 將這個 BinderProxy 對象封裝成了 ServiceManagerProxy 
        sServiceManager = ServiceManagerNative
                .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
        return sServiceManager;
    }
    
    /**
     * BinderInternal.getContextObject 這就是獲取 BinderProxy 對象的關鍵
     */
    public static final native IBinder getContextObject();
    
    /**
     * ServiceManagerNative.asInterface
     */
    static public IServiceManager asInterface(IBinder obj)
    {
        if (obj == null) {
            return null;
        }
        IServiceManager in =
            (IServiceManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
        // 將 IBinder 對象封裝成 ServiceManagerProxy 對象, 這個對象是 IServiceManager 提供給 Client 端使用的實現類
        return new ServiceManagerProxy(obj);
    }
    
}
複製代碼

咱們看到了一個很是重要的線索 BinderInternal.getContextObject() 這是一個很是關鍵的方法, 系統就是經過它獲取了 IServiceManager 的 Binder 代理對象

至此 Java 層的旅程就告一段落了, 接下來附上一張 ServiceManager 在 java 層的關係依賴圖

ServiceManager .png

接下來咱們就要深刻到 Native 層去看看 BinderInternal.getContextObject() 的實現了

BinderInternal.getContextObject()

// frameworks/base/core/jni/android_util_Binder.cpp
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
    // 調用了 ProcessState 的 getContextObject 獲取一個句柄值爲 NULL 的 IBinder 對象
    sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
    // 調用 javaObjectForIBinder 返回一個 Java 中的 Binder 對象
    return javaObjectForIBinder(env, b);
}
複製代碼

能夠看到 Native 層中的 getContextObject 中主要作了兩步操做

  • 經過 ProcessState->getContextObject(NULL) 獲取了一個 IBinder 對象
    • 若爲 ServiceManger 的建立進程, 則爲 BBinder 本地對象
    • 若非建立進程, 則爲 BpBinder 代理對象
  • 經過 javaObjectForIBinder 這個方法獲取 Java 的代理對象
// frameworks/base/core/jni/android_util_Binder.cpp
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    if (val == NULL) return NULL;

    // 若爲本地對象, 則返回 Java 中的 Binder 對象
    // 很顯然這個 val 爲 BpBinder, 咱們關注下面的代碼
    if (val->checkSubclass(&gBinderOffsets)) {
        jobject object = static_cast<JavaBBinder*>(val.get())->object();
        return object;
    }

    // 互斥鎖
    AutoMutex _l(mProxyLock);

    // 1. 判斷是否已經爲當前驅動建立了 BinderProxy 對象了
    jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
    if (object != NULL) {
        // 經過引用升級的方式, 判斷這個 BinderProxy 對象是否有效
        jobject res = jniGetReferent(env, object);
        if (res != NULL) {
            // 如有效則返回到 java 層
            return res;
        }
        ......
        // 若無效則解除這個對象與 BpBinder 的關聯
        val->detachObject(&gBinderProxyOffsets);
        ......
    }
    // 2. 這裏經過 JNI 的方式調用了 BinderProxy 的構造函數
    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
    if (object != NULL) {
        // 3. 給 BinderProxy 中的 mObject 對象賦值, 值爲 BpBinder 的句柄
        // 如此一來 Java 中的 BinderProxy 就能夠經過它找到 BpBinder 了
        env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
        val->incStrong((void*)javaObjectForIBinder);
        // 4. 將這個 BinderProxy 緩存到 BpBinder 中
        jobject refObject = env->NewGlobalRef(
                env->GetObjectField(object, gBinderProxyOffsets.mSelf));
        val->attachObject(&gBinderProxyOffsets, refObject,
                jnienv_to_javavm(env), proxy_cleanup);
        ......
    }

    return object;
}
複製代碼

能夠看到這個方法中作了以下幾件事情

  • 若 val 爲 BBinder, 則返回其關聯的 Java 層的 Binder 對象
  • 若 val 爲 BpBinder
    • 從緩存中查找對應的 BinderProxy 對象, 如有效則返回給 Java 層
    • 若無效則經過 JNI 實例化一個 BinderProxy 對象
      • 給 BinderProxy.mObject 賦值, 指向 Native 層對應的 BpBinder 對象
      • 將這個 BinderProxy 對象加入 BpBinder 的緩存

至此 Java 中的 BinderProxy 就在 Native 層建立出來了

總結

好的分析到這裏咱們知道了 Binder 實體對象與 代理對象的實例化過程, 而且也悄悄的解開了 Binder 驅動在應用框架層的面紗

  • 在 Client 端
    • Binder 提供了 BinderProxy 對象
    • BinderProxy 對象對應 Binder運行時庫中的 BpBinder
  • 在 Service 端
    • Binder 提供了 Binder 對象, 須要根據接口咱們自行實現
    • Binder 對象對應了 Binder 運行時庫中的 BBinder

好的, 至此 Binder 驅動的上篇就結束了, 下篇中會着重分析 Binder 運行時庫和一次 Binder 通訊的流程

相關文章
相關標籤/搜索