3、HAL层初始化流程详解:HAL Module加载、CameraProvider启动、CameraDevice打开、Stream配置流程

Camera HAL层初始化是上层应用与底层硬件交互的起点,也是调试过程中最常遇到问题的阶段。本章将按照初始化时序,逐一拆解HAL Module加载、CameraProvider启动、CameraDevice打开、Stream配置四个核心环节,并结合MTK平台特性给出关键调试点。

3.1 整体初始化流程概览

从Android CameraService到HAL层硬件操作的完整调用链如下表所示,每个阶段都有对应的关键接口和MTK特有实现。

阶段 调用方 关键接口/组件 MTK平台要点
1. HAL Module加载 CameraService HAL_MODULE_INFO_SYM → open() 加载 camera.mtxxxx.so,初始化 MtkCameraHalModule
2. CameraProvider启动 CamX/CameraProvider ICameraProvider::setCallback() → getCameraIdList() 枚举物理Camera,初始化Sensor/ISP驱动
3. CameraDevice打开 CameraService ICameraDevice::open() 创建 MtkCameraDevice,初始化Pipeline
4. Stream配置 CameraClient ICameraDeviceSession::configureStreams() 配置Stream集合,分配Buffer,建立ISP通路
调试提示: 初始化阶段最常见的失败原因包括:HAL库加载路径错误、Provider回调超时、Sensor驱动未就绪、Stream配置参数不匹配。建议在每一步都添加日志标记,便于定位卡死点。

3.2 HAL Module加载

CameraService通过 hw_get_module() 加载HAL Module,MTK平台对应的实现位于 vendor/mediatek/proprietary/custom/mtxxxx/hal/camera/ 目录下。

3.2.1 加载入口与数据结构

HAL Module的入口是 HAL_MODULE_INFO_SYM 宏定义的全局结构体,MTK的实现如下:

// hardware/libhardware/include/hardware/camera_common.h
struct hw_module_t HAL_MODULE_INFO_SYM = {
    .tag = HARDWARE_MODULE_TAG,
    .module_api_version = CAMERA_MODULE_API_VERSION_2_4,
    .hal_api_version = HARDWARE_HAL_API_VERSION,
    .id = CAMERA_HARDWARE_MODULE_ID,
    .name = "MTK Camera HAL Module",
    .author = "MediaTek",
    .methods = &mtk_camera_module_methods,
    .dso = NULL,
    .reserved = {0},
};

static struct hw_module_methods_t mtk_camera_module_methods = {
    .open = mtk_camera_module_open,
};

3.2.2 加载时序与关键日志

加载过程中,CameraService会调用 camera_module->get_number_of_cameras() 和 camera_module->get_camera_info() 获取Camera基本信息。MTK平台在此阶段会完成Sensor探测和EEPROM读取。

关键日志标记:
[MtkCam/HalModule] mtk_camera_module_open +
[MtkCam/HalModule] sensor_count = 3
[MtkCam/HalModule] camera_info[0]: facing=0, orientation=90
[MtkCam/HalModule] mtk_camera_module_open -

3.3 CameraProvider启动

在Android Treble架构下,CameraProvider运行在独立的HAL进程中,通过HIDL与CameraService通信。MTK平台的Provider启动流程如下:

  1. 注册Provider服务:MtkCameraProvider::onStart() 注册 ICameraProvider 服务。
  2. 设置回调:CameraService调用 setCallback() 注册状态监听。
  3. 获取Camera列表:getCameraIdList() 返回所有可用Camera ID。
  4. 初始化物理Camera:每个Camera ID对应一个 MtkCameraDevice 实例。
CameraProvider启动时序图 CameraService CameraProvider MtkCameraDevice setCallback() getCameraIdList() open() Provider内部初始化流程 1. 加载Sensor驱动配置 (sensor_cfg.ini) 2. 初始化ISP Pipeline (isp_pipeline.xml) 3. 创建MtkCameraDevice实例,绑定物理Camera ID MTK平台Provider启动关键检查点 • 检查 /vendor/etc/camera/camera_config.xml 是否存在且格式正确 • 确认所有Sensor的MCLK/PWDN/RST引脚电平状态
常见问题: Provider启动超时(通常为5秒)。如果 getCameraIdList() 返回空列表或超时,请检查:
1. Sensor驱动是否正常加载(dmesg | grep imgsensor)
2. EEPROM读取是否失败(logcat | grep eeprom)
3. Provider进程是否被SELinux策略阻止

3.4 CameraDevice打开

当应用调用 CameraManager.openCamera() 时,CameraService最终调用到HAL层的 device_open() 接口。MTK平台在此阶段会创建 MtkCameraDevice 对象并初始化内部Pipeline。

3.4.1 打开流程关键步骤

  1. 创建MtkCameraDevice:分配Camera ID对应的设备对象。
  2. 初始化Pipeline:加载ISP配置,创建Streaming Pipeline。
  3. 设置回调:注册 notify() 和 process_capture_result() 回调。
  4. 返回设备句柄:CameraService获得 camera3_device_t 指针。

3.4.2 关键数据结构

// MtkCameraDevice核心结构
struct MtkCameraDevice {
    camera3_device_t base;          // 标准camera3_device接口
    int32_t camera_id;              // 物理Camera ID
    MtkCameraHalModule* module;     // 所属HAL Module
    MtkStreamPipeline* pipeline;    // ISP Pipeline实例
    MtkSensorDriver* sensor;        // Sensor驱动实例
    MtkISPInterface* isp;           // ISP硬件接口
    camera3_callback_ops_t* cb_ops; // 上层回调函数
    bool is_opened;                 // 打开状态标志
};

3.5 Stream配置流程

Stream配置是初始化阶段最复杂的环节,涉及Buffer分配、ISP通路建立、Stream参数协商。应用通过 createCaptureSession() 触发此流程。

3.5.1 configureStreams() 调用链

步骤 接口 MTK平台实现 常见错误
1. 参数校验 configureStreams() 检查Stream数量、格式、分辨率是否在Sensor能力范围内 格式不支持(如YUV420_888)
2. 分配Buffer GrallocBufferPool 根据Stream配置分配GraphicBuffer,设置BufferHeap参数 Buffer分配失败(内存不足)
3. 建立ISP通路 MtkISPInterface::configStream() 配置ISP输入输出格式、裁剪区域、帧率控制 ISP超时无响应
4. 注册Stream registerStream() 将Stream ID与Pipeline绑定,准备Capture Stream ID冲突

3.5.2 Stream配置参数示例

// 典型的Stream配置参数
camera3_stream_configuration_t stream_config = {
    .num_streams = 3,
    .streams = (camera3_stream_t*[]){
        &stream_preview,   // 预览流: 1920x1080, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
        &stream_record,    // 录像流: 1920x1080, HAL_PIXEL_FORMAT_YCbCr_420_888
        &stream_snapshot   // 拍照流: 4032x3024, HAL_PIXEL_FORMAT_BLOB
    },
    .operation_mode = CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE,
    .session_parameters = NULL,
};
Stream配置流程与Buffer流转 CameraClient CameraService HAL层 ISP硬件 createCaptureSession configureStreams ISP配置 Buffer分配与流转路径 1. HAL层通过Gralloc分配Buffer → 注册到Stream BufferQueue 2. ISP处理完成后 → HAL层填充metadata → 回调process_capture_result 3. CameraService将Buffer返回给应用层显示/编码 MTK平台Stream配置调试要点 • 检查Stream分辨率是否在Sensor输出能力范围内(查看sensor_output_info) • 确认ISP输入格式与Sensor输出格式一致(RAW10/RAW16/YUV422)

3.6 初始化阶段常见问题与调试方法

问题1:HAL Module加载失败
现象:hw_get_module() 返回 -ENOENT
排查:
- 检查 /vendor/lib/hw/camera.mtxxxx.so 是否存在
- 检查 android.hardware.camera.provider@2.4-service-mtk.rc 中SELinux上下文
- 使用 ls -lZ /vendor/lib/hw/camera* 查看文件权限
问题2:Provider启动后Camera列表为空
现象:getCameraIdList() 返回空列表
排查:
- 检查Sensor驱动是否probe成功:cat /sys/class/video4linux/video*/name
- 检查 /vendor/etc/camera/camera_config.xml 中Camera节点配置
- 查看 logcat -s MtkCam::Provider 是否有错误日志
问题3:configureStreams() 返回错误
现象:configureStreams() 返回 CAMERA3_STATUS_INVALID_PARAM
排查:
- 检查Stream格式是否在 getCameraCharacteristics() 声明的 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS 中
- 检查Stream分辨率是否超过Sensor最大输出尺寸
- 检查多个Stream的总带宽是否超过ISP处理能力

3.7 调试经验总结

调试阶段 推荐工具/方法 关键日志Tag 预期结果
Module加载 adb shell logcat -s CameraService CameraService 看到 Loaded "camera.mtxxxx.so"
Provider启动 adb shell lshal | grep camera MtkCam::Provider Provider服务状态为 running
Device打开 adb shell logcat -s MtkCam::Device MtkCam::Device 看到 device_open() success
Stream配置 adb shell logcat -s MtkCam::Stream MtkCam::Stream 看到 configureStreams() done
MTK平台专用调试技巧:
1. 使用 adb shell "echo 1 > /sys/kernel/debug/mtk_camera/trace" 开启HAL层详细trace。
2. 在 vendor/mediatek/proprietary/custom/mtxxxx/hal/camera/inc/mtk_camera_debug.h 中调整日志级别:#define CAM_DEBUG_LEVEL 3。
3. 使用MTK提供的 CameraHalTest 工具单独测试每个初始化阶段,绕过上层框架干扰。