4. 闪光灯状态机:状态转换逻辑与HAL层设计
闪光灯在Camera HAL层并非简单的“开/关”控制,而是一个严格的状态机。HAL层需要管理四种核心状态:OFF(关闭)、SINGLE(单次闪)、TORCH(手电筒/常亮)和STROBE(连续频闪)。状态转换的合法性、时序约束以及异常恢复逻辑,直接决定了闪光灯功能的稳定性和拍照体验。
4.1 闪光灯状态定义与属性
下表列出了四种核心状态的语义、典型应用场景以及HAL层需要维护的关键属性:
| 状态 | 语义 | 典型场景 | HAL关键属性 |
|---|---|---|---|
| OFF | 闪光灯完全关闭,无电流输出 | 预览、视频录制(未开启补光) | 电流=0mA,驱动待机 |
| SINGLE | 单次脉冲闪光,持续时间短(通常1~100ms) | 拍照瞬间补光、防红眼预闪 | 峰值电流、脉冲宽度、预热标志 |
| TORCH | 持续低电流输出,常亮模式 | 视频补光、手电筒、对焦辅助灯 | 稳态电流、热限制阈值 |
| STROBE | 连续高频脉冲,用于连拍或特殊效果 | 连拍模式、高速同步、专业摄影 | 频率、占空比、最大脉冲数 |
调试要点:在HAL层日志中,应记录每次状态转换的发起者(Framework / 应用 / 内部定时器)和转换耗时。如果SINGLE状态持续时间超过预期(例如>200ms),通常表明驱动层未正确响应脉冲结束中断。
4.2 状态转换图与合法路径
以下SVG图展示了HAL层闪光灯状态机的核心转换逻辑。箭头上的标签表示触发转换的事件或条件。
常见陷阱:部分HAL实现允许从SINGLE直接切换到TORCH,这会导致驱动层电流冲突——脉冲电流尚未泄放,常亮电流又叠加,极易烧毁LED灯珠。正确的做法是:SINGLE→OFF→TORCH,中间必须经过OFF状态进行电流归零。
4.3 HAL层状态机设计要点
在HAL层实现状态机时,需要关注以下三个核心设计维度:
4.3.1 状态转换的原子性与互斥锁
闪光灯状态转换必须保证原子性。在多线程环境下(例如预览线程和拍照线程同时请求闪光灯),HAL层应使用互斥锁(Mutex)保护状态变量。典型伪代码如下:
// HAL层闪光灯状态机核心逻辑(简化)
FlashState g_flash_state = FLASH_OFF;
pthread_mutex_t g_flash_lock = PTHREAD_MUTEX_INITIALIZER;
int hal_flash_set_torch(bool on) {
pthread_mutex_lock(&g_flash_lock);
if (on) {
// 仅允许从 OFF 切换到 TORCH
if (g_flash_state != FLASH_OFF) {
pthread_mutex_unlock(&g_flash_lock);
return -EBUSY; // 状态冲突
}
// 执行硬件初始化:设置电流、使能GPIO
flash_hw_set_current(TORCH_CURRENT_MA);
flash_hw_enable(true);
g_flash_state = FLASH_TORCH;
} else {
// 仅允许从 TORCH 切换到 OFF
if (g_flash_state != FLASH_TORCH) {
pthread_mutex_unlock(&g_flash_lock);
return -EINVAL;
}
flash_hw_enable(false);
g_flash_state = FLASH_OFF;
}
pthread_mutex_unlock(&g_flash_lock);
return 0;
}
4.3.2 超时与异常恢复机制
每个非OFF状态都应关联一个看门狗定时器。例如:
- SINGLE超时:如果脉冲宽度超过硬件允许的最大值(通常为100ms),HAL应强制终止脉冲并回到OFF,同时上报错误事件给Framework。
- TORCH热保护:当TORCH模式持续超过热限制阈值(例如30秒),HAL应自动降低电流或关闭闪光灯,防止过热。
- STROBE脉冲计数:连续频闪模式下,HAL需记录已发出的脉冲数,达到上限后自动停止并回到OFF。
4.3.3 与Framework的接口对齐
Android Camera HAL3要求闪光灯状态机必须与ANDROID_FLASH_MODE和ANDROID_FLASH_STATE元数据严格对应。下表展示了HAL内部状态与Framework元数据的映射关系:
| HAL内部状态 | ANDROID_FLASH_MODE(请求) | ANDROID_FLASH_STATE(结果) |
|---|---|---|
| OFF | OFF / NONE | UNAVAILABLE |
| SINGLE | SINGLE | FIRED |
| TORCH | TORCH | READY(常亮中) |
| STROBE | (无标准模式,通常用SINGLE+连拍标志) | FIRED(逐帧上报) |
实战建议:在调试阶段,建议在HAL层增加一个状态机监控线程,每隔100ms轮询当前状态和硬件寄存器。当发现状态与预期不符时(例如硬件报告电流为0但HAL认为处于TORCH),立即打印堆栈并尝试恢复。这个机制在定位“闪光灯不亮”或“闪光灯常亮不灭”等顽固Bug时极为有效。
4.4 状态机设计中的边界条件
以下列表总结了HAL层状态机设计中容易忽略的边界条件,建议在代码审查和测试用例中重点覆盖:
- 重复触发SINGLE:在SINGLE脉冲未完成时,再次调用triggerFlash()。HAL应返回错误或排队等待,而不是直接忽略。
- TORCH模式下请求SINGLE:部分应用会错误地在手电筒模式下请求拍照闪光。HAL应拒绝该请求,并返回
-EBUSY。 - 系统休眠唤醒:闪光灯在TORCH模式下系统进入休眠,唤醒后HAL需重新查询硬件状态,确保状态机与硬件一致。
- 驱动异常断开:I2C/SPI通信失败时,HAL应强制将状态置为OFF,并尝试重新初始化驱动。
- 多Camera实例:前后置摄像头共享同一颗闪光灯驱动时,状态机需要增加所有者字段,防止后置切前置时误关闪光灯。