news 2026/4/23 12:41:21

高通SEE架构深度解析(2): Sensor HAL层代码实战与ADSP通信

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
高通SEE架构深度解析(2): Sensor HAL层代码实战与ADSP通信

上一篇文章我们梳理了高通SEE架构的原理与核心组件,了解到SEE作为传感器“中枢”,向上对接客户端、向下管理硬件的核心逻辑。本文将聚焦代码实战与硬件协同两大维度:一方面解析Sensor HAL层的关键代码结构与编译配置,带您看懂高通SEE的软件实现;另一方面深入ADSP(应用专用处理器)与SEE的通信机制,揭秘传感器数据在“应用层-硬件层”之间的流转路径。

一、SensorHAL层:SEE与Android的桥梁

在Android中,SEE通过SensorHAL层对接上层SensorService,屏蔽硬件差异,将SEE接口封装为Android标准HIDL接口。

1. 关键目录结构

高通SEE的Sensor HAL代码主要存放在vendor/qcom/proprietary/sensors-see/ 目录下(高通 proprietary 代码仓),该目录包含HAL实现、驱动适配、测试工具等核心模块,关键子目录功能如下:

vendor/qcom/proprietary/sensors-see/ ├── sensors-hal/ # HAL核心实现 ├── hal-2.0-hidl-impl/ # HIDL 2.0接口 ├── sensordaemon/ # 传感器守护进程 ├── QSensorTest/ # 测试工具 ├── reverserpc/ # 跨进程通信 └── nanopb/ # Protocol Buffers编解码

以sensors-hal/目录为例,其下的sensors/子目录是传感器驱动的“聚集地”,sensors_list.txt文件会列出当前设备支持的所有传感器,例如:

sensors_list.txt 示例

accelerometer:qti,accel,SUID_ACC_001 gyroscope:qti,gyro,SUID_GYRO_001 temperature:qti,temp,SUID_TEMP_001 proximity:qti,prox,SUID_PROX_001

每行对应一个传感器,格式为“传感器类型:厂商:驱动名:SUID”,HAL层会根据该列表加载对应的驱动模块。

2. 核心文件解析
  • ISensors.hal:Android标准HIDL接口定义
  • Sensors.cpp:HIDL接口实现,转发调用至SEE
  • sns_sensor.h:SEE传感器核心结构体定义

(1)ISensors.hal:HIDL接口定义
该文件是Android系统定义的传感器HAL标准接口,位于hardware/interfaces/sensors/1.0/ISensors.hal,定义了上层调用HAL的核心方法,例如:

// ISensors.hal 核心方法 interface ISensors { // 获取传感器列表 getSensorsList() generates (vec<SensorInfo> sensors); // 开启/关闭传感器 activate(int32_t sensorHandle, bool enabled) generates (Status status); // 设置采样率与批处理参数 batch(int32_t sensorHandle, int64_t samplingPeriodNs, int64_t maxReportLatencyNs) generates (Status status); // 读取传感器数据 poll(vec<Event>* events, vec<Fence>* fences) generates (Status status); // 刷新传感器缓冲区 flush(int32_t sensorHandle) generates (Status status); };

高通SEE的HAL层(sensors-hal/)需实现这些方法,并将其映射到SEE的内部接口(如set_client_request()、collect_data())。

(2)Sensors.cpp:HAL接口实现
hardware/interfaces/sensors/1.0/default/Sensors.cpp是HIDL接口的具体实现文件,编译后生成android.hardware.sensors@1.0-impl.so库。该文件的核心逻辑是“将Android HIDL调用转发到SEE”,例如activate()方法的实现:

// Sensors.cpp 中 activate() 方法示例 Return<Status> Sensors::activate(int32_t sensorHandle, bool enabled) { // 1. 根据sensorHandle获取SEE中的传感器SUID std::string sensorSuid = getSuidByHandle(sensorHandle); if (sensorSuid.empty()) { return Status::BAD_VALUE; } // 2. 构造SEE的请求参数(开启/关闭传感器) sns_sensor_request request; request.sensor_suid = sensorSuid; request.enable = enabled; // 3. 调用SEE的内部接口发送请求 status_t ret = see_send_request(&request); if (ret != NO_ERROR) { return Status::INTERNAL_ERROR; } return Status::OK; }

其中,see_send_request()是HAL层与SEE核心服务通信的关键函数,通过ReverseRPC或QMI协议将请求发送到SEE的服务管理器。

(3)sns_sensor.h:SEE传感器核心结构体
在SEE的内部实现中,所有传感器都通过sns_sensor结构体描述,该文件位于slpi_proc/ssc/inc/sns_sensor.h(SLPI是高通传感器低功耗岛处理器),定义了传感器的核心接口与状态:

// sns_sensor.h 核心结构体 typedef struct sns_sensor { // 传感器回调函数(如事件通知) sns_sensor_cb const *cb; // 传感器API(如创建实例、获取SUID) sns_sensor_api const *api; // 传感器状态(如是否激活、当前采样率) sns_sensor_state const *state; // 传感器实例列表 struct sns_sensor_instance **instances; // 实例数量 uint32_t num_instances; } sns_sensor; // 传感器核心API typedef struct sns_sensor_api { // 创建传感器实例 sns_sensor_instance* (*create_instance)(struct sns_sensor *sensor); // 移除传感器实例 void (*remove_instance)(struct sns_sensor *sensor, sns_sensor_instance *instance); // 获取传感器SUID sns_suid const* (*get_sensor_uuid)(struct sns_sensor *sensor); // 处理客户端请求 void (*set_client_request)(struct sns_sensor *sensor, sns_sensor_instance *instance, sns_request const *request); } sns_sensor_api;

该结构体是SEE“传感器实例化机制”的核心——每个传感器可创建多个实例,实例根据客户端请求的配置(如不同采样率)独立运行,实现“一传感器多场景适配”。

3. 编译配置

高通SEE的Sensor HAL层通过Android.mk与Android.bp(Soong编译系统)实现编译,关键配置文件如下:

  • Android.mk/Android.bp:模块编译规则
  • android.hardware.sensors@1.0-service.rc:服务启动配置

(1)sensors-hal/Android.mk
该文件定义sensors-hal模块的编译规则,指定源文件、依赖库与输出目标:

# Android.mk 示例 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # 模块名 LOCAL_MODULE := sensors-see-hal # 源文件(核心实现) LOCAL_SRC_FILES := framework/sns_hal.cpp \ sensors/sns_temp_sensor.cpp \ sensors/sns_accel_sensor.cpp # 依赖库(SEE核心库、nanopb协议库) LOCAL_SHARED_LIBRARIES := libsee-core \ libnanopb \ liblog # 头文件路径 LOCAL_C_INCLUDES := $(LOCAL_PATH)/inc \ $(TOP)/vendor/qcom/proprietary/sensors-see/nanopb/inc # 编译输出为共享库 include $(BUILD_SHARED_LIBRARY)

编译后会生成libsee-hal.so,供Sensor HAL服务加载。

(2)Android.hardware.sensors@1.0-service.rc
这是Sensor HAL服务的启动配置文件,位于hardware/interfaces/sensors/1.0/default/,定义了服务的启动时机与权限:

# 服务名称与可执行文件路径 service vendor.sensors-hal-1-0 /vendor/bin/hw/android.hardware.sensors@1.0-service # 声明HIDL接口(对接上层SensorService) interface android.hardware.sensors@1.0::ISensors default # 服务类型(hal类,随系统boot阶段启动) class hal # 权限配置(访问传感器硬件的权限) user system group system input

系统启动时,会在boot阶段执行class_start hal,启动该服务,进而加载libsee-hal.so与SEE核心模块。

二、ADSP与SEE通信:QMI协议详解

1. ADSP的角色
  • 低功耗:处理传感器数据的功耗仅为AP的1/10
  • 高实时性:微秒级调度延迟
  • 硬件隔离:数据在ADSP内处理,提升安全性
2. QMI通信流程
AP(HAL层) --QMI请求--> ADSP(SEE模块) ↑ ↓ 配置传感器 处理请求 ↑ ↓ AP(HAL层) <--QMI响应-- ADSP(SEE模块)

核心流程(以“设置采样率”为例)
2.1.AP侧(HAL层)发送请求

  • HAL层调用batch(sensor_type, period)方法(如设置温度传感器采样率为1Hz);
  • 通过qsh_qmi()函数(QMI接口封装)构造QMI消息,消息内容包含:传感器SUID、请求类型(设置采样率)、参数(period=1000ms);
  • 调用send_sync_sensor_request(suid)将QMI消息通过RPC通道发送到ADSP。

2.2.ADSP侧(SEE模块)处理请求

  • ADSP的QMI服务端接收消息,解析出传感器SUID与参数;
  • 调用SEE的set_client_request()接口,将采样率参数下发至传感器驱动;
  • 驱动更新硬件配置后,通过QMI发送“配置成功”的响应消息。

2.3.AP侧接收响应

  • HAL层通过qsh_qmi()接收响应消息,确认配置完成;
  • 向上层SensorService返回Status::OK,完成一次通信。
3. QMI消息格式(Protocol Buffers)

QMI消息基于协议缓冲区(Protocol Buffers) 定义,SEE架构中所有传感器相关的QMI消息都通过.proto文件标准化,例如:

  • sns_std.proto:定义框架级消息(如请求/响应头、错误码);
  • sns_accel.proto:定义加速度计的消息(如采样率配置、数据上报格式);
  • sns_temp.proto:定义温度传感器的消息(如阈值配置、温度数据格式)。

以sns_std.proto中的请求消息为例:

// sns_std.proto 示例 message sns_std_request { // 请求类型(如设置采样率=0x01,开启传感器=0x02) uint32 request_type = 1; // 传感器SUID sns_suid suid = 2; // 请求参数(键值对,如"period":1000) repeated sns_std_param params = 3; // 请求ID(用于匹配响应) uint32 request_id = 4; }

这种标准化格式确保了AP与ADSP之间的消息兼容性,即使硬件迭代,只需更新.proto文件即可适配。

三、实战:温度传感器数据采集(C++示例)

1. 初始化与激活传感器
sns_hal_context*hal_ctx=sns_hal_init();sensor_info_t*temp_sensor=find_sensor_by_type("temperature");sns_hal_activate(hal_ctx,temp_sensor->id,true);sns_hal_batch(hal_ctx,temp_sensor->id,&batch_param);
2. 激活传感器并设置采样率

通过QMI接口发送配置请求,激活传感器并设置采样率:

// 5. 激活温度传感器status_t activate_ret=sns_hal_activate(hal_ctx,temp_sensor->id,true);if(activate_ret!=STATUS_OK){printf("激活传感器失败,错误码:%d\n",activate_ret);return-1;}// 6. 设置采样率为1Hz(period=1000ms)batch_param_t batch_param={.sampling_period=1000000000,// 1秒(单位:ns).max_report_latency=0// 无延迟上报};status_t batch_ret=sns_hal_batch(hal_ctx,temp_sensor->id,&batch_param);if(batch_ret!=STATUS_OK){printf("设置采样率失败,错误码:%d\n",batch_ret);return-1;}printf("传感器激活成功,采样率:1Hz\n");
3. 采集并打印温度数据
sensor_event_t event;for(inti=0;i<10;i++){status_t ret=sns_hal_poll(hal_ctx,temp_sensor->id,&event,2000);if(ret==STATUS_OK){floattemperature=event.data[0];printf("温度: %.1f℃\n",temperature);}sleep(1);}// 8. 释放资源sns_hal_deactivate(hal_ctx,temp_sensor->id);sns_hal_deinit(hal_ctx);release_qsh_interface(qmi_iface);return0;
4. 运行结果示例
找到温度传感器,SUID:SUID_TEMP_001 获取QMI接口成功 传感器激活成功,采样率:1Hz 第1次采集:温度=22.5℃,时间戳=1690000000000 第2次采集:温度=22.6℃,时间戳=1690001000000 第3次采集:温度=22.5℃,时间戳=1690002000000 ...
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 9:20:01

提取文件(文件夹)名称小工具目录树文件名字提取BAT脚本加软件

大家好&#xff0c;我是大飞哥。日常办公或整理文件时&#xff0c;我们总遇到需要批量提取文件名、文件夹名却只能手动复制的痛点 —— 比如统计项目文件清单、整理素材库目录&#xff0c;手动逐行输入不仅效率低&#xff0c;还容易出错&#xff0c;想生成目录树更是要靠复杂的…

作者头像 李华
网站建设 2026/4/23 9:22:40

构建SpringBoot项目Docker镜像并发布到k8s集群中进行运行

此文的目的&#xff1a;构建企业级应用从开发、部署、运行的一个缩影&#xff0c;整个流程虽然相对简陋&#xff0c;但是麻雀虽小五脏俱全&#xff0c;打通了服务编写、镜像构建、部署。为了小伙伴们大致了解DevOps和K8s集群部署有一个初步认识。整体思路是&#xff1a;1&#…

作者头像 李华
网站建设 2026/4/23 9:20:24

《jQuery UI 下载指南:如何高效获取并使用jQuery UI组件库》

《jQuery UI 下载指南:如何高效获取并使用jQuery UI组件库》 引言 jQuery UI 是一个基于 jQuery 的用户界面构建工具集,它包含了一套丰富的交互组件和效果,旨在帮助开发者快速构建出美观且功能强大的网页应用。本文将为您提供详细的 jQuery UI 下载指南,包括如何获取最新…

作者头像 李华
网站建设 2026/4/23 9:19:40

Bootstrap 轮播

Bootstrap 轮播 Bootstrap轮播(Carousel)是Bootstrap框架中一个强大的组件,它允许开发者创建响应式、易于定制的轮播图。通过使用Bootstrap轮播,可以轻松地添加图片、文本以及其他多媒体元素,使得网页内容更加生动和丰富。本文将详细介绍Bootstrap轮播的用法、配置选项以…

作者头像 李华
网站建设 2026/4/23 10:49:01

Java 开发 - Objects 的 requireNonNull 方法

Objects 的 requireNonNull 方法 1、基本介绍 public static <T> T requireNonNull(RecentlyNullable T obj)检查一个对象是否为 null&#xff0c;如果是 null 则抛出 NullPointerException public static <T> T requireNonNull(RecentlyNullable T obj, Recent…

作者头像 李华