1. 传感器HAL框架初探
任务目标
在Android源码树中创建一个传感器HAL模块,实现传感器列表的静态注册。本案例聚焦于HAL模块的骨架搭建与传感器ID的静态声明,不涉及数据上报与动态事件处理。
环境准备
需要一台已配置Android源码编译环境的Linux主机(推荐Ubuntu 18.04+),源码版本建议使用Android 9.0(Pie)或更高。确保source build/envsetup.sh与lunch已正常执行,且具备mmm单模块编译能力。
目录结构创建
在源码树hardware/interfaces/下创建自定义HAL目录(以sensors_demo为例):
hardware/interfaces/sensors_demo/
├── Android.bp
├── sensors_demo.h
└── sensors_demo.cpp
关键完整代码
sensors_demo.h — 定义HAL模块与设备结构体:
#ifndef SENSORS_DEMO_H
#define SENSORS_DEMO_H
#include <hardware/hardware.h>
#include <hardware/sensors.h>
__BEGIN_DECLS
#define SENSORS_DEMO_HAL_ID "sensors_demo"
struct sensors_demo_device_t {
struct sensors_poll_device_1 common;
/* 扩展字段可在此添加 */
};
__END_DECLS
#endif // SENSORS_DEMO_H
sensors_demo.cpp — 实现HAL模块入口与静态传感器列表:
#define LOG_TAG "sensors_demo"
#include <log/log.h>
#include <hardware/hardware.h>
#include <hardware/sensors.h>
#include "sensors_demo.h"
/* 静态注册两个虚拟传感器:加速度计与温度计 */
static struct sensor_t const demo_sensor_list[] = {
{
.name = "Demo Accelerometer",
.vendor = "AOSP",
.version = 1,
.handle = 0x1001,
.type = SENSOR_TYPE_ACCELEROMETER,
.maxRange = 19.6f,
.resolution = 0.01f,
.power = 0.5f,
.minDelay = 10000,
.fifoReservedEventCount = 0,
.fifoMaxEventCount = 0,
.stringType = SENSOR_STRING_TYPE_ACCELEROMETER,
.requiredPermission = "",
.maxDelay = 200000,
.flags = SENSOR_FLAG_CONTINUOUS_MODE,
.reserved = {}
},
{
.name = "Demo Thermometer",
.vendor = "AOSP",
.version = 1,
.handle = 0x1002,
.type = SENSOR_TYPE_AMBIENT_TEMPERATURE,
.maxRange = 100.0f,
.resolution = 0.1f,
.power = 0.3f,
.minDelay = 1000,
.fifoReservedEventCount = 0,
.fifoMaxEventCount = 0,
.stringType = SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE,
.requiredPermission = "",
.maxDelay = 100000,
.flags = SENSOR_FLAG_ON_CHANGE_MODE,
.reserved = {}
}
};
static int sensors_demo_close(struct hw_device_t *dev) {
if (dev) free(dev);
return 0;
}
static int sensors_demo_open(const struct hw_module_t *module,
const char *name,
struct hw_device_t **device) {
if (strcmp(name, SENSORS_HARDWARE_POLL) != 0)
return -EINVAL;
struct sensors_poll_device_1 *poll_dev =
(struct sensors_poll_device_1 *)calloc(1, sizeof(*poll_dev));
if (!poll_dev) return -ENOMEM;
poll_dev->common.tag = HARDWARE_DEVICE_TAG;
poll_dev->common.version = SENSORS_DEVICE_API_VERSION_1_1;
poll_dev->common.module = (struct hw_module_t *)module;
poll_dev->common.close = sensors_demo_close;
/* 静态注册:直接返回传感器列表 */
poll_dev->get_sensors_list = [](struct sensors_poll_device_1 *dev,
struct sensor_t const **list) {
*list = demo_sensor_list;
return ARRAY_SIZE(demo_sensor_list);
};
/* 其余poll接口暂置空,仅保证结构完整 */
poll_dev->activate = nullptr;
poll_dev->setDelay = nullptr;
poll_dev->poll = nullptr;
poll_dev->batch = nullptr;
poll_dev->flush = nullptr;
*device = &poll_dev->common;
return 0;
}
static struct hw_module_methods_t sensors_demo_methods = {
.open = sensors_demo_open,
};
struct sensors_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = SENSORS_MODULE_API_VERSION_0_1,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = SENSORS_HARDWARE_MODULE_ID,
.name = "Demo Sensors HAL",
.author = "AOSP",
.methods = &sensors_demo_methods,
.dso = nullptr,
.reserved = {0},
},
.get_sensors_list = [](struct sensors_module_t *module,
struct sensor_t const **list) {
*list = demo_sensor_list;
return ARRAY_SIZE(demo_sensor_list);
},
};
Android.bp — 模块编译配置:
cc_library_shared {
name: "sensors.demo",
vendor: true,
relative_install_path: "hw",
srcs: ["sensors_demo.cpp"],
shared_libs: [
"liblog",
"libhardware",
],
header_libs: ["libhardware_headers"],
cflags: ["-Wno-unused-parameter"],
}
编译与验证
在源码根目录执行:
source build/envsetup.sh
lunch aosp_arm64-userdebug
mmm hardware/interfaces/sensors_demo/
编译通过后,检查输出文件:
ls $OUT/vendor/lib64/hw/sensors.demo.so
验证方法:将生成的sensors.demo.so推送到设备或模拟器的/vendor/lib64/hw/目录,重启system_server或直接调用SensorManager的getSensorList()接口,观察是否出现名为"Demo Accelerometer"与"Demo Thermometer"的两个传感器。若使用模拟器,可通过adb shell dumpsys sensorservice查看已注册的传感器列表。
判定标准
- 编译无错误,生成
sensors.demo.so动态库; - 设备端
sensorservice能成功加载该HAL模块; - 通过
dumpsys sensorservice或应用层API能枚举出上述两个静态注册的传感器,且名称、类型、vendor字段与代码定义一致。