相機硬件設備獲取過程hal

分析mModule的獲取過程,這個變量在相機open中,會使用到這個變量。

這個函數的主要功能是根據模塊ID尋找硬件模塊動態鏈接庫的地址,然後調用load去打開動態鏈接庫並從中獲取硬件模塊結構體地址。

文件CameraService.cpp

入口

CameraService.cpp

{
    ALOGI("CameraService process starting");

    BnCameraService::onFirstRef();

    // Update battery life tracking if service is restarting
    BatteryNotifier& notifier(BatteryNotifier::getInstance());
    notifier.noteResetCamera();
    notifier.noteResetFlashlight();

    camera_module_t *rawModule;
    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));
        logServiceError("Could not load camera HAL module", err);
        mNumberOfCameras = 0;
        mNumberOfNormalCameras = 0;
        return;
    }

    mModule = new CameraModule(rawModule);
    err = mModule->init();
    if (err != OK) {
        ALOGE("Could not initialize camera HAL module: %d (%s)", err,
            strerror(-err));
        logServiceError("Could not initialize camera HAL module", err);

        mNumberOfCameras = 0;
        delete mModule;
        mModule = nullptr;
        return;
    }
    ALOGI("Loaded \"%s\" camera module", mModule->getModuleName());

    mNumberOfCameras = mModule->getNumberOfCameras();
    mNumberOfNormalCameras = mNumberOfCameras;

    // Setup vendor tags before we call get_camera_info the first time
    // because HAL might need to setup static vendor keys in get_camera_info
    VendorTagDescriptor::clearGlobalVendorTagDescriptor();
    if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_2) {
        setUpVendorTags();
    }

    mFlashlight = new CameraFlashlight(*mModule, *this);
    status_t res = mFlashlight->findFlashUnits();
    if (res) {
        // impossible because we haven't open any camera devices.
        ALOGE("Failed to find flash units.");
    }

    int latestStrangeCameraId = INT_MAX;
    for (int i = 0; i < mNumberOfCameras; i++) {
        String8 cameraId = String8::format("%d", i);

        // Get camera info

        struct camera_info info;
        bool haveInfo = true;
        status_t rc = mModule->getCameraInfo(i, &info);
        if (rc != NO_ERROR) {
            ALOGE("%s: Received error loading camera info for device %d, cost and"
                    " conflicting devices fields set to defaults for this device.",
                    __FUNCTION__, i);
            haveInfo = false;
        }

        // Check for backwards-compatibility support
        if (haveInfo) {
            if (checkCameraCapabilities(i, info, &latestStrangeCameraId) != OK) {
                delete mModule;
                mModule = nullptr;
                return;
            }
        }

        // Defaults to use for cost and conflicting devices
        int cost = 100;
        char** conflicting_devices = nullptr;
        size_t conflicting_devices_length = 0;

        // If using post-2.4 module version, query the cost + conflicting devices from the HAL
        if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 && haveInfo) {
            cost = info.resource_cost;
            conflicting_devices = info.conflicting_devices;
            conflicting_devices_length = info.conflicting_devices_length;
        }

        std::set<String8> conflicting;
        for (size_t i = 0; i < conflicting_devices_length; i++) {
            conflicting.emplace(String8(conflicting_devices[i]));
        }

        // Initialize state for each camera device
        {
            Mutex::Autolock lock(mCameraStatesLock);
            mCameraStates.emplace(cameraId, std::make_shared<CameraState>(cameraId, cost,
                    conflicting));
        }

        if (mFlashlight->hasFlashUnit(cameraId)) {
            mTorchStatusMap.add(cameraId,
                    ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF);
        }
    }

    if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_1) {
        mModule->setCallbacks(this);
    }

    CameraDeviceFactory::registerService(this);

    CameraService::pingCameraServiceProxy();
}

文件hardware.c

hw_get_module方法 很關鍵

int hw_get_module(const char *id, const struct hw_module_t **module)
{
    return hw_get_module_by_class(id, NULL, module);
}

hw_get_module_by_class() 方法

讀取庫文件,嘗試的順序是:
ro.hardware
ro.product.board
ro.board.platform
ro.arch
default
通過 load 函數加載模塊。

int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{
    int i = 0;
    char prop[PATH_MAX] = {0};
    char path[PATH_MAX] = {0};
    char name[PATH_MAX] = {0};
    char prop_name[PATH_MAX] = {0};


    if (inst)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
    else
        strlcpy(name, class_id, PATH_MAX);

    /*
     * Here we rely on the fact that calling dlopen multiple times on
     * the same .so will simply increment a refcount (and not load
     * a new copy of the library).
     * We also assume that dlopen() is thread-safe.
     */

    /* First try a property specific to the class and possibly instance */
    snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
    if (property_get(prop_name, prop, NULL) > 0) {
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

    /* Loop through the configuration variants looking for a module */
    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
        if (property_get(variant_keys[i], prop, NULL) == 0) {
            continue;
        }
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

    /* Nothing found, try the default */
    if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
        goto found;
    }

    return -ENOENT;

found:
    /* load the module, if this fails, we're doomed, and we should not try
     * to load a different variant. */
    return load(class_id, path, module);
}

load():
調用 dlopen() 函數獲取一個 handle。
調用 dlsym() 函數從動態鏈接庫中獲取 hw_module_t 類型的 hmi。
NOTE:
爲了獲取動態鏈接庫中的結構體,我們需要用到一個字符串 sym。
sym 對應宏 HAL_MODULE_INFO_SYM_AS_STR,即 “HMI”。
我們的動態鏈接庫 .so 文件,是一個 ELF 文件。
ELF:Executable and Linkable Format,可執行鏈接格式。
ELF 文件頭保存了一個路線圖,用於描述文件的組織結構。
通過 readelf -s 命令,我們可以查看對應的 .so 文件描述,可以看到其中有一個 Name 屬性爲 HMI ,其對應的位置就是我們所需要的結構體 hw_module_t。
於是我們通過 HMI 字段,就可以從動態鏈接庫中讀取出相應的結構體,從而得以在 Libraries 層中調用 HAL 層的庫函數。
至此,我們就獲得了最終的 rawModule,然後我們回到 onFirstRef() 中繼續分析。

static int load(const char *id,
        const char *path,
        const struct hw_module_t **pHmi)
{
    int status = -EINVAL;
    void *handle = NULL;
    struct hw_module_t *hmi = NULL;

    /*
     * load the symbols resolving undefined symbols before
     * dlopen returns. Since RTLD_GLOBAL is not or'd in with
     * RTLD_NOW the external symbols will not be global
     */
    handle = dlopen(path, RTLD_NOW);
    if (handle == NULL) {
        char const *err_str = dlerror();
        ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
        status = -EINVAL;
        goto done;
    }

    /* Get the address of the struct hal_module_info. */
    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
    hmi = (struct hw_module_t *)dlsym(handle, sym);
    if (hmi == NULL) {
        ALOGE("load: couldn't find symbol %s", sym);
        status = -EINVAL;
        goto done;
    }

    /* Check that the id matches */
    if (strcmp(id, hmi->id) != 0) {
        ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);
        status = -EINVAL;
        goto done;
    }

    hmi->dso = handle;

    /* success */
    status = 0;

    done:
    if (status != 0) {
        hmi = NULL;
        if (handle != NULL) {
            dlclose(handle);
            handle = NULL;
        }
    } else {
        ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
                id, path, *pHmi, handle);
    }

    *pHmi = hmi;

    return status;
}

在回到文件CameraModule.cpp

注意,這裏的 mModule 是 camera_module_t 類型。

CameraModule::CameraModule(camera_module_t *module) {
    if (module == NULL) {
        ALOGE("%s: camera hardware module must not be null", __FUNCTION__);
        assert(0);
    }
    mModule = module;
}

繼續init()函數

int CameraModule::init() {
    ATRACE_CALL();
    int res = OK;
    if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 &&
            mModule->init != NULL) {
        ATRACE_BEGIN("camera_module->init");
        res = mModule->init();
        ATRACE_END();
    }
    mCameraInfoMap.setCapacity(getNumberOfCameras());
    return res;
}

文件camera_common.h

聲明瞭 camera_module_t:
結構體中聲明瞭許多函數指針。
其中就有 init 函數指針。
這個指針指向的具體函數,是根據具體的 Camera 設備確定的,其中我查看了 QCamera2Factory.cpp ,這裏就實現了對應的函數

typedef struct camera_module {

    hw_module_t common;
    int (*get_number_of_cameras)(void);
    int (*get_camera_info)(int camera_id, struct camera_info *info);
    int (*set_callbacks)(const camera_module_callbacks_t *callbacks);
    void (*get_vendor_tag_ops)(vendor_tag_ops_t* ops);
    int (*open_legacy)(const struct hw_module_t* module, const char* id,
            uint32_t halVersion, struct hw_device_t** device);
    int (*set_torch_mode)(const char* camera_id, bool enabled);
    int (*init)();
    /* reserved for future use */
    void* reserved[5];
} camera_module_t;

小結
這篇筆記中,我們從 CameraService::onFirstRef() 入手,逐漸理順了以 hw_get_module() 爲中心的一個調用邏輯。
實際上,Android HAL 層有一個通用的入口,即宏 HAL_MODULE_INFO_SYM,通過它,我們獲取 HAL 層中的模塊實例,從而使得我們可以調用 HAL 層所提供的函數。
理解了 HAL 層的入口,接下來我們可以去對 Camera.startPreview() 的控制流程進行分析,從而再次加深我們對 Camera 控制流的理解。
 

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