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通路 |
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启动流程如下:
- 注册Provider服务:
MtkCameraProvider::onStart()注册ICameraProvider服务。 - 设置回调:CameraService调用
setCallback()注册状态监听。 - 获取Camera列表:
getCameraIdList()返回所有可用Camera ID。 - 初始化物理Camera:每个Camera ID对应一个
MtkCameraDevice实例。
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 打开流程关键步骤
- 创建MtkCameraDevice:分配Camera ID对应的设备对象。
- 初始化Pipeline:加载ISP配置,创建Streaming Pipeline。
- 设置回调:注册
notify()和process_capture_result()回调。 - 返回设备句柄: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,
};
3.6 初始化阶段常见问题与调试方法
现象:
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* 查看文件权限
现象:
getCameraIdList() 返回空列表排查:
- 检查Sensor驱动是否probe成功:
cat /sys/class/video4linux/video*/name- 检查
/vendor/etc/camera/camera_config.xml 中Camera节点配置- 查看
logcat -s MtkCam::Provider 是否有错误日志
现象:
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 |
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 工具单独测试每个初始化阶段,绕过上层框架干扰。