1. 程式人生 > >AndroidO Treble架構下Binder物件的轉換過程

AndroidO Treble架構下Binder物件的轉換過程

上文中詳細分析了Hal的整個啟動過程,這裡將補充上文中沒有詳細分析的Binder物件轉換過程,下圖為hidl服務的完整註冊過程:

1.  HwcHal繼承於IBase類,是對hw_module_t的封裝,該物件位於Hal程序空間;

2.  通過hwservicemanager的binder代理將HwcHal物件註冊到hwservicemanager程序空間;

3. 在IPC呼叫過程中,HwcHal物件的身份一直在變化,到達hwservicemanager程序後,變成BpHwBase物件,該物件封裝了BpHwBinder,並儲存在hwservicemanager程序中。

建立HIDL服務的本地binder物件

我們知道,binder通訊可以傳輸的資料型別包括:

1. 普通資料型別;

2. fd控制代碼型別;

3. IBinder型別;

4. 經過序列化的自定義型別;

在註冊HwcHal這個hidl服務物件時,由於HwcHal繼承IBase類,並非binder型別,而在BpHwServiceManager::_hidl_add函式中會通過以下程式碼段將HwcHal這個物件傳送給hwservicemanager程序,那麼傳送的是否是HwcHal物件本身呢?

    if (service == nullptr) {
        _hidl_err = _hidl_data.writeStrongBinder(nullptr);
    } else {
        ::android::sp<::android::hardware::IBinder> _hidl_binder = ::android::hardware::toBinder<
                ::android::hidl::base::V1_0::IBase>(service);
        if (_hidl_binder.get() != nullptr) {
            _hidl_err = _hidl_data.writeStrongBinder(_hidl_binder);
        } else {
            _hidl_err = ::android::UNKNOWN_ERROR;
        }
    }

::android::hardware::toBinder<::android::hidl::base::V1_0::IBase>(service)

system\libhidl\transport\include\hidl\HidlBinderSupport.h

// Construct a smallest possible binder from the given interface.
// If it is remote, then its remote() will be retrieved.
// Otherwise, the smallest possible BnChild is found where IChild is a subclass of IType
// and iface is of class IChild. BnChild will be used to wrapped the given iface.
// Return nullptr if iface is null or any failure.
template <typename IType, typename ProxyType>
sp<IBinder> toBinder(sp<IType> iface) {
    IType *ifacePtr = iface.get();
    if (ifacePtr == nullptr) {
        return nullptr;
    }
    if (ifacePtr->isRemote()) {
        return ::android::hardware::IInterface::asBinder(static_cast<ProxyType *>(ifacePtr));
    } else {
        std::string myDescriptor = details::getDescriptor(ifacePtr);
        if (myDescriptor.empty()) {
            // interfaceDescriptor fails
            return nullptr;
        }
        auto func = details::gBnConstructorMap.get(myDescriptor, nullptr);
        if (!func) {
            return nullptr;
        }
        return sp<IBinder>(func(static_cast<void *>(ifacePtr)));
    }
}

這裡首先判斷IComposer這個業務物件是否是BpHwComposer,如果是,那麼呼叫asBinder來得到BpHwBinder物件。在BpHwComposer中,isRemote()預設為true,而在IComposer中,isRemote()預設為false。

struct BpHwComposer : public ::android::hardware::BpInterface<IComposer>, public ::android::hardware::details::HidlInstrumentor {
    explicit BpHwComposer(const ::android::sp<::android::hardware::IBinder> &_hidl_impl);

    typedef IComposer Pure;

    virtual bool isRemote() const override { return true; }
struct IComposer : public ::android::hidl::base::V1_0::IBase {
    virtual bool isRemote() const override { return false; }

這裡註冊的是HwcHal物件,他實現了IComposer介面。因此將根據介面描述符從gBnConstructorMap中找到對應的建構函式指標,然後回撥建構函式:

composer\2.1\[email protected]_genc++\gen\android\hardware\graphics\composer\2.1\ComposerAll.cpp

const char* IComposer::descriptor("[email protected]::IComposer");

__attribute__((constructor))static void static_constructor() {
    ::android::hardware::details::gBnConstructorMap.set(IComposer::descriptor,
            [](void *iIntf) -> ::android::sp<::android::hardware::IBinder> {
                return new BnHwComposer(static_cast<IComposer *>(iIntf));
            });
    ::android::hardware::details::gBsConstructorMap.set(IComposer::descriptor,
            [](void *iIntf) -> ::android::sp<::android::hidl::base::V1_0::IBase> {
                return new BsComposer(static_cast<IComposer *>(iIntf));
            });
};

__attribute__((destructor))static void static_destructor() {
    ::android::hardware::details::gBnConstructorMap.erase(IComposer::descriptor);
    ::android::hardware::details::gBsConstructorMap.erase(IComposer::descriptor);
};

這裡會建立一個BnHwComposer物件,並將HwcHal儲存到其變數_hidl_mImpl中:

BnHwComposer::BnHwComposer(const ::android::sp<IComposer> &_hidl_impl)
        : ::android::hidl::base::V1_0::BnHwBase(_hidl_impl, "[email protected]", "IComposer") { 
            _hidl_mImpl = _hidl_impl;
            auto prio = ::android::hardware::details::gServicePrioMap.get(_hidl_impl, {SCHED_NORMAL, 0});
            mSchedPolicy = prio.sched_policy;
            mSchedPriority = prio.prio;
}

所以toBinder函式功能如下:

1.     如果是BpHwComposer物件,則得到BpHwComposer的成員變數BpHwBinder物件;

2.     如果是BpHwComposer物件,則建立BnHwComposer物件;


由於這裡轉換的是HwcHal物件,該物件實現了IComposer介面,但並不是BpHwComposer型別,因此將建立並返回一個BnHwComposer物件,接著通過_hidl_data.writeStrongBinder(_hidl_binder)將這個BnHwComposer物件傳輸給hwservicemanager程序,我們知道,binder驅動可以傳輸binder實體物件,binder驅動自動識別binder實體物件,並轉化為binder代理物件,對端程序將得到binder代理物件。

system\libhwbinder\Parcel.cpp

status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
    return flatten_binder(ProcessState::self(), val, this);
}
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
    const wp<IBinder>& binder, Parcel* out)
{
    flat_binder_object obj;

    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    if (binder != NULL) {
        sp<IBinder> real = binder.promote();
        if (real != NULL) {
            IBinder *local = real->localBinder();
            if (!local) {
                BpHwBinder *proxy = real->remoteBinder();
                if (proxy == NULL) {
                    ALOGE("null proxy");
                }
                const int32_t handle = proxy ? proxy->handle() : 0;
                obj.type = BINDER_TYPE_WEAK_HANDLE;
                obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
                obj.handle = handle;
                obj.cookie = 0;
            } else {
                obj.type = BINDER_TYPE_WEAK_BINDER;
                obj.binder = reinterpret_cast<uintptr_t>(binder.get_refs());
                obj.cookie = reinterpret_cast<uintptr_t>(binder.unsafe_get());
            }
            return finish_flatten_binder(real, obj, out);
        }

        // XXX How to deal?  In order to flatten the given binder,
        // we need to probe it for information, which requires a primary
        // reference...  but we don't have one.
        //
        // The OpenBinder implementation uses a dynamic_cast<> here,
        // but we can't do that with the different reference counting
        // implementation we are using.
        ALOGE("Unable to unflatten Binder weak reference!");
        obj.type = BINDER_TYPE_BINDER;
        obj.binder = 0;
        obj.cookie = 0;
        return finish_flatten_binder(NULL, obj, out);

    } else {
        obj.type = BINDER_TYPE_BINDER;
        obj.binder = 0;
        obj.cookie = 0;
        return finish_flatten_binder(NULL, obj, out);
    }
}

建立HIDL服務的binder代理物件

Hal程序將BnHwComposer物件傳遞給hwservicemanager後,hwservicemanager程序通過_hidl_err=_hidl_data.readNullableStrongBinder(&_hidl_service_binder);拿到client程序傳送過來的BnHwComposer物件,binder實體到達目的端程序將變為binder代理物件:

system\libhwbinder\Parcel.cpp

sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    // Note that a lot of code in Android reads binders by hand with this
    // method, and that code has historically been ok with getting nullptr
    // back (while ignoring error codes).
    readNullableStrongBinder(&val);
    return val;
}
status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
    return unflatten_binder(ProcessState::self(), *this, val);
}
status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
    const flat_binder_object* flat = in.readObject<flat_binder_object>();

    if (flat) {
        switch (flat->type) {
            case BINDER_TYPE_BINDER:
                *out = reinterpret_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE:
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpHwBinder*>(out->get()), *flat, in);
        }
    }
    return BAD_TYPE;
}
system\libhwbinder\ProcessState.cpp
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    AutoMutex _l(mLock);
    handle_entry* e = lookupHandleLocked(handle);
    if (e != NULL) {
        // We need to create a new BpHwBinder if there isn't currently one, OR we
        // are unable to acquire a weak reference on this current one.  See comment
        // in getWeakProxyForHandle() for more info about this.
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            b = new BpHwBinder(handle);
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            // This little bit of nastyness is to allow us to add a primary
            // reference to the remote proxy when this team doesn't have one
            // but another team is sending the handle to us.
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }
    return result;
}

因此hwservicemanager程序通過readStrongBinder()函式將得到BpHwBinder物件,然後通過fromBinder函式將binder代理物件轉換為業務代理物件:

service = ::android::hardware::fromBinder<IBase,BpHwBase,BnHwBase>(_hidl_service_binder);

system\libhidl\transport\include\hidl\HidlBinderSupport.h

template <typename IType, typename ProxyType, typename StubType>
sp<IType> fromBinder(const sp<IBinder>& binderIface) {
    using ::android::hidl::base::V1_0::IBase;
    using ::android::hidl::base::V1_0::BnHwBase;

    if (binderIface.get() == nullptr) {
        return nullptr;
    }
    if (binderIface->localBinder() == nullptr) {
        return new ProxyType(binderIface);
    }
    sp<IBase> base = static_cast<BnHwBase*>(binderIface.get())->getImpl();
    if (details::canCastInterface(base.get(), IType::descriptor)) {
        StubType* stub = static_cast<StubType*>(binderIface.get());
        return stub->getImpl();
    } else {
        return nullptr;
    }
}

因此fromBinder函式功能如下:

1.      如果是binder代理,則基於binder代理建立業務代理物件;

2.      如果是binder實體,則得到業務實現類物件;


通過fromBinder函式後,這裡將建立一個BpHwBase物件,並將BpHwBinder儲存到其成員變數_hidl_impl中。
BpHwBase::BpHwBase(const ::android::sp<::android::hardware::IBinder> &_hidl_impl)
        : BpInterface<IBase>(_hidl_impl),
          ::android::hardware::details::HidlInstrumentor("[email protected]", "IBase") {
}

Hal程序在向hwservicemanager程序註冊IComposer介面服務時,通過服務實現類物件HwcHal經過toBinder函式將在Hal程序地址空間中建立binder實體物件BnHwComposer,然後將BnHwComposer傳送給hwservicemanager程序,hwservicemanager程序將得到其binder代理物件BpHwBinder,然後經過fromBinder函式在自身程序地址空間中建立BpHwBase物件,如下圖所示:


因此BnHwComposer和BpHwBinder才是真正的IBinder物件,hwservicemanager程序中的BpHwBase和Hal程序中的HwcHal就是通過BnHwComposer和BpHwBinder建立關聯的,在Treble的binder架構中,無論是Client端還是Server端都是採用代理模式來實現的,這裡與普通的binder通訊框架有所區別,普通binder通訊框架中,BpBinder和BnBinder都繼承IBinder類,Client端的業務代理和Binder代理直接採用代理模式,而在Server端,業務實現在本地Binder的子類中。hwBinder下,命名有所混亂,讓人很容易誤以為BpHwXXX和BnHwXXX是binder通訊下的代理物件和本地物件。

Treble架構下的Hal程序模型變化

在AndroidO以前,Hal採用Legacy模式,Framework Server程序直接dlopen hal庫,如下圖所示:

但在AndroidO以後,所有的Hal獨立執行在自己的程序空間,Framework Server程序通過binder訪問Hal,為了相容之前版本的hal實現,在hal庫之上定義了一個hal實現類,用於封裝hal介面,編譯為[email protected],hal程序在啟動時通過dlopen該so庫庫得到Hal介面類物件,而[email protected]中又會dlopen真正的hal實現庫。

上圖說明對於Hal程序來說,預設使用PassthroughServiceManager來載入[email protected]庫,並得到Hidl服務介面類物件,而對於要訪問Hal的Client程序,比如Framework server程序,需要根據當前訪問的hidl服務的Transport型別來決定獲取方式,如果當前訪問的hidl服務是hwbinder,那麼就從hwservicemanager中查詢,如果當前方位的hidl服務是PASSTHROUGH,那麼久會採用PassthroughServiceManager將[email protected]庫載入到當前程序地址空間。