Android Camera Provider啓動流程

在 Android O 中,系統啓動時,就會啓動 CameraProvider 服務。它將 Camera HAL 從 cameraserver 進程中分離出來,作爲一個獨立進程 [email protected] 來控制 HAL。
這兩個進程之間通過 HIDL 機制進行通信。

這樣的改動源自於 Android O 版本加入的 Treble 機制,它的主要功能(如下圖所示)是將 service 與 HAL 隔離,以方便 HAL 部分進行獨立升級。這其實和 APP 與 Framework 之間的 Binder 機制類似,通過引入一個進程間通信機制而針對不同層級進行解耦(從 Local call 變成了 Remote call)。

下面以Android P進行相應的學習分析。

camera provider 啓動

  • android/hardware/interfaces/camera/provider/2.4/default/[email protected]

    service vendor.camera-provider-2-4 /vendor/bin/hw/[email protected]
        class hal
        user cameraserver
        group audio camera input drmrpc
        ioprio rt 4
        capabilities SYS_NICE
        writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks
    

在android啓動的過程中,init進程調用該腳本啓動 camera provider 服務。根據該目錄下的 Android.bp 可以知道,其實就是運行該目錄下 service.cpp 編譯的可執行文件,service.cpp 內容如下:

int main()
{
    ALOGI("Camera provider Service is starting.");
    // The camera HAL may communicate to other vendor components via
    // /dev/vndbinder
    android::ProcessState::initWithDriver("/dev/vndbinder");
    return defaultPassthroughServiceImplementation<ICameraProvider>("legacy/0", /*maxThreads*/ 6);
}

根據以上代碼可以得知:

  • android::ProcessState::initWithDriver :camera HAL 通過 /dev/vndbinder 驅動可與其他模塊的HAL進行通信;
  • defaultPassthroughServiceImplementation :創建默認爲直通模式(passthrough)的 CameraProvider 服務;
LegacySupport.h

文件路徑:android/system/libhidl/transport/include/hidl

/**
 * Registers passthrough service implementation.
 */
template<class Interface>
__attribute__((warn_unused_result))
status_t registerPassthroughServiceImplementation(
        std::string name = "default") {
    /* 獲得CameraProvider實例化對象(不是Binder代理),(此處的name爲 “legacy/0”) */
    sp<Interface> service = Interface::getService(name, true /* getStub */);

    if (service == nullptr) {
        ALOGE("Could not get passthrough implementation for %s/%s.",
            Interface::descriptor, name.c_str());
        return EXIT_FAILURE;
    }

    LOG_FATAL_IF(service->isRemote(), "Implementation of %s/%s is remote!",
            Interface::descriptor, name.c_str());

    /* 將 CameraProvider 註冊爲一個服務,其他進程需要使用camera HAL層時,通過Binder
     * 得到 CameraProvider 代理類即可操作 camera HAL層,不需要每次都dlopen(HAL.so)
     * */
    status_t status = service->registerAsService(name);

    if (status == OK) {
        ALOGI("Registration complete for %s/%s.",
            Interface::descriptor, name.c_str());
    } else {
        ALOGE("Could not register service %s/%s (%d).",
            Interface::descriptor, name.c_str(), status);
    }

    return status;
}

獲取 CameraProvider 實例對象

從 LegacySupport.h 可以知道,defaultPassthroughServiceImplementation爲模板類函數,將會通過 sp<ICameraProvider> service = ICameraProvider::getService(name, true /* getStub */) 獲取 CameraProvider 實例化對象,以上操作,將會進入 CameraProviderAll.cpp。

CameraProviderAll.cpp

文件路徑:android/out/soong/.intermediates/hardware/interfaces/camera/provider/2.4/[email protected]_genc++/gen/android/hardware/camera/provider/2.4

// static
::android::sp<ICameraProvider> ICameraProvider::getService(const std::string &serviceName, const bool getStub) {
    return ::android::hardware::details::getServiceInternal<BpHwCameraProvider>(serviceName, true, getStub);
}
HidlTransportSupport.h

文件路徑:android/system/libhidl/transport/include/hidl

template <typename BpType, typename IType = typename BpType::Pure,
          typename = std::enable_if_t<std::is_same<i_tag, typename IType::_hidl_tag>::value>,
          typename = std::enable_if_t<std::is_same<bphw_tag, typename BpType::_hidl_tag>::value>>
sp<IType> getServiceInternal(const std::string& instance, bool retry, bool getStub) {
    using ::android::hidl::base::V1_0::IBase;

    sp<IBase> base = getRawServiceInternal(IType::descriptor, instance, retry, getStub);

    if (base == nullptr) {
        return nullptr;
    }

    if (base->isRemote()) {
        // getRawServiceInternal guarantees we get the proper class
        return sp<IType>(new BpType(toBinder<IBase>(base)));
    }

    return IType::castFrom(base);
}

其中,參數 BpHwCameraProvider::descriptor 爲[email protected]::ICameraProvider,instance 爲 “legacy/0” ,retry 爲 true,getStub 爲 true。

ServiceManagement.cpp

文件路徑:android/system/libhidl/transport

在調用 getRawServiceInternal() 函數時,由於我們的參數 getStub 爲 true,所以,該函數主要執行以下部分:

sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& descriptor,
                                                             const std::string& instance,
                                                             bool retry, bool getStub) {
    ...

	/* getStub 爲 true,直通模式,將返回CameraProvider實例對象 */
	if (getStub || vintfPassthru || vintfLegacy) {
        /* 獲取ServiceManager代理 */
        const sp<IServiceManager> pm = getPassthroughServiceManager();
        if (pm != nullptr) {
            /* 獲取CameraProvider實例對象 */
            sp<IBase> base = pm->get(descriptor, instance).withDefault(nullptr);
            if (!getStub || trebleTestingOverride) {
                base = wrapPassthrough(base);
            }
            return base;
        }
    }

    return nullptr;
}

struct PassthroughServiceManager : IServiceManager1_1 {
    static void openLibs(
        const std::string& fqName,
        const std::function<bool /* continue */ (void* /* handle */, const std::string& /* lib */,
                                                 const std::string& /* sym */)>& eachLib) {
        //fqName looks like [email protected]::IFoo
        /* fqName = [email protected]::ICameraProvider */
        size_t idx = fqName.find("::");

        if (idx == std::string::npos ||
                idx + strlen("::") + 1 >= fqName.size()) {
            LOG(ERROR) << "Invalid interface name passthrough lookup: " << fqName;
            return;
        }

        std::string packageAndVersion = fqName.substr(0, idx);
        std::string ifaceName = fqName.substr(idx + strlen("::"));

        /* prefix = [email protected] */
        const std::string prefix = packageAndVersion + "-impl";
        /* sym = HIDL_FETCH_ICameraProvider */
        const std::string sym = "HIDL_FETCH_" + ifaceName;

        constexpr int dlMode = RTLD_LAZY;
        void* handle = nullptr;

        dlerror(); // clear

        static std::string halLibPathVndkSp = android::base::StringPrintf(
            HAL_LIBRARY_PATH_VNDK_SP_FOR_VERSION, details::getVndkVersionStr().c_str());
        std::vector<std::string> paths = {HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR,
                                          halLibPathVndkSp, HAL_LIBRARY_PATH_SYSTEM};

        for (const std::string& path : paths) {
            std::vector<std::string> libs = search(path, prefix, ".so");

            for (const std::string &lib : libs) {
                const std::string fullPath = path + lib;

                /* 經過上面的一些添加轉換,最終
                 * fullPath = /vendor/lib/hw/[email protected]
                 * */
                if (path == HAL_LIBRARY_PATH_SYSTEM) {
                    handle = dlopen(fullPath.c_str(), dlMode);
                } else {
                    handle = android_load_sphal_library(fullPath.c_str(), dlMode);
                }

                if (handle == nullptr) {
                    const char* error = dlerror();
                    LOG(ERROR) << "Failed to dlopen " << lib << ": "
                               << (error == nullptr ? "unknown error" : error);
                    continue;
                }

                /* Lambda表達式代入 */
                if (!eachLib(handle, lib, sym)) {
                    return;
                }
            }
        }
    }

    Return<sp<IBase>> get(const hidl_string& fqName,
                          const hidl_string& name) override {
        sp<IBase> ret = nullptr;

        /* [&] 此處爲Lambda表達式,簡單理解爲函數指針即可,先執行 openLibs() */
        openLibs(fqName, [&](void* handle, const std::string &lib, const std::string &sym) {
            /* handle :dlopen() 的返回值
             * lib :[email protected]
             * sym :HIDL_FETCH_ICameraProvider
             */
            IBase* (*generator)(const char* name);
            /* 返回 HIDL_FETCH_ICameraProvider() 函數對應的函數地址 */
            *(void **)(&generator) = dlsym(handle, sym.c_str());
            if(!generator) {
                const char* error = dlerror();
                LOG(ERROR) << "Passthrough lookup opened " << lib
                           << " but could not find symbol " << sym << ": "
                           << (error == nullptr ? "unknown error" : error);
                dlclose(handle);
                return true;
            }

            /* 執行 HIDL_FETCH_ICameraProvider() 函數,該函數返回CameraProvider實例對象保存在ret,
             * 所以get()函數將返回 ret 
             * */
            ret = (*generator)(name.c_str());

            if (ret == nullptr) {
                dlclose(handle);
                return true; // this module doesn't provide this instance name
            }

            // Actual fqname might be a subclass.
            // This assumption is tested in vts_treble_vintf_test
            using ::android::hardware::details::getDescriptor;
            std::string actualFqName = getDescriptor(ret.get());
            CHECK(actualFqName.size() > 0);
            registerReference(actualFqName, name);
            return false;
        });

        return ret;
    }
}

get() 函數傳遞進來的fpName爲 [email protected]::ICameraProvider ,name爲 legacy/0。

CameraProvider.cpp

文件路徑:android/hardware/interfaces/camera/provider/2.4/default

ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name) {
    /* 傳遞進來的 name 爲 legacy/0,而 kLegacyProviderName 定義爲 legacy/0 */
    if (strcmp(name, kLegacyProviderName) == 0) {
        /* 創建CameraProvider對象,構造函數將會調用initialize() 函數 */
        CameraProvider* provider = new CameraProvider();
        if (provider == nullptr) {
            ALOGE("%s: cannot allocate camera provider!", __FUNCTION__);
            return nullptr;
        }
        if (provider->isInitFailed()) {
            ALOGE("%s: camera provider init failed!", __FUNCTION__);
            delete provider;
            return nullptr;
        }
        return provider;
    } else if (strcmp(name, kExternalProviderName) == 0) {
        ExternalCameraProvider* provider = new ExternalCameraProvider();
        return provider;
    }
    ALOGE("%s: unknown instance name: %s", __FUNCTION__, name);
    return nullptr;
}

bool CameraProvider::initialize() {
    camera_module_t *rawModule;
    /* 在通過 hw_get_module() 加載HAL層so:其實是通過獲取各種android屬性
     * (在設備端可以通過 getprop 命令查看當前設備支持的屬性),
     * 得到HAL so的名稱(*variant_keys[]),而後探測、加載該HAL so庫,並通
     * 過 dlsym() 函數返回標識符爲 HAL_MODULE_INFO_SYM_AS_STR 的HMI地址
     * (由於各個HAL層代碼最終會通過 HAL_MODULE_INFO_SYM 修飾,編譯器識別到
     * 該符號時將會將標示地址導出爲HMI符號,從而在加載HAL so時可以獲取)
     */
    int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID,
            (const hw_module_t **)&rawModule);
    if (err < 0) {
        ALOGE("Could not load camera HAL module: %d (%s)", err, strerror(-err));
        return true;
    }
    /* rawModule 將指向 HAL 中的 camera_module_t 類型結構體,
     * 此時,CameraProvider 與 camera HAL 綁定成功,可以通過
     * CameraProvider操作camera HAL
     */
    /* 創建 CameraModule 對象 */
    /* CameraModule.cpp:android/hardware/interfaces/camera/common/1.0/default */
    mModule = new CameraModule(rawModule);
    /* mModule->init()主要完成以下操作:
     * 1. 當camera HAL的 module_api_version >= CAMERA_MODULE_API_VERSION_2_4,將調用HAL->init()
     * 2. 通過 HAL getNumberOfCameras() 獲取設置camera數量,並將該參數設置爲 mCameraInfoMap 容器的大小
     * */
    err = mModule->init();
    if (err != OK) {
        ALOGE("Could not initialize camera HAL module: %d (%s)", err, strerror(-err));
        mModule.clear();
        return true;
    }
    ALOGI("Loaded \"%s\" camera module", mModule->getModuleName());

    ...

    mNumberOfLegacyCameras = mModule->getNumberOfCameras();
    for (int i = 0; i < mNumberOfLegacyCameras; i++) {
        struct camera_info info;
        /* 將獲取camera信息並保存,其中將有HAL version 信息,應用
         * 層將會檢查HAL層版本信息從而確認調用不同的API實現相機應用
         */
        auto rc = mModule->getCameraInfo(i, &info);
        if (rc != NO_ERROR) {
            ALOGE("%s: Camera info query failed!", __func__);
            mModule.clear();
            return true;
        }

        ...
    }

    return false; // mInitFailed
}

至此,已獲得CameraProvider實例對象,最終返回賦值給 registerPassthroughServiceImplementation() 函數中的 service 。

將 CameraProvider 註冊爲服務

在得到CameraProvider實例對象之後,將通過 service->registerAsService(name) 進行服務註冊。

::android::status_t ICameraProvider::registerAsService(const std::string &serviceName) {
    ::android::hardware::details::onRegistration("[email protected]", "ICameraProvider", serviceName);

    const ::android::sp<::android::hidl::manager::V1_0::IServiceManager> sm
            = ::android::hardware::defaultServiceManager();
    if (sm == nullptr) {
        return ::android::INVALID_OPERATION;
    }
    /* 通過add(),最終調用到 ServiceManagerAll.cpp
    (路徑是android/out/soong/.intermediates/system/libhidl/transport/manager/1.0/
           [email protected]_genc++/gen/android/hidl/manager/1.0)
     中的BpHwServiceManager::add()進行註冊服務
    */
    ::android::hardware::Return<bool> ret = sm->add(serviceName.c_str(), this);
    return ret.isOk() && ret ? ::android::OK : ::android::UNKNOWN_ERROR;
}

由於當前CameraProvider是通過hidl進行相應的操作,這部分的內容可以在網上進行搜索,這裏就不再進行相應的跟蹤了。(主要是我也不懂:-D)

最後

當CameraProvider註冊爲服務之後,CameraService運行時,將會與之進行通信進而操作camera HAL,這樣,HAL與Service進行了一道隔離。下圖爲在跟蹤代碼過程中,記錄的UML圖。

CameraProviderService

參考文章

在瞭解學習CameraProvider服務的過程中,參考了網上很多的優秀文章,感謝!

[Android O] Camera 服務啓動流程簡析

Android P之Camera HAL3流程分析(0)

Android Camera原理之camera provider啓動

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