Camera1 源码解析系列—— Camera1 hw_get_module() 解析
Posted ByteSaid
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Camera1 源码解析系列—— Camera1 hw_get_module() 解析相关的知识,希望对你有一定的参考价值。
前言
这一章,我们将从 hw_get_module()
函数入手,去探究 Libraries
层是如何调用 HAL
层的库中的函数的。
CameraService
是在开机时就会启动的,而当它第一次启动时,就会调用一个名为 onFirstRef()
的成员函数,我们所要探究的内容就是从这里开始的。
1 CameraService
- 路径:
framework/av/services/camera/libcameraservice/CameraService.cpp
CameraService::onFirstRef()
:- 首先调用其基类的
onFirstRef
函数。 - 更新
notifier
(这个BatteryNotifier
好像是个单例,看类名好像和电池有关)。 - 通过
hw_get_module
函数获取rawModule
。 - 注意
rawModule
是camera_module_t
类型。 - 利用
rawModule
创建mModule
的实例,mModule
是CameraModule
类。
- 首先调用其基类的
BnCameraService::onFirstRef();
// Update battery life tracking if service is restarting
BatteryNotifier& notifier(BatteryNotifier::getInstance());
notifier.noteResetCamera();
notifier.noteResetFlashlight();
camera_module_t *rawModule;
/*** NOTE THIS ***/
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);
return;
/*** NOTE THIS ***/
mModule = new CameraModule(rawModule);
err = mModule->init();
2 hardware
2.1 hardware.h
- 路径:
hardware/libhardware/include/hardware/hardware.h
- 注意两个宏定义:
/**
* Name of the hal_module_info
*/
#define HAL_MODULE_INFO_SYM HMI
/**
* Name of the hal_module_info as a string
*/
#define HAL_MODULE_INFO_SYM_AS_STR "HMI"
声明了这两个函数:
hw_get_module()
:- 作用是通过传入的
id
来获取模块相关的信息。 - 成功则返回
0
,出错则返回值小于0
且*module == NULL
。
- 作用是通过传入的
hw_get_module_by_class()
:- 作用是通过
class_id
获取与模块实例相关的信息。 - 提供模块信息的库文件应该是带有这样命名规范的:
- 作用是通过
audio.primary.<variant>.so
audio.a2dp.<variant>.so
/**
* Get the module info associated with a module by id.
*
* @return: 0 == success, <0 == error and *module == NULL
*/
int hw_get_module(const char *id, const struct hw_module_t **module);
/**
* Get the module info associated with a module instance by class 'class_id'
* and instance 'inst'.
*
* Some modules types necessitate multiple instances. For example audio supports
* multiple concurrent interfaces and thus 'audio' is the module class
* and 'primary' or 'a2dp' are module interfaces. This implies that the files
* providing these modules would be named audio.primary.<variant>.so and
* audio.a2dp.<variant>.so
*
* @return: 0 == success, <0 == error and *module == NULL
*/
int hw_get_module_by_class(const char *class_id, const char *inst,
const struct hw_module_t **module);
2.2 hardware.c
- 路径:
hardware/libhardware/hardware.c
- 注意这个数组:
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"
;
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
函数加载模块。
- 读取库文件,尝试的顺序是:
/* 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. */
/*** NOTE THIS ***/
return load(class_id, path, module);
/* 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. */
/*** NOTE THIS ***/
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
层的库函数。
- 为了获取动态链接库中的结构体,我们需要用到一个字符串
- 调用
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
*/
/*** NOTE THIS ***/
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. */
/*** NOTE THIS ***/
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;
/*** NOTE THIS ***/
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;
至此,我们就获得了最终的 rawModule
,然后我们回到 onFirstRef()
中继续分析 CameraModule
。
3 CameraModule
3.1 CameraModule.cpp
- 路径:
frameworks/av/services/camera/libcameraservice/common/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()
:- 调用
mModule
的init()
函数,这个mModule
就是camera_module_t
结构体对象。
- 调用
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;
3.2 camera_common.h
- 路径:
hardware/libhardware/include/hardware/camera_common.h
- 声明了
camera_module_t
:- 结构体中声明了许多函数指针,其中就有
init
函数指针。
- 结构体中声明了许多函数指针,其中就有
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)();
void* reserved[5];
camera_module_t;
那么这些函数指针被映射到什么地方了?hardware
中 CameraHAL.cpp
中提供了原生的映射方法。
3.3 CameraHAL.cpp
- 路径:
hardware/libhardware/modules/camera/3_0/CameraHAL.cpp
camera_module_t HAL_MODULE_INFO_SYM __attribute__ ((visibility("default"))) =
.common =
.tag = HARDWARE_MODULE_TAG,
.module_api_version = CAMERA_MODULE_API_VERSION_2_2,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = CAMERA_HARDWARE_MODULE_ID,
.name = "Default Camera HAL",
.author = "The android Open Source Project",
.methods = &gCameraModuleMethods,
.dso = NULL,
.reserved = 0,
,
.get_number_of_cameras = get_number_of_cameras,
.get_camera_info = get_camera_info,
.set_callbacks = set_callbacks,
.get_vendor_tag_ops = get_vendor_tag_ops,
.open_legacy = NULL,
.set_torch_mode = NULL,
.init = NULL,
.reserved = 0,
;
这是通用的映射,我们手机的芯片一般会重写这个 HAL
层接口,例如使用高通芯片的话,会在 QCamera2Hal.cpp
中重写这个函数映射。不同的芯片会在不同的地方,但是不会相差太大,况且这些函数指针都是一样的,这是 Android HAL
层提供的通用调用方法。
3.4 QCamera2Hal.cpp
- 路径:
hardware/qcom/camera/QCamera2/QCamera2Hal.cpp
- 这个文件中有如下定义:
- 详细描述了
camera_common
。 - 确定了函数指针的指向,
QCamera2Factory::mModuleMethods
- 详细描述了
static hw_module_t camera_common =
.tag = HARDWARE_MODULE_TAG,
.module_api_version = CAMERA_MODULE_API_VERSION_2_4,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = CAMERA_HARDWARE_MODULE_ID,
.name = "QCamera Module",
.author = "Qualcomm Innovation Center Inc",
.methods = &qcamera::QCamera2Factory::mModuleMethods,
.dso = NULL,
.reserved = 0
;
camera_module_t HAL_MODULE_INFO_SYM =
.common = camera_common,
.get_number_of_cameras = qcamera::QCamera2Factory::get_number_of_cameras,
.get_camera_info = qcamera::QCamera2Factory::get_camera_info,
.set_callbacks = qcamera::QCamera2Factory::set_callbacks,
.get_vendor_tag_ops = qcamera::QCamera3VendorTags::get_vendor_tag_ops,
.open_legacy = qcamera::QCamera2Factory::open_legacy,
.set_torch_mode = qcamera::QCamera2Factory::set_torch_mode,
.init = NULL,
.reserved = 0
;
3.5 QCamera2Factory.cpp
- 路径:
hardware/qcom/camera/QCamera2/QCamera2Factory.cpp
struct hw_module_methods_t QCamera2Factory::mModuleMethods =
.open = QCamera2Factory::camera_device_open,
;
int QCamera2Factory::camera_device_open(
const struct hw_module_t *module, const char *id,
struct hw_device_t **hw_device)
int rc = NO_ERROR;
if (module != &HAL_MODULE_INFO_SYM.common)
LOGE("Invalid module. Trying to open %p, expect %p",
module, &HAL_MODULE_INFO_SYM.common);
return INVALID_OPERATION;
if (!id)
LOGE("Invalid camera id");
return BAD_VALUE;
#ifdef QCAMERA_HAL1_SUPPORT
if(gQCameraMuxer)
rc = gQCameraMuxer->camera_device_open(module, id, hw_device);
else
#endif
rc = gQCamera2Factory->cameraDeviceOpen(atoi(id), hw_device);
return rc;
再往下追踪就是芯片中重写的核心方法了,暂时不作深入分析。
4 流程简图
5 总结
本篇我们从 CameraService::onFirstRef()
入手,逐渐理顺了以 hw_get_module()
为中心的一个调用逻辑。实际上,Android HAL
层有一个通用的入口,即宏 HAL_MODULE_INFO_SYM
,通过它,我们获取 HAL
层中的模块实例,从而使得我们可以调用 HAL
层所提供的函数。理解了 HAL
层的入口,接下来我们可以去对 Camera.startPreview()
的控制流程进行分析了。
以上是关于Camera1 源码解析系列—— Camera1 hw_get_module() 解析的主要内容,如果未能解决你的问题,请参考以下文章
Camera1 源码解析系列—— Camera1 startPreview() 流程解析
Camera1 源码解析系列—— Camera1 Open() 流程解析
Camera1 源码解析系列—— Camera1 takePicture() 流程解析