2. Wear OS传感器生态与硬件抽象层
在 Wear OS 上开发传感器应用,第一件需要建立起来的认知是:你写的代码几乎从不直接和芯片对话。手表里可能同时存在加速度计、陀螺仪、磁力计、心率 PPG、血氧、气压计、环境光等多个物理器件,它们来自不同厂商、挂在不同总线上、采样率和量程各不相同。Wear OS 通过一套硬件抽象层(HAL)把这些差异屏蔽掉,向上暴露统一的 SensorManager 接口。理解这条从物理器件到应用回调的链路,是后续所有采样、滤波、功耗优化的基础。
一、四层结构:从芯片到回调
Wear OS 的传感器栈可以粗略分为四层。最底层是物理传感器与驱动,负责把模拟量转成数字量并通过 I²C/SPI 上报;往上是传感器 HAL,由 SoC 厂商实现,统一了上报格式、时间戳基准和批处理能力;再往上是系统服务层,即 SensorService 与 SensorManager,负责权限校验、多应用复用、采样率仲裁和唤醒策略;最上层才是应用进程,通过 SensorEventListener 或 TriggerEventListener 接收数据。
这条链路的关键含义是:应用请求的采样率只是“期望值”,系统会结合其他应用的需求、屏幕状态和功耗策略做仲裁。因此你请求 50Hz,实际可能拿到 25Hz 或 100Hz,必须通过 SensorEvent 的时间戳自行计算真实间隔,而不能假设固定周期。
二、SensorManager 与 Sensor 对象
SensorManager 是应用访问传感器的入口,通过 getSystemService(SENSOR_SERVICE) 获取。它提供三类能力:查询(getSensorList、getDefaultSensor)、注册(registerListener)和注销(unregisterListener)。Sensor 对象本身不持有数据,它只是一份描述元数据,常用字段包括:
getType():传感器类型常量,如TYPE_ACCELEROMETER、TYPE_HEART_RATE。getMaxRange()/getResolution():量程与最小可分辨变化,决定数值精度。getMinDelay():最小采样间隔(微秒),0 表示仅支持变化触发(on-change)。getPower():标称功耗(mA),是功耗预算的核心依据。getFifoMaxEventCount():硬件 FIFO 容量,决定批处理深度。isWakeUpSensor():是否为唤醒传感器,关系到熄屏后能否唤醒 AP。
一个常见误区是认为 getDefaultSensor 一定返回可用对象。在部分低功耗手表上,血氧或环境光可能缺失,返回值可能为 null,必须做空判断并降级处理。
三、SensorEvent 与采样率
SensorEvent 是回调中携带的数据包,包含四个关键成员:sensor、timestamp、accuracy 和 values[]。timestamp 的单位是纳秒,基准为 SystemClock.elapsedRealtimeNanos(),即设备开机时间,不受系统时间修改影响,适合做差分计算。
注册时传入的 samplingPeriodUs 是期望周期。系统会把它映射到最接近的可用档位。例如请求 20000μs(50Hz),若硬件只支持 10Hz/25Hz/50Hz,则可能落到 50Hz;若同时有前台应用请求 100Hz,系统可能统一按 100Hz 下发,你的回调频率随之升高。因此正确做法是:
// 用时间戳计算真实采样间隔,而非假设固定周期
private long lastTs = 0;
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
if (lastTs != 0) {
float realHz = 1_000_000_000f / (event.timestamp - lastTs);
// realHz 用于自适应滤波系数
}
lastTs = event.timestamp;
float ax = event.values[0];
float ay = event.values[1];
float az = event.values[2];
}
}
四、传感器类型分类
按行为特征,Wear OS 传感器可分为三类,这直接决定了注册方式和功耗模型:
| 类别 | 典型类型 | 行为特征 | 注册方式 |
|---|---|---|---|
| 连续型 | 加速度计、陀螺仪、磁力计 | 按固定速率持续上报 | registerListener + 采样周期 |
| 变化触发型 | 环境光、接近、显著运动 | 仅数值变化时上报 | samplingPeriodUs = 0 |
| 单次触发型 | 显著运动、倾斜检测 | 事件发生后自动注销 | requestTriggerSensor |
此外还有复合传感器,如 TYPE_STEP_COUNTER、TYPE_HEART_RATE、TYPE_LINEAR_ACCELERATION。它们可能由多个物理传感器融合而成,也可能由协处理器独立运行。复合传感器的优势是功耗低、结果已处理,但采样率和延迟不可控,不适合需要原始波形的场景。
五、权限与后台限制
Wear OS 基于 Android 权限模型,普通传感器(加速度计、陀螺仪)无需运行时权限,但以下类型需要显式声明:
BODY_SENSORS:心率、血氧等体征传感器,属于危险权限,需运行时申请。ACTIVITY_RECOGNITION:步数、活动识别,Android 10 起需运行时申请。HIGH_SAMPLING_RATE_SENSORS:Android 12 起,采样率超过 200Hz 需要此权限,否则被限流。
后台限制是 Wear OS 上更容易踩坑的部分。应用进入后台后,系统会限制传感器注册:连续型传感器在后台可能被降频或暂停;Android 9 起,后台应用无法接收连续传感器事件,除非使用前台服务。因此长时间采集(如睡眠监测)必须启动前台服务并显示常驻通知,同时配合 WakeLock 或唤醒传感器来保证熄屏后仍能工作。
六、批处理与功耗权衡
registerListener 的最后一个参数 maxReportLatencyUs 控制批处理延迟。设为 0 表示立即上报;设为 5_000_000(5 秒)表示允许硬件在 FIFO 中缓存最多 5 秒再批量交付。批处理能显著降低 AP 唤醒次数,从而省电,代价是数据延迟增加。对于计步、活动识别这类不需要实时响应的场景,批处理是首选;对于手势识别、跌倒检测,则必须低延迟。
一个实用的判断方法是:先查 getFifoMaxEventCount(),再结合目标采样率估算可缓存时长。例如 FIFO 容量 3000 个事件、采样率 50Hz,则最多缓存 60 秒。若请求的延迟超过该上限,系统会自动截断,实际延迟小于请求值。
getMinDelay()、getPower()、getFifoMaxEventCount() 和 isWakeUpSensor(),形成一份设备能力清单。不同手表差异很大,这份清单能帮你快速判断某个功能是否可行、功耗是否可接受。
把以上内容串起来看,Wear OS 传感器开发的核心不是“调用哪个 API”,而是理解 HAL 抽象带来的三个约束:采样率是协商结果而非保证值、后台行为受系统策略支配、功耗与延迟需要显式权衡。掌握这三点,后续的滤波、融合和低功耗设计才有稳固的基础。