栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android R camera Hal启动(下)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android R camera Hal启动(下)

文章目录
  • 前言
  • 代码流程分析
  • 总结


前言

接上一篇Android R camera Hal启动(上)接着写,把谷歌的代码都分析完成,高通/MTK的代码就不贴了。


代码流程分析

上一篇说到getProviderImpl函数。实例化了CameraProvider对象,先看CameraProvider的构造函数。

template
struct CameraProvider : public ICameraProvider {
    CameraProvider() : impl() {}
    ...
}

调用了impl也就是LegacyCameraProviderImpl_2_4的构造。

LegacyCameraProviderImpl_2_4::LegacyCameraProviderImpl_2_4() :
        camera_module_callbacks_t({sCameraDeviceStatusChange,
                                   sTorchModeStatusChange}) {
    mInitFailed = initialize();
}

camera_module_callbacks_t是HAL的回调函数,用于通知FW相机状态更新。直接看构造函数调用camera_module_callbacks_t比较奇怪,先看下LegacyCameraProviderImpl_2_4的类的申明和sCameraDeviceStatusChange/sTorchModeStatusChange两个函数的定义就能明白了。

struct LegacyCameraProviderImpl_2_4 : public camera_module_callbacks_t {
    ...
static void sCameraDeviceStatusChange(
    const struct camera_module_callbacks* callbacks,
    int camera_id,
    int new_status);

static void sTorchModeStatusChange(
    const struct camera_module_callbacks* callbacks,
    const char* camera_id,
    int new_status);
    ...
}

LegacyCameraProviderImpl_2_4是继承了camera_module_callbacks_t,所以类构造的同时使用sCameraDeviceStatusChange/sTorchModeStatusChange初始化了camera_module_callbacks_t中的camera_device_status_change/torch_mode_status_change函数指针。
camera_module_callbacks_t结构定义如下:

typedef struct camera_module_callbacks {
    void (*camera_device_status_change)(const struct camera_module_callbacks*,
            int camera_id,
            int new_status);

    void (*torch_mode_status_change)(const struct camera_module_callbacks*,
            const char* camera_id,
            int new_status);
} camera_module_callbacks_t;

再继续往下看,调用mInitFailed = initialize();看下initialize的实现:

bool LegacyCameraProviderImpl_2_4::initialize() {
    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));
        return true;
    }

    mModule = new CameraModule(rawModule);
    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());

    // Setup vendor tags here so HAL can setup vendor keys in camera characteristics
    VendorTagDescriptor::clearGlobalVendorTagDescriptor();
    if (!setUpVendorTags()) {
        ALOGE("%s: Vendor tag setup failed, will not be available.", __FUNCTION__);
    }

    // Setup callback now because we are going to try openLegacy next
    err = mModule->setCallbacks(this);
    if (err != OK) {
        ALOGE("Could not set camera module callback: %d (%s)", err, strerror(-err));
        mModule.clear();
        return true;
    }

    mPreferredHal3MinorVersion =
        property_get_int32("ro.vendor.camera.wrapper.hal3TrebleMinorVersion", 3);
    ALOGV("Preferred HAL 3 minor version is %d", mPreferredHal3MinorVersion);
    switch(mPreferredHal3MinorVersion) {
        case 2:
        case 3:
            // OK
            break;
        default:
            ALOGW("Unknown minor camera device HAL version %d in property "
                    "'camera.wrapper.hal3TrebleMinorVersion', defaulting to 3",
                    mPreferredHal3MinorVersion);
            mPreferredHal3MinorVersion = 3;
    }

    mNumberOfLegacyCameras = mModule->getNumberOfCameras();
    for (int i = 0; i < mNumberOfLegacyCameras; i++) {
        uint32_t device_version;
        auto rc = mModule->getCameraDeviceVersion(i, &device_version);
        if (rc != NO_ERROR) {
            ALOGE("%s: Camera device version query failed!", __func__);
            mModule.clear();
            return true;
        }

        if (checkCameraVersion(i, device_version) != OK) {
            ALOGE("%s: Camera version check failed!", __func__);
            mModule.clear();
            return true;
        }

        char cameraId[kMaxCameraIdLen];
        snprintf(cameraId, sizeof(cameraId), "%d", i);
        std::string cameraIdStr(cameraId);
        mCameraStatusMap[cameraIdStr] = CAMERA_DEVICE_STATUS_PRESENT;

        addDeviceNames(i);
    }

    return false; // mInitFailed
}

先看hw_get_module函数:hardware/libhardware/hardware.c

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

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);

    

    
    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;
        }
    }

    
    for (i=0 ; i 

hw_get_module会调用hw_get_module_by_class去找到实现HAL的so,class_id的值就是camera。先根据ro.hardware.camera的prop来找,这是没有的,然后就是根据variant_keys的数组查找对应的prop。

static const char *variant_keys[] = {
    "ro.hardware",  
    "ro.product.board",
    "ro.board.platform",
    "ro.arch"
};

高通的平台ro.hardware的值是qcom,因为这个数组中的prop的值get出来之后能找到对应的so,所以就会调用hw_module_exists拼接这个so的完整路径,如果找不到的话就会调用hw_module_exists拼接camera.default.so的全路径,camera.default.so的源码在hardware/libhardware/modules/camera/3_0目录下,平台方会自己实现camera.xxx.so,所以这里可以看成谷歌写的一个demo,如果自己想写一个camera HAL的话,可以参考着写。
再继续看hw_get_module_by_class,通过hw_module_exists拿到全路径之后,继续调用load。

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;
#ifdef __ANDROID_VNDK__
    const bool try_system = false;
#else
    const bool try_system = true;
#endif

    
    if (try_system &&
        strncmp(path, HAL_LIBRARY_PATH1, strlen(HAL_LIBRARY_PATH1)) == 0) {
        
        handle = dlopen(path, RTLD_NOW);
    } else {
#if defined(__ANDROID_RECOVERY__)
        handle = dlopen(path, RTLD_NOW);
#else
        handle = android_load_sphal_library(path, RTLD_NOW);
#endif
    }
    if (handle == NULL) {
        char const *err_str = dlerror();
        ALOGE("load: module=%sn%s", path, err_str?err_str:"unknown");
        status = -EINVAL;
        goto done;
    }

    
    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;
    }

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

    hmi->dso = handle;

    
    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, hmi, handle);
    }

    *pHmi = hmi;

    return status;
}

load函数会根据上面传过来的地址通过dlopen打开camera.xxxx.so,这里打开的就是/vendor/lib64/hw/camera.qcom.so。然后再通过HAL_MODULE_INFO_SYM_AS_STR找到对应的符号链接。

#define HAL_MODULE_INFO_SYM_AS_STR  "HMI"

这里为什么要用HMI,自行谷歌搜索,我一开始看到这里也很懵。谷歌搜完了只知道反正就是这么定的,想要用dlsym找到对应的符号,必须要这么写:

camera_module_t HAL_MODULE_INFO_SYM __attribute__ ((visibility("default")))

再用readelf -s camera.xxxx.so可以看到符号表里面有HMI。下面是我拿手机看的符号表:

0000000000802718   344 OBJECT  GLOBAL DEFAULT   23 HMI

既然一定要有camera_module_t HAL_MODULE_INFO_SYM,那就到平台的代码里面找一下。
果然,在平台的代码里面找到了camera_module_t HAL_MODULE_INFO_SYM对应的实现。
到这里就明白了,谷歌只是注册了一个hidl服务,怎么就能调用到平台的代码完成初始化了。
再往下就是平台的具体实现,代码就不贴了,继续回头看bool LegacyCameraProviderImpl_2_4::initialize()函数。
接下来就是初始化module:

mModule = new CameraModule(rawModule);

hardware/interfaces/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.h中定义了:

using ::android::hardware::camera::common::V1_0::helper::CameraModule;

还是和前面一样,先看一下如何使用这个CameraModule的,先看一下hardware/interfaces/camera/common/1.0/default/Android.bp

cc_library_static {
    name: "android.hardware.camera.common@1.0-helper",
    vendor_available: true,
    defaults: ["hidl_defaults"],
    srcs: [
        "CameraModule.cpp",
        "Camerametadata.cpp",
        "CameraParameters.cpp",
        "VendorTagDescriptor.cpp",
        "Handleimporter.cpp",
        "Exif.cpp",
    ],
    cflags: [
        "-Werror",
        "-Wextra",
        "-Wall",
    ],
    shared_libs: [
        "liblog",
        "libgralloctypes",
        "libhardware",
        "libcamera_metadata",
        "android.hardware.graphics.mapper@2.0",
        "android.hardware.graphics.mapper@3.0",
        "android.hardware.graphics.mapper@4.0",
        "libexif",
    ],
    include_dirs: ["system/media/private/camera/include"],
    export_include_dirs: ["include"],
}

cc_library_static说明这是一个静态库,应该直接就link到android.hardware.camera.provider@2.4-impl.so里面了。找了个手机看来一下,果然搜不到这个库,再看一下android.hardware.camera.provider@2.4-impl的编译文件。

cc_library_shared {
   name: "android.hardware.camera.provider@2.4-impl",
   ...
   static_libs: [
       "android.hardware.camera.common@1.0-helper",
   ],
   ...
}

再看CameraModule的构造:

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

因为CameraModule就是相机HAL的一个封装,所以初始化就是要保存camera_module_t到mModule。再继续看initialize函数。调用了err = mModule->init();这个实际上就是camera_module_t的init,平台的代码中实现了init,谷歌原生代码并没有实现这部分。再往下就没有什么特殊的代码就是一些初始化,获取属性,最终将camera状态设置成CAMERA_DEVICE_STATUS_PRESENT。initialize函数初始化完成,返回值是false。。。最终这个值给到mInitFailed。
这里的代码看完,再回到hardware/interfaces/camera/provider/2.4/default/CameraProvider_2_4.cpp中,provider初始化完成,调用provider->isInitFailed()检查是不是init成功。

总结

到这里就全部结束了,上面的流程是按照看代码的过程写的,有点乱,好多细节也没有说,不过也算是梳理了整个代码流程。最主要是说明HAL进程如何加载平台so并且关联到平台代码的。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/310139.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号