2. Android传感器框架:Android Sensor Framework 架构概览
好,我们正式开始聊Android的传感器框架。说实话,很多做应用开发的同事,可能一辈子都没碰过HAL层。但如果你要做距离传感器的深度调优,不了解这个框架,就像开车不看仪表盘——能跑,但心里没底。
我个人习惯把Android传感器框架分成三层来看:应用层、框架层、硬件抽象层。这三层各司其职,又紧密配合。今天我们就一层层剥开它。
2.1 应用层:你天天打交道的三个类
应用层说白了就是SDK里暴露给开发者的API。核心就三个类:SensorManager、Sensor、SensorEventListener。我刚开始做传感器开发时,以为只要new一个SensorManager就能拿到数据了——嗯,后来被坑得不轻。
2.1.1 SensorManager——传感器的大管家
这个类是你获取传感器服务的入口。通过Context.getSystemService(SENSOR_SERVICE)拿到它。它负责三件事:
- 列举设备上的传感器:
getSensorList()返回所有可用传感器列表 - 获取特定传感器:
getDefaultSensor()拿到默认的某个类型传感器 - 注册/注销监听:
registerListener()和unregisterListener()
重要提醒:getDefaultSensor() 返回的不一定是物理传感器。如果设备上有多个同类型传感器,系统会选一个“最优”的。我在项目中遇到过,某款手机的距离传感器有两个,一个在听筒旁边,一个在顶部,系统默认选的那个位置不对,导致通话时屏幕一直亮着。
2.1.2 Sensor——传感器的身份证
Sensor 对象本身不干活,它只是描述传感器的属性。比如:
getName():传感器名字,比如 "STK3321 Proximity Sensor"getType():类型,距离传感器是Sensor.TYPE_PROXIMITYgetMaximumRange():最大量程,距离传感器通常是5cm或10cmgetResolution():分辨率,决定了数据精度getMinDelay():最小采样间隔,单位微秒
你想想看,如果不知道传感器的量程,你怎么判断返回的“5.0”是5厘米还是5毫米?所以拿到Sensor对象后,第一件事就是读它的属性。
2.1.3 SensorEventListener——数据回调的桥梁
这个接口就两个方法:
public interface SensorEventListener {
void onSensorChanged(SensorEvent event);
void onAccuracyChanged(Sensor sensor, int accuracy);
}
onSensorChanged 里你会拿到 SensorEvent,它的 values[] 数组就是传感器数据。距离传感器通常只有一个值,存在 values[0] 里。
我的习惯:在 onSensorChanged 里不要做耗时操作。这个回调频率可能很高(尤其是加速度计),你如果在里面写文件或做网络请求,UI线程直接卡死。我曾经见过一个同事,在回调里写Log写到手软,结果手机烫得能煎鸡蛋。
2.2 框架层:系统服务层的秘密
应用层下面,是系统服务层。这一层在 system_server 进程里运行,叫 SensorService。它负责:
- 管理所有传感器的注册和注销
- 控制传感器的采样率和上报频率
- 把HAL层上报的原始数据转换成应用层能理解的格式
- 处理权限校验(比如某些传感器需要特定权限)
这里有个关键点:应用层注册监听时指定的采样率,只是一个“建议值”。系统服务层会根据所有注册者的需求,取一个最优的采样率。比如你要求100ms一次,另一个应用要求200ms一次,系统可能就按100ms来采样,然后分别分发给你们。
避坑指南:我曾经在项目里把采样率设成 SENSOR_DELAY_FASTEST(最快模式),结果电池一小时掉光。后来才知道,这个模式下传感器以硬件支持的最高频率上报,距离传感器还好,如果是加速度计,那数据量是惊人的。所以,按需设置采样率,别贪快。
2.3 HAL层:硬件和系统的最后一道关卡
HAL层,全称 Hardware Abstraction Layer。它把硬件厂商的驱动和Android框架隔离开。为什么要有这一层?说白了,就是Google不想管每个厂商的驱动怎么写,只要厂商实现HAL接口,系统就能用。
距离传感器的HAL接口定义在 hardware/libhardware/include/hardware/sensors.h 里。核心结构体是:
struct sensor_t {
const char* name;
const char* vendor;
int version;
int handle;
int type;
float maxRange;
float resolution;
float power;
int32_t minDelay;
uint16_t fifoReservedEventCount;
uint16_t fifoMaxEventCount;
const char* stringType;
const char* requiredPermission;
int32_t maxDelay;
uint32_t flags;
void* reserved;
};
你看,这个结构体和应用层的 Sensor 类几乎一一对应。数据就是从HAL层一路传上来的。
2.4 三层关系:一张图说清楚
下面这张图是我自己画的,展示了数据从硬件到应用的完整路径:
数据流向是:硬件 → HAL层 → SensorService → SensorManager → 你的应用。反过来,你的注册请求是:应用 → SensorManager → SensorService → HAL层 → 硬件。
2.5 数据流的核心:SensorEventQueue
这里有个细节很多人不知道。应用层和系统服务层之间,数据是通过 SensorEventQueue 传递的。它是一个共享内存队列,系统服务层往里面写数据,应用层从里面读数据。这样做的好处是:
- 减少Binder调用次数:不用每次数据变化都跨进程通信
- 批量处理:可以一次读取多个事件
- 降低延迟:共享内存比Binder快得多
我记得有一次排查距离传感器延迟问题,发现是 SensorEventQueue 的缓冲区太小,导致数据丢失。后来调整了 maxBatchReportLatency 参数才解决。
2.6 总结:记住这三层
好了,这一章的内容就这些。你只要记住:
- 应用层:你写代码的地方,用SensorManager注册监听
- 框架层:系统服务SensorService,负责调度和分发
- HAL层:硬件厂商的驱动实现,把物理信号变成数字
这三层缺一不可。下一章我们会深入HAL层,看看距离传感器的驱动到底是怎么写的。到时候我会拿一个真实的驱动代码来拆解,保证你看完就能上手。
一句话总结:Android传感器框架就是一条从硬件到应用的数据管道,每一层都有自己的职责。理解了这个架构,你才能知道问题出在哪一层。