第 17 章:传感器
Android 搭载了通用操作系统中最为完备的传感器框架之一。从实现屏幕旋转的加速度计,到为耳机音频做空间化处理的头部追踪器,同一套架构将数据经由三层定义清晰的层级完成转发:Java/Kotlin 应用 API(SensorManager)、原生系统服务(SensorService)以及厂商 HAL(ISensors)。本章追踪每一个事件:从传感器硬件产生,经过 HAL,进入服务层,最终向上送达应用,同时标注 AOSP 中每一步实现对应的源码文件。17.1 传感器架构概述17.1.1 三层堆栈传感器子系统沿用 AOSP 中随处可见的分层设计。从上至下各层级如下:框架层(Java)—android.hardware.SensorManager及相关类。应用调用registerListener(),在指定 Handler 线程上接收周期性的SensorEvent对象。系统服务层(C++)—SensorService,一个原生 BinderService,运行在system_server的 sensor‑service 线程中(并非运行在 system_server 的 JVM 内部)。它管理连接、虚拟传感器、传感器融合、电源策略以及事件路由。HAL 层(AIDL / HIDL)— 厂商提供的ISensors实现,与实际传感器硬件交互。现代设备使用 AIDL 接口;老旧设备使用 HIDL 1.0 / 2.0 / 2.1。17.1.2 端到端数据通路17.1.3 核心抽象概念类名文件传感器元数据Sensor / SensorInfosensor/Sensor.h、SensorInfo.aidl硬件传感器封装HardwareSensorSensorInterface.h虚拟(融合)传感器VirtualSensorSensorInterface.h运行时传感器RuntimeSensorSensorInterface.h单客户端连接SensorEventConnectionSensorEventConnection.h直连通道SensorDirectConnectionSensorDirectConnection.hHAL 抽象层ISensorHalWrapperISensorHalWrapper.hAIDL HAL 封装AidlSensorHalWrapperAidlSensorHalWrapper.h传感器融合SensorFusion / FusionSensorFusion.h、Fusion.hHAL 设备单例SensorDeviceSensorDevice.h17.1.4 组件图17.2 SensorService — 原生系统服务SensorService是传感器子系统的核心。它既是 BinderService(向 servicemanager 注册为sensorservice),又是 Thread(拥有独立的轮询循环)。源码文件:frameworks/native/services/sensorservice/SensorService.cpp头文件:frameworks/native/services/sensorservice/SensorService.h入口:frameworks/native/services/sensorservice/main_sensorservice.cpp17.2.1 启动:onFirstRef ()当SensorService第一次被引用(通常在 system_server 启动阶段),onFirstRef()执行完整初始化流程:源码关键实现细节:传感器注册。HAL 返回的每个硬件传感器都被封装为HardwareSensor对象(接近传感器除外,它使用ProximitySensor做激活状态跟踪)。调用链:// SensorService.cpp onFirstRef(), 约365行 registerSensor(std::make_sharedHardwareSensor(list[i]));registerSensor()将传感器加入SensorList并创建RecentEventLogger:// SensorService.cpp, 约538行 bool SensorService::registerSensor(std::shared_ptrSensorInterface s, bool isDebug, bool isVirtual, int deviceId) { const int handle = s-getSensor().getHandle(); const int type = s-getSensor().getType(); if (mSensors.add(handle, std::move(s), isDebug, isVirtual, deviceId)) { mRecentEvent.emplace(handle, new SensorServiceUtil::RecentEventLogger(type)); return true; } else { LOG_FATAL("Failed to register sensor with handle %d", handle); return false; } }虚拟传感器条件判断。位掩码virtualSensorsNeeds跟踪哪些复合传感器类型已经由 HAL 原生提供。如果 HAL 本身提供SENSOR_TYPE_GRAVITY(例如来自传感器集线器),SensorService就不会注册软件实现的GravitySensor。编译时标志IGNORE_HARDWARE_FUSION(默认 false)可以强制所有复合传感器全部走软件融合。套接字缓冲区大小。只要任意传感器报告非零的fifoMaxEventCount,套接字缓冲区就会被放大到MAX_SOCKET_BUFFER_SIZE_BATCHED(100KB),单次写入可承载约 1000 个事件。该值会被限制在内核wmem_max上限以内。17.2.2 主线程循环:threadLoop ()SensorService继承 Thread,threadLoop()是核心数据通路。它以SCHED_FIFO优先级 10 运行,最大限度降低抖动。源码:SensorService.cpp,约 1125 行循环逻辑:虚拟传感器处理:每收到一条硬件原始事件,所有激活的虚拟传感器都会调用process()。如果产生输出事件,则追加到缓冲区。缓冲区大小计算公式为MAX_RECEIVE_BUFFER_EVENT_COUNT / (1 + virtualSensorCount),保证最坏场景下(每一条输入事件都触发全部虚拟传感器输出)有足够存储空间。唤醒锁协议:当poll()返回唤醒传感器事件时,SensorService持有SensorService_wakelock部分唤醒锁,直到全部SensorEventConnection完成应答(由SensorEventAckReceiver线程处理)。Looper 设置 5 秒超时,避免唤醒锁永久泄漏。17.2.3 事件分发:sendEventsToAllClients ()// SensorService.cpp, 约1063行 void SensorService::sendEventsToAllClients( const std::vectorspSensorEventConnection activeConnections, ssize_t count) { bool needsWakeLock = false; for (const spSensorEventConnection connection : activeConnections) { connection-sendEvents(mSensorEventBuffer, count, mSensorEventScratch, mMapFlushEventsToConnections); needsWakeLock |= connection-needsWakeLock(); if (connection-hasOneShotSensors()) { cleanupAutoDisabledSensorLocked(connection, mSensorEventBuffer, count); } } if (mWakeLockAcquired !needsWakeLock) { setWakeLockAcquiredLocked(false); } }每一个SensorEventConnection从全局缓冲区过滤出该客户端注册过的传感器事件,写入自身 BitTube 套接字。mSensorEventScratch缓冲区用于过滤过程中的临时存储。17.2.4 SensorEventConnection — 客户端状态Java 层每调用一次SensorManager.registerListener(),原生层就会创建对应的SensorEventConnection。源码:frameworks/native/services/sensorservice/SensorEventConnection.h关键字段:字段用途mChannel (BitTube)Unix 套接字对,用于事件投递mSensorInfo传感器句柄到 FlushInfo 的映射表mEventCache套接字满时的事件缓存mWakeLockRefCount尚未应答的唤醒事件计数mUid所属应用的 UIDmTargetSdk用于采样率限制策略sendEvents()为热点路径,执行逻辑:从全局事件缓冲区过滤出该连接注册的传感器;前置待处理的 flush 完成事件;每个数据包中恰好标记一个唤醒事件,打上WAKE_UP_SENSOR_EVENT_NEEDS_ACK标记;通过SOCK_SEQPACKET向 BitTube 写入;如果写入失败(套接字已满),缓存事件等待后续发送。17.2.5 SensorDirectConnection — 低时延通路对于时延敏感应用(游戏、VR),SensorDirectConnection完全绕开 BitTube 套接字。由 HAL 直接把事件写入共享内存(ashmem 或 gralloc)。源码:frameworks/native/services/sensorservice/SensorDirectConnection.h直连通道事件采用固定 104 字节格式(DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH),搭配原子计数器,应用轮询检测新数据;通道配置完成后,完全消除系统调用开销。17.2.6 工作模式SensorService支持 5 种工作模式,可通过 dumpsys 控制:模式值用途NORMAL0标准运行DATA_INJECTION1接收注入数据,用于算法测试RESTRICTED2仅白名单包可使用传感器(CTS 测试)REPLAY_DATA_INJECTION3注入数据投递到全部应用HAL_BYPASS_REPLAY_DATA_INJECTION4注入数据缓存在 SensorDevice 层模式切换命令:# 进入RESTRICTED模式(CTS测试) adb shell dumpsys sensorservice restrict .cts. # 进入DATA_INJECTION模式 adb shell dumpsys sensorservice data_injection .xts. # 切回NORMAL adb shell dumpsys sensorservice enable17.2.7 传感器隐私与 UID 策略SensorService实现两套相互独立的访问控制机制:UID 策略(UidPolicy):通过IUidObserver跟踪每个 UID 处于 ACTIVE 或 IDLE 状态。IDLE 状态 UID(后台应用)收不到传感器事件;UID 切换到 ACTIVE 时,事件投递自动恢复。传感器隐私(SensorPrivacyPolicy):系统全局开关,关闭所有应用的传感器。开启后,全部直连通道停止,所有传感器订阅暂停,拒绝新的注册。独立的MicrophonePrivacyPolicy处理麦克风隐私开关,会将运动传感器采样率限制到 200Hz(5ms 周期),防范声学侧信道攻击。17.2.8 隐私相关采样率限制面向 Android S 及以上、且没有HIGH_SAMPLING_RATE_SENSORS权限的应用,采样率上限为 200Hz(SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS = 5,000,000 ns)。直连通道则限制为SENSOR_DIRECT_RATE_NORMAL(最高约 110Hz)。源码:SensorService.h,67‑74 行#define SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS (5 * 1000 * 1000) #define SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL SENSOR_DIRECT_RATE_NORMAL17.3 Sensor HAL — 厂商接口17.3.1 ISensors AIDL 接口现代设备使用 AIDL 版本 Sensors HAL,定义文件:hardware/interfaces/sensors/aidl/android/hardware/sensors/ISensors.aidl接口核心方法:方法用途getSensorsList()获取全部静态传感器列表initialize(eventQueueDescriptor, wakeLockDescriptor, callback)初始化 FMQ 与回调activate(sensorHandle, enabled)使能 / 关闭传感器batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs)配置采样率与批处理flush(sensorHandle)触发 FIFO 刷新injectSensorData(event)注入测试数据registerDirectChannel(mem)注册共享内存直连通道unregisterDirectChannel(channelHandle)注销直连通道configDirectReport(sensorHandle, channelHandle, rate)配置直报模式setOperationMode(mode)切换 NORMAL / DATA_INJECTION 模式17.3.2 Fast Message Queues(FMQ,快速消息队列)AIDL HAL 使用两套 FMQ 实现零拷贝、无锁数据传输:Event FMQ:HAL 写入Event对象(传感器数据);写完后调用EventFlag::wake(),带上EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS唤醒框架。Wake Lock FMQ:框架写入唤醒事件的应答计数。HAL 读取该计数,确认可以释放自身SensorsHAL_WAKEUP唤醒锁。设置WAKE_LOCK_TIMEOUT_SECONDS(1 秒)超时,防止框架无响应造成唤醒锁泄漏。17.3.3 SensorInfo — 传感器描述每个传感器由可序列化 Parcelable 对象SensorInfo描述。源码:hardware/interfaces/sensors/aidl/android/hardware/sensors/SensorInfo.aidl字段类型说明sensorHandleint传感器唯一标识句柄nameString可读名称vendorString硬件厂商versionint驱动 + 硬件版本typeSensorType传感器类型枚举typeAsStringStringOEM 自定义类型标识(例如 com.google.glass.onheaddetector)maxRangefloatSI 单位下最大量程resolutionfloat最小可检测变化量powerfloat功耗,单位 mA