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层) OFF SINGLE TORCH STROBE triggerFlash() 脉冲完成 / abort setTorchMode(true) setTorchMode(false) 连拍开始 连拍结束 / 超时 强制切换(需驱动支持) 状态转换约束: 1. SINGLE→TORCH 非法:单次闪未完成时禁止切入手电筒模式。 2. 所有状态均可直接回到 OFF,但需确保驱动安全关断。
常见陷阱:部分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实例:前后置摄像头共享同一颗闪光灯驱动时,状态机需要增加所有者字段,防止后置切前置时误关闪光灯。