2. Camera HAL 开发环境搭建:交叉编译工具链配置、Android 源码树结构、HAL 模块编译与集成方法
搭建一套可复现、可调试的 Camera HAL 开发环境,是移植适配与稳定性优化的基础。本章围绕三个核心环节展开:交叉编译工具链的选型与配置、Android 源码树的目录结构与 HAL 模块定位、以及HAL 模块的编译与集成方法。掌握这些内容后,你可以在任意 AOSP 或厂商分支上快速建立 Camera HAL 的构建与验证闭环。
2.1 交叉编译工具链配置
Camera HAL 运行在嵌入式设备(如手机、车载摄像头模组)上,开发主机通常是 x86_64 Linux 工作站,因此必须使用交叉编译工具链生成目标架构(ARM64、ARM32 或 RISC-V)的可执行文件与共享库。
2.1.1 工具链选型对比
| 工具链类型 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| AOSP 预编译工具链 | 标准 Android 平台开发 | 与源码版本严格匹配,无需额外下载 | 版本固定,无法自定义优化参数 |
| Linaro GCC | ARM 架构通用开发 | 社区活跃,支持多架构 | 与 AOSP 集成需手动配置 sysroot |
| Android NDK 独立工具链 | HAL 模块独立编译测试 | 轻量、可脱离源码树编译 | 缺少 Android 框架头文件 |
| Clang/LLVM(AOSP 默认) | Android 10+ 强制要求 | 诊断信息友好,支持 LTO | 对老旧内核模块兼容性较差 |
实践建议:从 Android 10 开始,Google 强制使用 Clang 作为默认编译器。如果你的目标平台是 Android 12 及以上,请直接使用 AOSP 自带的 Clang 工具链,避免 GCC 导致的 ABI 兼容问题。
2.1.2 工具链配置步骤(以 AOSP Clang 为例)
- 确认主机环境:Ubuntu 20.04/22.04 LTS,安装必要依赖包:
libncurses5、libssl-dev、flex、bison。 - 下载 AOSP 源码:使用
repo init+repo sync同步目标分支(如android-14.0.0_r15)。 - 加载编译环境:执行
source build/envsetup.sh并lunch选择目标产品。 - 验证工具链路径:
echo $ANDROID_TOOLCHAIN应指向prebuilts/clang/host/linux-x86/clang-xxxx/bin/。 - 测试交叉编译:编写一个简单的 HAL 桩文件,使用
mm或m命令编译,检查输出文件架构:file out/target/product/xxx/vendor/lib64/hw/camera.xxx.so。
常见错误:如果
lunch 后未正确设置 ANDROID_PRODUCT_OUT,编译产物会输出到错误路径。请始终在 lunch 后执行 cd $ANDROID_BUILD_TOP 确认环境变量生效。
2.2 Android 源码树结构:HAL 模块定位
Camera HAL 模块在 AOSP 源码树中分布在多个关键目录下。理解这些目录的职责,能帮助你快速找到需要修改或移植的文件。
2.2.1 核心目录与职责
2.2.2 HAL 模块关键文件清单
| 文件路径(相对 AOSP 根目录) | 作用 | 是否需修改 |
|---|---|---|
hardware/libhardware/include/hardware/camera.h |
定义 camera_module_t、camera_device_t 等核心结构体 | 通常不修改,直接引用 |
hardware/libhardware/modules/camera/ |
Google 提供的参考实现(Camera HAL v1) | 可作为移植起点 |
hardware/interfaces/camera/ |
HIDL 定义文件(.hal),用于 Camera HAL v3+ | 需根据传感器能力扩展 |
device/<vendor>/<board>/camera/ |
厂商自定义 HAL 实现,包含 sensor 驱动适配 | 核心修改区域 |
frameworks/av/camera/ |
CameraService 与 CameraClient 框架代码 | 仅调试时需阅读 |
2.3 HAL 模块编译与集成方法
Camera HAL 模块的编译方式取决于你使用的是传统 Android.mk 还是新的 Android.bp(Soong 构建系统)。Android 11 之后,Google 逐步废弃 Android.mk,但许多厂商分支仍保留混合构建。
2.3.1 两种构建系统对比
| 特性 | Android.mk(Makefile) | Android.bp(Blueprint/Soong) |
|---|---|---|
| 语法 | GNU Make 变量与函数 | 结构化 JSON 风格 |
| 模块定义 | LOCAL_MODULE := camera.xxx |
cc_library_shared { name: "camera.xxx" } |
| 依赖管理 | 隐式全局变量 | 显式 deps 字段 |
| 增量编译速度 | 较慢(全量解析) | 快(并行依赖图) |
| 推荐场景 | 遗留项目或内核模块 | Android 11+ 新开发 |
2.3.2 典型 Android.bp 示例(Camera HAL v3 实现)
// device/<vendor>/<board>/camera/Android.bp
cc_library_shared {
name: "camera.<board>",
vendor: true,
relative_install_path: "hw",
srcs: [
"CameraHal.cpp",
"CameraDevice.cpp",
"CameraStream.cpp",
],
shared_libs: [
"libhardware",
"libcamera_metadata",
"libutils",
"liblog",
"android.hardware.camera.provider@2.4",
],
static_libs: [
"libxml2",
],
cflags: [
"-Wall",
"-Werror",
"-O2",
"-DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION)",
],
include_dirs: [
"device/<vendor>/<board>/include",
],
}
2.3.3 编译与集成步骤
- 编写或修改 HAL 源码:在
device/<vendor>/<board>/camera/下实现camera_module_t接口。 - 创建或更新构建文件:确保 Android.bp 或 Android.mk 中模块名与
camera.<board>.so一致。 - 执行编译:
- 全量编译:
m -j$(nproc) camera.<board> - 增量编译:
mm -j$(nproc)(需在模块目录下)
- 全量编译:
- 检查产物:
out/target/product/<board>/vendor/lib64/hw/camera.<board>.so - 集成到系统镜像:
make -j$(nproc) systemimage vendorimage或使用adb push推送到设备的/vendor/lib64/hw/目录。 - 验证加载:重启设备,执行
lshal或dumpsys media.camera确认 HAL 模块被 CameraService 成功加载。
关键检查点:如果 HAL 模块加载失败,首先检查
• 模块名与
• 缺少依赖的共享库(如
• SELinux 策略阻止 HAL 进程访问
logcat -b all | grep -i camera 中的错误信息。常见原因包括:• 模块名与
hw_module_methods_t 中定义的 tag 不匹配• 缺少依赖的共享库(如
libcamera_metadata.so 版本不兼容)• SELinux 策略阻止 HAL 进程访问
/dev/video* 节点
2.4 开发环境验证与常见问题
2.4.1 环境验证清单
| 验证项 | 命令/方法 | 预期结果 |
|---|---|---|
| 工具链可用性 | clang --version |
显示 AOSP 内置 Clang 版本号 |
| 交叉编译目标 | file out/.../camera.xxx.so |
显示 ELF 64-bit LSB shared object, ARM aarch64 |
| HAL 模块加载 | adb shell lshal | grep camera |
列出 camera provider 服务 |
| CameraService 通信 | adb shell dumpsys media.camera |
显示已注册的摄像头 ID 与特性 |
2.4.2 常见问题与解决方案
- 编译错误:undefined reference to 'HIDL_FETCH_xxx'
原因:HIDL 接口未正确生成 C++ 实现。解决方案:确保hardware/interfaces/camera/下的.hal文件已通过hidl-gen生成对应的FooAll.cpp。 - 运行时错误:Failed to open camera HAL module
原因:模块路径或权限问题。解决方案:确认/vendor/lib64/hw/camera.xxx.so存在且 SELinux context 为u:object_r:hal_camera_default_exec:s0。 - 性能问题:预览帧率远低于预期
原因:HAL 中未正确配置 sensor 输出格式或帧间隔。解决方案:检查configure_streams实现中的stream_configuration参数。
调试利器:在 HAL 代码中加入
ALOGD 日志,配合 logcat -s CameraHal 过滤,可以快速定位初始化、流配置、帧回调等关键路径的执行情况。建议在 open、configure_streams、process_capture_request 三个函数入口和出口各加一条日志。