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 为例)

  1. 确认主机环境:Ubuntu 20.04/22.04 LTS,安装必要依赖包:libncurses5、libssl-dev、flex、bison。
  2. 下载 AOSP 源码:使用 repo init + repo sync 同步目标分支(如 android-14.0.0_r15)。
  3. 加载编译环境:执行 source build/envsetup.sh 并 lunch 选择目标产品。
  4. 验证工具链路径:echo $ANDROID_TOOLCHAIN 应指向 prebuilts/clang/host/linux-x86/clang-xxxx/bin/。
  5. 测试交叉编译:编写一个简单的 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 核心目录与职责

Android 源码树中 Camera HAL 相关目录结构 AOSP 根目录 hardware/ frameworks/av/ device/ hardware/libhardware hardware/interfaces frameworks/av/camera/ device/<vendor>/<board>/ include/hardware/camera.h ICameraProvider.hal CameraService / CameraClient camera/ / libcameraservice/ HAL 模块实际编译入口 hardware/libhardware/modules/camera/ 或 device/<vendor>/<board>/camera/

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 编译与集成步骤

  1. 编写或修改 HAL 源码:在 device/<vendor>/<board>/camera/ 下实现 camera_module_t 接口。
  2. 创建或更新构建文件:确保 Android.bp 或 Android.mk 中模块名与 camera.<board>.so 一致。
  3. 执行编译:
    • 全量编译:m -j$(nproc) camera.<board>
    • 增量编译:mm -j$(nproc)(需在模块目录下)
  4. 检查产物:out/target/product/<board>/vendor/lib64/hw/camera.<board>.so
  5. 集成到系统镜像:make -j$(nproc) systemimage vendorimage 或使用 adb push 推送到设备的 /vendor/lib64/hw/ 目录。
  6. 验证加载:重启设备,执行 lshal 或 dumpsys media.camera 确认 HAL 模块被 CameraService 成功加载。
关键检查点:如果 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 三个函数入口和出口各加一条日志。