hardware 主要的三个结构体。
// hardware/libhardware/include_all/hardware/hardware.h
struct hw_module_t;
struct hw_module_methods_t;
struct hw_device_t;
hw_module_t
使用方式:
- 每个硬件模块都必须有一个名为 HAL_MODULE_INFO_SYM 的数据结构。
- 并且此数据结构的字段必须以 hw_module_t 开头。
- 随后是模块特定信息。
举例:输入设备
// hardware/libhardware/include_all/hardware/input.h
struct input_module {
// 此数据结构的字段必须以 hw_module_t 开头。
struct hw_module_t common;
// 随后是模块特定信息。
void (*init)(const input_module_t* module, input_host_t* host, input_host_callbacks_t cb);
void (*notify_report)(const input_module_t* module, input_report_t* report);
};
// hardware/libhardware/modules/input/evdev/EvdevModule.cpp
// 每个硬件模块都必须有一个名为 HAL_MODULE_INFO_SYM 的数据结构,包括输入模块。
input_module_t HAL_MODULE_INFO_SYM = {
};
hw_module_t::tag 要求该值只能是 HARDWARE_MODULE_TAG ,用于标识该结构体属于硬件模块结构体。
举例:输入设备
// hardware/libhardware/modules/input/evdev/EvdevModule.cpp
input_module_t HAL_MODULE_INFO_SYM = {
.common = {
// 该值只能是 HARDWARE_MODULE_TAG
.tag = HARDWARE_MODULE_TAG,
},
};
hw_module_t::id 使用 id 来区分不同硬件模块。
hw_module_t::methods
// hardware/libhardware/include_all/hardware/hardware.h
// 硬件模块对应的 方法结构体。
struct hw_module_methods_t* methods;
hw_module_methods_t
只有一个 open 函数指针。
打开后将获取到的硬件设备信息放入双重指针指向的 hw_device_t 结构体。
// hardware/libhardware/include_all/hardware/hardware.h
typedef struct hw_module_methods_t {
/**
* 函数指针。
* 用于打开硬件模块对应的一个硬件设备。
*
* module 为硬件模块。
* id 为硬件设备 ID。
* device 为双重指针,打开后获取硬件设备信息。
*/
int (*open)(const struct hw_module_t* module, const char* id,
struct hw_device_t** device);
} hw_module_methods_t;
hw_device_t
使用方式:
- 每个设备数据结构都必须以 hw_device_t 开头。
- 随后是模块特定的公共方法和属性。
举例:摄像头
// hardware/libhardware/include_all/hardware/camera3.h
// 摄像头硬件设备的结构体
typedef struct camera3_device {
// 每个设备数据结构都必须以 hw_device_t 开头。
hw_device_t common;
// 随后是模块特定的公共方法和属性。
camera3_device_ops_t *ops;
void *priv;
} camera3_device_t;
hw_device_t::tag 要求该值只能是 HARDWARE_DEVICE_TAG ,用于标识该结构体属于硬件设备结构体。
举例:摄像头
// hardware/libhardware/modules/camera/3_4/camera.cpp
Camera::Camera(int id)
{
// 该值只能是 HARDWARE_DEVICE_TAG ,用于标识该结构体属于硬件设备结构体。
mDevice.common.tag = HARDWARE_DEVICE_TAG;
}
hw_device_t::close
函数指针,用于关闭硬件设备。
// hardware/libhardware/include_all/hardware/hardware.h
typedef struct hw_device_t {
// 函数指针,用于关闭硬件设备。
int (*close)(struct hw_device_t* device);
} hw_device_t;
hardware module 接口的使用方式
hw_get_module 获取一个硬件模块的指针。
// hardware/libhardware/tests/camera3/camera3test_fixtures.h
class Camera3Module : public testing::Test {
protected:
virtual void SetUp() {
const hw_module_t *hw_module = NULL;
// 获取一个硬件模块的指针。
ASSERT_EQ(0, hw_get_module(CAMERA_HARDWARE_MODULE_ID, &hw_module))
<< "Can't get camera module";
cam_module_ = reinterpret_cast<const camera_module_t*>(hw_module);
}
const camera_module_t * cam_module() { return cam_module_; }
};
hw_module_methods_t::open 获取一个硬件设备的指针。
// hardware/libhardware/tests/camera3/camera3test_fixtures.h
class Camera3Device : public Camera3Module {
protected:
virtual void SetUp() {
Camera3Module::SetUp();
hw_device_t *device = NULL;
// 获取一个硬件设备的指针。
ASSERT_EQ(0, cam_module()->common.methods->open(
(const hw_module_t*)cam_module(), "0", &device))
<< "Can't open camera device";
cam_device_ = reinterpret_cast<camera3_device_t*>(device);
}
camera3_device_t* cam_device() { return cam_device_; }
};
调用具体的hal实现方法。
// hardware/libhardware/tests/camera3/camera3tests.cpp
TEST_F(Camera3Device, DefaultSettingsStillCaptureHasAndroidControlMode) {
// 调用具体的hal实现方法。
const camera_metadata_t *default_settings =
cam_device()->ops->construct_default_request_settings(cam_device(),
CAMERA3_TEMPLATE_STILL_CAPTURE);
}
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);
}
hw_get_module_by_class
- 将硬件模块 ID 赋值给 name
- 将 name 拼接到 ro.hardware. 后面,赋值给 prop_name
- 查询 prop_name 对应的动态库,存在的话,直接加载。
- 变体属性。
- 默认属性。
// hardware/libhardware/hardware.c
static const char *variant_keys[] = {
"ro.hardware",
"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)
{
// 将硬件模块 ID 赋值给 name
strlcpy(name, class_id, PATH_MAX);
// 将 name 拼接到 ro.hardware. 后面,赋值给 prop_name
snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
// 查询该属性。
if (property_get(prop_name, prop, NULL) > 0) {
// 该属性对应的 so 动态库是否存在。
if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
goto found;
}
}
// 遍历变体属性。
for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
if (property_get(variant_keys[i], prop, NULL) == 0) {
continue;
}
// 变体属性对应的 so 动态库是否存在。
if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
goto found;
}
}
// 默认属性对应的 so 动态库是否存在。
if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
goto found;
}
return -ENOENT;
found:
// 加载动态库。
return load(class_id, path, module);
}
hw_module_exists
- 检查是否存在具有给定名称和子名称的HAL,如果存在,则返回0,否则返回负数。
- /odm/lib64/hw
- /vendor/lib64/hw
- /system/lib64/hw
// hardware/libhardware/hardware.c
#define HAL_LIBRARY_SUBDIR "lib64/hw"
#define HAL_LIBRARY_PATH1 "/system/" HAL_LIBRARY_SUBDIR
#define HAL_LIBRARY_PATH2 "/vendor/" HAL_LIBRARY_SUBDIR
#define HAL_LIBRARY_PATH3 "/odm/" HAL_LIBRARY_SUBDIR
/*
* 检查是否存在具有给定名称和子名称的HAL,如果存在,则返回0,否则返回负数。
*/
static int hw_module_exists(char *path, size_t path_len, const char *name,
const char *subname)
{
// /odm/lib64/hw
if (path_in_path(path, HAL_LIBRARY_PATH3) && access(path, R_OK) == 0)
return 0;
// /vendor/lib64/hw
if (path_in_path(path, HAL_LIBRARY_PATH2) && access(path, R_OK) == 0)
return 0;
// /system/lib64/hw
if (path_in_path(path, HAL_LIBRARY_PATH1) && access(path, R_OK) == 0)
return 0;
return -ENOENT;
}
load
- 运行时加载硬件的动态库
- dlopen 打开动态库。通过它,可以在程序运行时加载动态链接库(.so 文件)
- dlsym 获取结构体 hal_module_info 的地址。通过它,可以在运行时加载和使用动态链接库中的函数或变量。
// hardware/libhardware/hardware.c
/**
* 加载变量定义的文件,如果成功,返回 dlopen 句柄和 hmi
*/
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;
// dlopen
handle = dlopen(path, RTLD_NOW);
// 获取结构体 hal_module_info 的地址。
const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
// dlsym
hmi = (struct hw_module_t *)dlsym(handle, sym);
// dlopen 句柄保存在 hal_module_info中。
hmi->dso = handle;
// 标记成功。
status = 0;
*pHmi = hmi;
return status;
}
HAL 层动态库的意义
使用动态库的方式目的是保护硬件厂商的利益,适配 Android 平台无需将操作硬件的代码开源出来。
参考链接: