Camera HAL工程实战:从移植到量产优化 - 第3节
3.1 交叉编译工具链配置
Camera HAL 模块最终运行在嵌入式设备(如手机、平板、IoT 摄像头)的 Linux 内核之上,而非开发主机(x86_64)。因此,必须使用交叉编译工具链,在主机上编译出目标架构(ARM64、ARM32、RISC-V 等)的可执行文件与共享库。
3.1.1 工具链选择与安装
Android 官方推荐使用 Clang/LLVM 作为默认编译器,GCC 已逐步弃用。在 AOSP 源码树中,预编译工具链位于 prebuilts/clang/host/linux-x86/ 目录下。对于 Camera HAL 开发,通常不需要手动安装独立工具链,而是通过 Android 构建系统(Soong / Make)自动调用。
| 工具链组件 | 说明 | 典型路径(AOSP 内) |
|---|---|---|
| Clang 编译器 | C/C++ 前端,生成 LLVM IR | prebuilts/clang/host/linux-x86/clang-r487747/bin/clang |
| LLVM 链接器 (lld) | 替代 GNU ld,速度更快 | 同上目录下的 ld.lld |
| sysroot | 目标系统的头文件与库文件根目录 | prebuilts/ndk/current/platforms/android-34/arch-arm64 |
| binutils | 汇编器、反汇编器、strip 等 | prebuilts/gas/linux-x86/ |
TARGET_CLANG_VERSION := clang-r487747。
3.1.2 环境变量与构建配置
在开始编译 Camera HAL 之前,需要正确设置以下环境变量(通常通过 source build/envsetup.sh 和 lunch 自动完成):
- ANDROID_BUILD_TOP:AOSP 源码根目录。
- ANDROID_PRODUCT_OUT:编译产物输出目录。
- ANDROID_HOST_OUT:主机工具输出目录。
- PATH:必须包含
$ANDROID_BUILD_TOP/prebuilts/clang/host/linux-x86/clang-版本/bin。
# 典型初始化流程
cd ~/aosp
source build/envsetup.sh
lunch aosp_arm64-userdebug
# 验证工具链
which clang
# 输出应指向 prebuilts/clang/.../clang
clang --version
# 确认目标 triple 为 aarch64-linux-android
3.2 Android 源码树结构
Camera HAL 开发人员必须熟悉 AOSP 源码树中与 Camera 相关的关键目录。错误的文件放置位置会导致编译系统找不到模块或依赖。
3.2.1 Camera 相关目录全景
3.2.2 关键目录职责
| 目录路径 | 职责 | HAL 开发者关注点 |
|---|---|---|
hardware/interfaces/camera/ |
定义 Camera HIDL/AIDL 接口(ICameraDevice、ICameraProvider 等) | 实现接口时需严格遵循 .hal 文件中的方法签名 |
hardware/libhardware/modules/camera/ |
存放 legacy Camera HAL (camera_module_t) 示例代码 | 参考 CameraHardwareInterface.h 实现 open/close/ops |
frameworks/av/camera/ |
CameraService、CameraClient、Camera2Client | 理解 Framework 如何调用 HAL 接口,调试 binder 调用 |
device/<vendor>/<board>/camera/ |
OEM 自定义 Camera HAL 实现、专属算法库、传感器驱动适配 | 主要开发工作目录,包含 Android.bp 和所有源文件 |
vendor/<oem>/ |
闭源二进制库、专有图像处理库(如高通、联发科、三星) | 链接 libmmcamera.so 或 libcamx.so 等闭源库 |
3.3 HAL 模块编译与集成流程
从零开始将一个 Camera HAL 模块集成到 AOSP 构建系统中,需要依次完成模块声明、依赖配置、编译脚本编写、产物打包四个步骤。
3.3.1 模块声明与 Android.bp
Android 新构建系统使用 Blueprint/Soong,配置文件为 Android.bp(取代旧式的 Android.mk)。以下是一个典型的 Camera HAL 模块 Android.bp 示例:
// device/vendor/board/camera/Android.bp
cc_library_shared {
name: "camera.<vendor>.<board>",
vendor: true,
relative_install_path: "hw",
srcs: [
"CameraHAL.cpp",
"CameraDevice.cpp",
"CameraStream.cpp",
],
shared_libs: [
"libhardware",
"libcutils",
"libutils",
"liblog",
"libcamera_metadata",
"libsync",
],
header_libs: [
"camera_metadata_headers",
],
cflags: [
"-Wall",
"-Werror",
"-O2",
"-DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION)",
],
include_dirs: [
"device/vendor/board/include",
],
sanitize: {
hwaddress: true, // 量产前开启 HWASan 检测内存错误
},
}
•
vendor: true:产物安装到 /vendor/lib64/hw/ 分区,而非 system 分区。•
relative_install_path: "hw":HAL 模块必须放在 hw 子目录下,HAL 加载器通过 /vendor/lib64/hw/camera.<board>.so 路径查找。•
shared_libs:必须链接 libhardware(提供 hw_module_t 结构体)和 libcamera_metadata(操作 camera_metadata_t)。
3.3.2 编译与产物验证
执行以下命令编译 Camera HAL 模块:
cd ~/aosp
source build/envsetup.sh
lunch aosp_arm64-userdebug
# 编译指定模块
make camera.<vendor>.<board> -j$(nproc)
# 或者编译整个 vendor 分区
make vendorimage -j$(nproc)
编译成功后,产物位于 $ANDROID_PRODUCT_OUT/vendor/lib64/hw/camera.<vendor>.<board>.so。使用以下命令验证模块结构:
# 检查 ELF 架构
readelf -h camera.<vendor>.<board>.so | grep Machine
# 输出应为 Machine: AArch64
# 检查 HAL 模块符号
readelf -s camera.<vendor>.<board>.so | grep HAL_MODULE_INFO_SYM
# 必须存在 HAL_MODULE_INFO_SYM_AS_STR 符号,否则 HAL 加载器无法识别
# 检查依赖库
readelf -d camera.<vendor>.<board>.so | grep NEEDED
3.3.3 集成到系统镜像
将 HAL 模块集成到最终系统镜像中有两种方式:
| 集成方式 | 适用场景 | 操作要点 |
|---|---|---|
| 直接编译进 vendor image | 量产固件、完整 OTA 包 | 在 device/vendor/board/device.mk 中添加 PRODUCT_PACKAGES += camera.<vendor>.<board> |
| 通过 adb push 单独调试 | 开发阶段快速迭代 | adb root && adb remount && adb push camera.<vendor>.<board>.so /vendor/lib64/hw/ && adb reboot |
✓ SELinux policy 是否允许 HAL 进程访问 /dev/video* 节点?
✓ 是否在
manifest.xml 中注册了 Camera HAL 实例?✓ 是否关闭了调试日志(
LOG_NDEBUG)以避免性能开销?✓ 是否使用
strip 去除调试符号以减少 .so 体积?
3.3.4 编译集成流程图
3.4 本章小结
Camera HAL 开发环境搭建的核心要点可归纳为:
- 工具链:使用 AOSP 预置的 Clang/LLVM,通过
lunch自动配置交叉编译环境,避免手动设置 sysroot。 - 源码结构:HAL 接口定义在
hardware/interfaces/camera/,Framework 服务在frameworks/av/camera/,OEM 实现放在device/<vendor>/<board>/camera/。 - 编译集成:使用
Android.bp声明模块,通过make编译,产物放入/vendor/lib64/hw/,并在device.mk中注册。 - 验证:使用
readelf检查架构、符号表、依赖库,确保 HAL_MODULE_INFO_SYM 符号存在。
VtsHalCameraProviderV2_4TargetTest 会严格检查 HAL 接口实现的完整性,任何未实现的回调方法都会导致测试失败,阻塞 OTA 发布。