Android Sensor Input类型 (四) Sensor HAL 实现

2024-04-18 10:58

本文主要是介绍Android Sensor Input类型 (四) Sensor HAL 实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

msm8909 Sensor HAL

代码路径:code/hardware/qcom/sensors/

核心作用:封装对 sensor的方法,不直接通过本地C库直接访问

├── Accelerometer.cpp
├── AccelSensor.h
├── AkmSensor.cpp
├── AkmSensor.h
├── algo
├── Android.mk
├── Bmp180.cpp
├── CalibrationManager.cpp
├── CalibrationManager.h
├── CalibrationModule.h
├── calmodule.cfg
├── CompassSensor.cpp
├── CompassSensor.h
├── Gyroscope.cpp
├── GyroSensor.h
├── InputEventReader.cpp
├── InputEventReader.h
├── LICENSE
├── LightSensor.cpp
├── LightSensor.h
├── NativeSensorManager.cpp
├── NativeSensorManager.h
├── PressureSensor.h
├── ProximitySensor.cpp
├── ProximitySensor.h
├── SensorBase.cpp
├── SensorBase.h
├── sensors.cpp
├── sensors_extension.h
├── sensors.h
├── sensors_XML.cpp
├── sensors_XML.h
├── SignificantMotion.cpp
├── SignificantMotion.h
├── VirtualSensor.cpp
└── VirtualSensor.h

重要文件有:

sensors.cpp

sensors.cpp 中提供数据机构架构,提供 hw_device_t 封装; 让其他层可以获得这个结构,得以使用其中的方法;

通过实现的结构可以发现,所有的操作都使用了, NativeSensorManager用来做具体的操作

NativeSensorManager.cpp

Native SensorManager 是个class,继承Singleton; 单例模式,只存在一个对象;

即被多次定义引用的对象 sm; 它的存在是统一管理sensor HAL的sensor访问;

将存在的sensor统一存在数组里,不针对sensor具体类型; 是HAL的实际操作者;

SensorBase.cpp

VirtualSensor.cpp

sensors主要设备结构

sensor_t

struct sensor_t {const char*     name;//!< sensor名称 By: jixuanconst char*     vendor;//!< 厂商名 By: jixuan int             version;int             handleint             type;//!< 类型标识 By: jixuanfloat           maxRange;float           resolution;//!< 解析度 即报告数值的最大差异范围 By: jixuan float           power;int32_t         minDelay;uint32_t        fifoReservedEventCount;uint32_t        fifoMaxEventCount;//!< 类型字符串 Note By: yujixuan const char*    stringType;//!< 权限 Note By: yujixuan const char*    requiredPermission;void*           reserved[2];
};

sensor_moudule_t

struct sensors_module_t {struct hw_module_t common;//!< hw_module_t 基础结构 >! NoteBy: yujixuan int (*get_sensors_list)(struct sensors_module_t* module,struct sensor_t const** list);//!< 拓展接口,获取sensor 列表 >! NoteBy:yujixuanint (*set_operation_mode)(unsigned int mode);//!< 操作设置sensor mode >! NoteBy: yujixuan
};//!< 定义 名为HMI的 hw_module_t 结构体(可以转型为包含它的具体设备类型,首地址保持相同),get_module 获取它 >! NoteBy: yujixuan
struct sensors_module_t HAL_MODULE_INFO_SYM = {common: {tag: HARDWARE_MODULE_TAG,  //!< 固定名 >! NoteBy: yujixuanversion_major: 1,version_minor: 0,id: SENSORS_HARDWARE_MODULE_ID, name: "Quic Sensor module",author: "Quic",methods: &sensors_module_methods,  //!< hw_module_t 必要填充的方法 >! NoteBy: yujixuandso: NULL,reserved: {0},},get_sensors_list: sensors__get_sensors_list,  //!< sensor_module_t 拓展的方法 >! NoteBy: yujixuan
};
static struct hw_module_methods_t sensors_module_methods = {open: open_sensors  //!< 只有一个open函数,它的作用是返回具体的 device >! NoteBy: yujixuan
};
//!< 打开一个新的sensor 实例 填充具体的hw_device_t>! NoteBy: yujixuan

open函数实现:open_sensors

#define HAL_MODULE_INFO_SYM        HMI
#define HAL_MODULE_INFO_SYM_AS_STR  "HMI"static int open_sensors(const struct hw_module_t* module, const char*,struct hw_device_t** device)
{int status = -EINVAL;sensors_poll_context_t *dev = new sensors_poll_context_t();NativeSensorManager& sm(NativeSensorManager::getInstance());memset(&dev->device, 0, sizeof(sensors_poll_device_1_ext_t));dev->device.common.tag = HARDWARE_DEVICE_TAG;
#if defined(SENSORS_DEVICE_API_VERSION_1_3)ALOGI("Sensors device API version 1.3 supported\n");dev->device.common.version = SENSORS_DEVICE_API_VERSION_1_3;
#elsedev->device.common.version = SENSORS_DEVICE_API_VERSION_0_1;
#endifdev->device.common.module   = const_cast<hw_module_t*>(module);dev->device.common.close	= poll__close;dev->device.activate		= poll__activate;dev->device.setDelay		= poll__setDelay;dev->device.poll		= poll__poll;dev->device.calibrate		= poll_calibrate;
#if defined(SENSORS_DEVICE_API_VERSION_1_3)dev->device.batch		= poll__batch;dev->device.flush		= poll__flush;
#endif*device = &dev->device.common;status = 0;return status;
}

open_sensors新的sensor 实例,首先new了一个sensors_poll_context_tdevice ,然后设置该device,并返回 给到调用者;

针对 sensors_poll_context_t 下面内容会做具体分析;

static int sensors__get_sensors_list(struct sensors_module_t*,struct sensor_t const** list)
{NativeSensorManager& sm(NativeSensorManager::getInstance());return sm.getSensorList(list);
}

拓展的sensors_module_t 中添加了 get_sensor_list方法;

可以看到它是通过NativeSensorManger 来做具体的Hal层访问;

Sensor服务用户程序不能直接访问,通过NativeSensorManager来访问。 (note: nativeSensorManager是指在HAL中的管理sensor的设备结构,需要区别于Android Framework中的SensorManager)

里面使用了NativeSensorManagersensors__get_sensors_list函数中调用单例模式创建了一个实例sm,通过调用其中的成员函数获取传感器列表,并返回,返回值对应的sensor_t结构体;NativeSensorManager统一管理着所有的传感器、物理和虚拟传感器;

SensorHAL 解析

Native Sensor Hal框架中,最为主要的内容即是 open函数中对device的回调设置;简单的可以理解为是上层函数与调用底层驱动的桥接;

所以在Hal这个层次应着重分析这块内容;,由上可知,当前的代码里是通过sensors_poll_context_t来定义一个device; 以下是 sensors_poll_context_t 的内容:

sensors_poll_context_t

struct sensors_poll_context_t {// extension for sensors_poll_device_1, must be firststruct sensors_poll_device_1_ext_t device;// must be first//!< 必须放在首个位置,它是个联合体,首个属性是 hw_device_t; >! NoteBy: yujixuansensors_poll_context_t();~sensors_poll_context_t();//!<struct同样有构造函数,析构函数,完成重要的初始化功能 >! NoteBy: yujixuanint activate(int handle, int enabled);int setDelay(int handle, int64_t ns);int pollEvents(sensors_event_t* data, int count);int calibrate(int handle, cal_cmd_t *para);int batch(int handle, int sample_ns, int latency_ns);int flush(int handle);private:static const size_t wake = MAX_SENSORS;static const char WAKE_MESSAGE = 'W';struct pollfd mPollFds[MAX_SENSORS+1];int mWritePipeFd;SensorBase* mSensors[MAX_SENSORS];mutable Mutex mLock;
};

通过open函数返回的的是hw_device_t,实际是传入的地址值;只要保证,包含此结构,且sensors_poll_device_1_ext_t放在首位,可以向上转型回具体的sensor

设备device;

实际device的函数调用 都是拓展的;比如上面的 activate; setDelay; pollEvents;等;

struct sensors_poll_device_1_ext_t {union {struct sensors_poll_device_1 aosp;struct {struct hw_device_t common;int (*activate)(struct sensors_poll_device_t *dev,int handle, int enabled);int (*setDelay)(struct sensors_poll_device_t *dev,int handle, int64_t period_ns);int (*poll)(struct sensors_poll_device_t *dev,sensors_event_t* data, int count);int (*batch)(struct sensors_poll_device_1* dev,int handle, int flags, int64_t period_ns, int64_t timeout);int (*flush)(struct sensors_poll_device_1* dev, int handle);void (*reserved_procs[8])(void);};};struct sensors_poll_device_t {struct hw_device_t common;int (*activate)(struct sensors_poll_device_t *dev,int sensor_handle, int enabled);int (*setDelay)(struct sensors_poll_device_t *dev,int sensor_handle, int64_t sampling_period_ns);int (*poll)(struct sensors_poll_device_t *dev,sensors_event_t* data, int count);
};

通过sensors_poll_device_1_ext_t也可以看出,实际sensors_poll_context_t 可以是sensors_poll_device_t

这是面向对象 多态的思想方式; 获取到的device根据具体的类型,再转换为具体的 device进行函数调用;

实际device的函数调用 都是拓展的;比如上面的 activate; setDelay; pollEvents;等;

在open函数中,new一个实例对象;sensors_poll_context_t会调用其构造函数完成最重要的初始化功能,如下:

sensors_poll_context_t::sensors_poll_context_t()
{int number;int i;const struct sensor_t *slist; const struct SensorContext *context;NativeSensorManager& sm(NativeSensorManager::getInstance());number = sm.getSensorList(&slist);//!< 获取sensor个数; 与sensor构成的链表list >! NoteBy: yujixuan/* use the dynamic sensor list */for (i = 0; i < number; i++) {context = sm.getInfoByHandle(slist[i].handle);mPollFds[i].fd = (context == NULL) ? -1 : context->data_fd;mPollFds[i].events = POLLIN;mPollFds[i].revents = 0;}ALOGI("The avaliable sensor handle number is %d",i);int wakeFds[2];int result = pipe(wakeFds);ALOGE_IF(result<0, "error creating wake pipe (%s)", strerror(errno));fcntl(wakeFds[0], F_SETFL, O_NONBLOCK);fcntl(wakeFds[1], F_SETFL, O_NONBLOCK);mWritePipeFd = wakeFds[1];mPollFds[number].fd = wakeFds[0];mPollFds[number].events = POLLIN;mPollFds[number].revents = 0;
}

构造函数中,通过NativeSensorManager 获取了sensor 列表;

通过struct SensorContext *context;

context = sm.getInfoByHandle(slist[i].handle);

维系记录了handle对应的SensorContext对象指针的句柄;SensorContext 的结构如下:

SensorContext

struct SensorContext {char   name[SYSFS_MAXLEN]; // name of the sensorchar   vendor[SYSFS_MAXLEN]; // vendor of the sensorchar   enable_path[PATH_MAX]; // the control path of this sensorchar   data_path[PATH_MAX]; // the data path to get sensor eventsstruct sensor_t *sensor; // point to the sensor_t structure in the sensor listSensorBase     *driver; // point to the sensor driver instanceint data_fd; // the file descriptor of the data device nodeint enable; // indicate if the sensor is enabledbool is_virtual; // indicate if this is a virtual sensorint64_t delay_ns; // the poll delay setting of this sensorint64_t latency_ns; // the max report latency of this sensorstruct listnode dep_list; // the background sensor type needed for this sensorstruct listnode listener; // the head of listeners of this sensor
};

从上可以看出: SensorContext中的 SensorBase *driver; 指向了具体的sensor实例;

在构造函数中,还完成了pollfd即mPollFds用来监听senso时用的文件描述符;

open函数的后面的部分,也就是对sensors_poll_context_t 拓展的那些方法的链接;

比如:

        dev->device.common.close    = poll__close;dev->device.activate        = poll__activate;dev->device.setDelay        = poll__setDelay;dev->device.poll        = poll__poll;dev->device.calibrate        = poll_calibrate;

poll函数分析

这里分析下,最重要的一个函数 poll__poll;

static int poll__poll(struct sensors_poll_device_t *dev,sensors_event_t* data, int count) {sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;//!< 这里就用到了 向上转型;将sensor_poll_device_t 转为 sensor_poll_context_t >! NoteBy: yujixuanreturn ctx->pollEvents(data, count);//!< 返回pollEvents >! NoteBy: yujixuan
}
int sensors_poll_context_t::pollEvents(sensors_event_t* data, int count)
{int nbEvents = 0;int n = 0;NativeSensorManager& sm(NativeSensorManager::getInstance());const sensor_t *slist;int number = sm.getSensorList(&slist);do {// see if we have some leftover from the last poll()for (int i = 0 ; count && i < number ; i++) {if ((mPollFds[i].revents & POLLIN) || (sm.hasPendingEvents(slist[i].handle))) {Mutex::Autolock _l(mLock);int nb = sm.readEvents(slist[i].handle, data, count);if (nb < 0) {ALOGE("readEvents failed.(%d)", errno);return nb;}if (nb <= count) {// no more data for this sensormPollFds[i].revents = 0;}count -= nb;nbEvents += nb;data += nb;}}if (count) {// we still have some room, so try to see if we can get// some events immediately or just wait if we don't have// anything to returndo {n = poll(mPollFds, number + 1, nbEvents ? 0 : -1);} while (n < 0 && errno == EINTR);if (n<0) {ALOGE("poll() failed (%s)", strerror(errno));return -errno;}if (mPollFds[number].revents & POLLIN) {char msg;int result = read(mPollFds[number].fd, &msg, 1);ALOGE_IF(result<0, "error reading from wake pipe (%s)", strerror(errno));ALOGE_IF(msg != WAKE_MESSAGE, "unknown message on wake queue (0x%02x)", int(msg));mPollFds[number].revents = 0;}}// if we have events and space, go read them} while (n && count);return nbEvents;
}

主要函数:sm.readEvents(slist[i].handle, data, count);

NativeSensorManager::readEvents中调用了:

nb = list->driver->readEvents(data, count);

list->driver是一个SensorBase结构体,SensorBase结构体的函数readEvents,

这里就需要联合 nativesensormanger的实现来看具体的读取流程;

nativesensormanger相关内容,在后续的内容中分析;

这篇关于Android Sensor Input类型 (四) Sensor HAL 实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/914588

相关文章

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1

MySQL8.0设置redo缓存大小的实现

《MySQL8.0设置redo缓存大小的实现》本文主要在MySQL8.0.30及之后版本中使用innodb_redo_log_capacity参数在线更改redo缓存文件大小,下面就来介绍一下,具有一... mysql 8.0.30及之后版本可以使用innodb_redo_log_capacity参数来更改

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque