Camera Provider注册、初始化、调用时序图_独家原创

目录

一. Android Camera Architecture整体架构

二. Camera Provider注册时序图

三. Camera Provider初始化时序图:

四. CameraProvider与CameraService、CameraHAL交互

五. CameraService调用CameraProvider


一. Android Camera Architecture整体架构

首先来看Camera Provider的位置:

Camera Provider正是包含v4l2 camera hal的核心模块,负责与虚拟Camera节点的交互。

对于各个模块关键作用如下:

  • Camera Frameworkjar包形式运行在app进程中,实现了Camera Api v2标准接口,通过Camera AIDL跨进程接口将请求发送至Camera Service
  • Camera Service独立进程。通过HIDL跨进程接口将请求再次下发到Camera Provider
  • Camera Provider独立进程。内部加载了Camera HAL ModuleModuleOEM/ODM实现,遵循谷歌制定的标准Camera HAL3接口
  • Camera Driver: LINUX为视频采集设备制定了标准的V4L2接口,并在内核中实现了其基础框架V4L2 Core,视频采集设备驱动厂商按照V4L2 Core的要求开发自己的驱动程序

一图胜千言,对照图走一遍流程自然全部理解。

二. Camera Provider注册时序图

三. Camera Provider初始化时序图:

在hw_get_module查找camera.xxx.so文件时,关键部分代码如下:

/*
 * Check if a HAL with given name and subname exists, if so return 0, otherwise
 * otherwise return negative.  On success path will contain the path to the HAL.
 */
static int hw_module_exists(char *path, size_t path_len, const char *name,
                            const char *subname)
{
    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH3, name, subname);
    if (path_in_path(path, HAL_LIBRARY_PATH3) && access(path, R_OK) == 0)
        return 0;

    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH2, name, subname);
    if (path_in_path(path, HAL_LIBRARY_PATH2) && access(path, R_OK) == 0)
        return 0;

#ifndef __ANDROID_VNDK__
    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH1, name, subname);
    if (path_in_path(path, HAL_LIBRARY_PATH1) && access(path, R_OK) == 0)
        return 0;
#endif

    return -ENOENT;
}

path即为so文件路径,是通过三个字符串拼接而成。第一个字符串HAL_LIBRARY_PATH1/2/3即为时序图中列出的三个路径,第二个字符串name为传入的camera,第三个字符串需要注意,首先会先判断ro.hardware.camera是否为空,对于v4l2 camera hal而言,ro.hardware.camera=v4l2,因此第三个字符串为v4l2,最后找的so也就是camera.v4l2.so。如果ro.hardware.camera为空,则从系统中四个prop属性中获取,如下:

static const char *variant_keys[] = {
    "ro.hardware",  /* This goes first so that it can pick up a different
                       file on the emulator. */
    "ro.product.board",
    "ro.board.platform",
    "ro.arch"
};

static const int HAL_VARIANT_KEYS_COUNT =
    (sizeof(variant_keys)/sizeof(variant_keys[0]));

...

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 */
    // 此处为 ro.hardware.camera
    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);
}

使用adb shell getprop ro.hardware等共四个,可获取到对应值,高通芯片一般ro.hardware=qcom。

用dlopen查找存在对应名字的so,再用dlsym获取HAL_MODULE_INFO_SYM函数地址找到camera_module_t地址即为hal入口地好址,进而调用hal的各个接口。各个接口由OEM厂商进行具体实现,开发可在此基础上自行修改、新增,但修改的接口要符合Camera v2标准。

四. CameraProvider与CameraService、CameraHAL交互

1. CameraService进程通信

CameraProvider进程主要是使用了HIDL直通式的方式注册了ICameraProvider.hal中的服务端,这个是用来给CameraService进程来主动调用

ICameraProvider.hal里面会有setCallback的函数主要是通过回调的形式让CameraService进程接收CameraProvider进程主动发送的消息。

2. 加载CameraHAL的so库

CameraProvider初始化时通过hw_module_get()加载对应的so库,获取到camera_module_t对象之后赋值给CameraModule,然后在CameraModule中通过camera_module_t获取摄像头的信息以及后续对摄像头进行操作

五. CameraService调用CameraProvider

上面已经提到,系统启动时CameraProvider就已经注册,那么CameraService如何调用CameraProvider呢?

起点在/frameworks/av/camera/cameraserver/main_cameraserver.cpp

CameraService::instantiate();

这里需要注意CameraService继承自几个类:

class CameraService :
    public BinderService<CameraService>,
    public virtual ::android::hardware::BnCameraService,
    public virtual IBinder::DeathRecipient,
    public virtual CameraProviderManager::StatusListener

其中,BinderService实现了instantiate()方法。其中CameraService被强指针引用,首次被强指针引用会调到CameraService::onFirstRef()方法中,一路调到CameraProviderManager:

sp<provider::V2_4::ICameraProvider> interface;
interface = mServiceProxy->tryGetService(providerName);
...
providerInfo->initialize(interface, mDeviceState);
...
mProviders.push_back(providerInfo);

通过ProviderInfo来保存当前Camera Provider信息。

具体见以下博客:

Android Camera Provider and Service 启动流程_信田君9527的博客-CSDN博客_android.hardware.camera.provider

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值