Android - 摄像头 - hal - 开发教程,例子,常见问题,分析方法,解决方案

Android Camera HAL 完整开发指南(AIDL HAL 新架构,适配 Android 16)

前置核心背景(承接上文HIDL→AIDL HAL变革)

Android 11开始支持AIDL HAL,Android 16彻底移除HIDL,Camera HAL必须基于AIDL HAL实现 ,IPC全程单Binder驱动,不再有hwbinder。

Camera HAL 两个主流版本:

  1. Camera HAL3(AOSP标准,主流)android.hardware.camera.device@3.x,AIDL重构后为 android.hardware.camera.device AIDL接口
  2. Camera HAL1(废弃) :老旧设备兼容,新项目不考虑
    Treble分区要求:HAL实现必须放到 vendor 分区,通过VNDK隔离system/vendor,遵循分区不可直接链接规则。

一、整体调用数据流(AIDL HAL新架构)

复制代码
App Camera2 API → Framework CameraService(Java AIDL) → JNI → libcamera_client.so(Native)
→ AIDL HAL(标准Binder)→ vendor 厂商Camera HAL实现 → 内核V4L2驱动 → 硬件Sensor/ISP

老架构此处是HIDL+HwBinder,Android16全链路统一标准Binder。

层级拆解

  1. App层:Camera2 API(CaptureRequest/CaptureResult)
  2. Framework层:CameraService、CameraProviderManager,向上AIDL,向下调用HAL
  3. AIDL HAL接口层:Google定义的标准AIDL接口(camera.provider/camera.device/camera.metadata)
  4. Vendor HAL实现层:厂商自研代码,对接V4L2内核驱动
  5. Linux内核层:V4L2 subdev、ISP、CSI总线、DMA缓冲区管理

二、环境准备 & 目录结构(AOSP源码)

1. 源码路径

1)Google标准AIDL HAL接口(不可修改)

复制代码
hardware/interfaces/camera/
├── device/          # ICameraDevice.aidl 设备操作接口
├── provider/       # ICameraProvider.aidl 枚举摄像头、打开设备
├── metadata/       # 元数据定义、能力参数(Characteristics/Request/Result)
└── common/         # 共用枚举、结构体

2)厂商Vendor HAL实现目录(自定义)

规范路径:vendor/[厂商名]/hardware/camera/aidl/

复制代码
vendor/xxx/hardware/camera/aidl/camera_device/
├── Android.bp               # Soong编译脚本(AIDL HAL必须用bp,弃用mk)
├── CameraDevice.cpp/h       # 实现ICameraDevice AIDL接口
├── CameraProvider.cpp/h     # 实现ICameraProvider AIDL接口
├── V4L2Wrapper.cpp/h        # 封装内核V4L2 ioctl操作
├── MetadataHelper.cpp/h     # 处理camera metadata静态/动态参数
└── buffer/                  # Gralloc buffer管理(ANativeWindow、DMA buf)

3)Manifest声明(Treble注册HAL服务)

vendor/etc/vintf/manifest.xml 必须添加,否则Framework无法通过Binder发现HAL服务:

xml 复制代码
<hal format="aidl">
    <name>android.hardware.camera.provider</name>
    <version>1</version>
    <interface>
        <name>ICameraProvider</name>
        <instance>internal/0</instance>
    </interface>
</hal>

2. Android.bp 核心编译模板(AIDL HAL固定写法)

json 复制代码
cc_binary {
    name: "android.hardware.camera.provider-service.xxx",
    init_rc: ["camera_provider.rc"], // init启动脚本

    srcs: [
        "CameraProvider.cpp",
        "CameraDevice.cpp",
        "V4L2Wrapper.cpp",
        "MetadataHelper.cpp",
    ],

    // 依赖Google官方AIDL HAL接口库
    shared_libs: [
        "android.hardware.camera.provider-V1-ndk",
        "android.hardware.camera.device-V1-ndk",
        "android.hardware.camera.metadata-V1-ndk",
        "libbinder_ndk",    // AIDL Binder依赖
        "libutils",
        "libcutils",
        "libgralloc",       // 图形缓冲区
        "libcamera_metadata",
    ],

    // 关键:标记为vendor分区HAL,VNDK稳定
    vendor: true,
    soc_specific: true,
    vintf_fragments: ["manifest_camera.xml"],
}

3. init.rc 启动脚本(camera_provider.rc)

让init进程开机启动HAL Binder服务,注册到servicemanager:

rc 复制代码
service camera-provider-xxx /vendor/bin/android.hardware.camera.provider-service.xxx
    class hal
    user camera
    group camera graphics drmrpc
    capabilities SYS_NICE
    on binder SERVICE_MANAGER_PRIORITY_HAL

三、最简代码实现示例(AIDL HAL)

示例1:ICameraProvider 核心接口实现(枚举摄像头)

cpp 复制代码
#include <android/hardware/camera/provider/ICameraProvider.h>
using namespace ::android::hardware::camera::provider;

class CameraProvider : public ICameraProvider {
public:
    // 1. 获取当前所有摄像头ID(后置0、前置1)
    binder::Status getCameraIdList(std::vector<std::string>* outCameraIds) override {
        outCameraIds->clear();
        outCameraIds->push_back("0"); // 后置主摄
        outCameraIds->push_back("1"); // 前置副摄
        return binder::Status::ok();
    }

    // 2. 根据cameraId打开ICameraDevice设备
    binder::Status openCameraDevice(const std::string& cameraId,
            const ::android::sp<::android::hardware::camera::device::ICameraDeviceCallback>& cb,
            ::android::sp<::android::hardware::camera::device::ICameraDevice>* outDevice) override {

        if (cameraId == "0" || cameraId == "1") {
            *outDevice = new CameraDevice(cameraId, cb);
        } else {
            return binder::Status::fromServiceSpecificError(-1);
        }
        return binder::Status::ok();
    }

    // 3. 注册Binder服务入口
    static void registerService() {
        sp<ICameraProvider> provider = new CameraProvider();
        ::android::defaultServiceManager()->addService(
            String16("android.hardware.camera.provider/internal/0"), provider);
    }
};

// main函数,HAL服务入口
int main() {
    CameraProvider::registerService();
    ::android::ProcessState::self()->startThreadPool();
    pause();
    return 0;
}

示例2:ICameraDevice 核心能力(下发CaptureRequest、V4L2取流)

核心需要实现的关键AIDL方法:

  1. getCameraCharacteristics():上报摄像头静态能力(分辨率、对焦、AE、HDR、传感器尺寸)
  2. configureStreams():配置预览/拍照流尺寸、格式(YUV_420_888、RAW、JPEG)
  3. submitCaptureRequests():下发上层CaptureRequest,驱动V4L2队列buffer、触发ISP拍照
  4. flush()/close():停止流、释放buffer、关闭V4L2设备节点

V4L2极简封装片段

cpp 复制代码
int V4L2Wrapper::openDev(const std::string& devPath) {
    mFd = open(devPath.c_str(), O_RDWR);
    // 设置捕获格式 V4L2_PIX_FMT_YUV420
    struct v4l2_format fmt = {};
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width = 1920;
    fmt.fmt.pix.height = 1080;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
    ioctl(mFd, VIDIOC_S_FMT, &fmt);

    // 申请MMAP缓冲区、入队buffer
    requestBuffers();
    enqueueAllBuffers();
    // 启动捕获
    int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ioctl(mFd, VIDIOC_STREAMON, &type);
    return mFd;
}

示例3:Camera Metadata 能力上报(决定App可用功能)

getCameraCharacteristics 必须填充标准key,Framework校验不通过摄像头直接不可用:

cpp 复制代码
camera_metadata_t* chars = allocate_camera_metadata(100, 10);
// 支持自动对焦
add_camera_metadata_entry(chars, ANDROID_LENS_FOCUS_AVAILABLE_MODES,
    ANDROID_LENS_FOCUS_MODE_AUTO);
// 最大预览分辨率
int32_t res[] = {1920, 1080};
add_camera_metadata_array(chars, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, res, 2);

四、调试&问题定位全套分析方法(实操工具链)

工具1:dumpsys 查看HAL服务是否注册成功

bash 复制代码
# 查看camera provider AIDL HAL是否注册
adb shell dumpsys android.hardware.camera.provider
# 列出所有已注册AIDL HAL服务
adb shell dumpsys binder | grep camera
# 查看VINTF manifest是否加载正确
adb shell dumpsys vendor | grep camera.provider

正常输出能看到 internal/0 实例,失败=manifest.xml写错/rc未启动服务。

工具2:Logcat 分层日志过滤

bash 复制代码
# 过滤CameraService Framework日志
adb logcat -b main CameraService:* *:S
# 过滤Vendor HAL层自定义日志(TAG:CAM_HAL)
adb logcat CAM_HAL:* *:S
# 过滤Binder AIDL调用事务日志
adb logcat Binder:* BpCamera:* BnCamera:* *:S

工具3:Perfetto 全链路性能追踪(你重点在用)

抓取要点(适配Android16 AIDL HAL)

  1. 数据源勾选:binder transactioncameraftracev4l2dmabuf
  2. 可观测链路:
    • App → CameraService Binder耗时
    • CameraService → Vendor AIDL HAL Binder单次调用耗时(只有一套Binder,无HwBinder割裂)
    • HAL内部V4L2 ioctl阻塞、buffer队列等待、DMA内存拷贝耗时
  3. 典型瓶颈:submitCaptureRequests Binder调用耗时过长、V4L2 poll阻塞、内存拷贝过多。

工具4:内核层V4L2调试工具

bash 复制代码
# 查看摄像头V4L2设备节点
adb shell ls /dev/v4l-subdev* /dev/video*
# v4l2-ctl查看当前格式、帧率、buffer队列状态
adb shell v4l2-ctl -d /dev/video0 --get-fmt-video
adb shell v4l2-ctl --list-formats
# 查看内核CSI/ISP报错dmesg
adb shell dmesg | grep -E "camera|isp|csi|dvp|v4l2"

工具5:libcamera工具验证HAL可用性

bash 复制代码
adb shell libcamera-hello
# 枚举摄像头能力
adb shell libcamera-list

如果libcamera能枚举,说明HAL服务注册、V4L2驱动基本正常,问题在上层Framework参数适配。


五、高频常见问题 + 根因 + 解决方案

问题1:打开相机提示无法连接相机,App闪退,dumpsys看不到HAL实例

根因

  1. vintf manifest.xml AIDL hal name/version写错;
  2. init.rc权限不足(缺少camera/graphics用户组);
  3. Android.bp未添加vendor: true,编译进system分区,Treble拦截;
  4. HAL进程crash,logcat有SIGSEGV空指针。

解决

  1. 核对manifest AIDL格式,HIDL写法全部删掉(Android16不兼容);
  2. rc文件group添加camera、graphics、drmrpc;
  3. bp强制vendor:true,soc_specific:true;
  4. logcat定位崩溃栈,修复空指针(大概率openCameraDevice返回空设备)。

问题2:摄像头枚举成功,configureStreams失败,预览黑屏

根因

  1. stream配置的分辨率/像素格式V4L2内核不支持;
  2. Gralloc buffer DMA内存分配失败,HAL无法映射buffer到内核;
  3. V4L2_STREAMON启动失败,ISP时钟/CSI硬件未上电。

解决

  1. v4l2-ctl --list-formats只上报硬件支持的格式;
  2. 依赖libgralloc,使用dmabuf fd传递缓冲区,避免用户态拷贝;
  3. dmesg排查ISP上电、时钟树、MIPI CSI配置。

问题3:拍照CaptureRequest下发无回调,CaptureResult不返回

根因

  1. HAL层ICameraDeviceCallback AIDL回调未触发;
  2. V4L2 DQBUF取帧阻塞,死锁;
  3. Metadata Result未填充有效数据回调给Framework。

解决

  1. 出队V4L2 buffer后主动调用cb->notifyCaptureResult()
  2. V4L2 poll设置超时,防止无限阻塞;
  3. 必须填充ANDROID_SENSOR_TIMESTAMP等必填元数据。

问题4:预览卡顿、掉帧,Perfetto看到Binder耗时高

根因(Android16 AIDL HAL特有)

  1. CaptureRequest频繁大量AIDL Parcel序列化拷贝;
  2. HAL内同步阻塞ioctl占用Binder线程池;
  3. buffer频繁内存拷贝,未使用DMA零拷贝。

解决

  1. 耗时V4L2操作丢到独立工作线程,不占用Binder主线程;
  2. 使用dmabuf文件描述符跨进程传递buffer,零拷贝;
  3. 批量合并CaptureRequest,减少Binder事务次数。

问题5:Android16编译报错,提示HIDL接口找不到

根因

Android16完全移除HIDL库,旧项目依赖@3.5 HIDL接口直接编译失败。

解决

全部迁移为AIDL HAL,替换所有hidl-gen编译规则为aidl-gen,删除hwbinder依赖,全程使用标准binder。

问题6:前后摄切换卡死,CameraDevice关闭释放异常

根因

  1. V4L2文件句柄未close,fd泄漏;
  2. Binder强引用sp循环引用导致对象无法析构;
  3. buffer队列未flush,V4L2缓冲区未释放。

解决

  1. close接口中停止V4L2流、释放mmap buffer、close fd;
  2. 手动弱引用断开ICameraDeviceCallback;
  3. submit flush命令清空pending请求队列。

问题7:相机特性缺失(HDR、美颜、自动对焦App不显示)

根因

getCameraCharacteristics metadata关键字段未正确上报,Framework判定硬件不支持。

解决

对照AOSP camera_metadata_tags.h,完整填充对焦模式、AE模式、可用流配置、动态范围能力。


六、进阶优化点(车载/智能座舱场景,HiCar适配常用)

  1. 多摄像头并发:CameraProvider管理多个ICameraDevice实例,线程池隔离;
  2. 低功耗:Idle状态关闭ISP/CSI时钟,降低功耗;
  3. 360全景拼接:HAL层多目同步曝光、时间戳对齐,输出拼接后大图;
  4. 安全权限 :vendor sepolicy添加camera HAL对/dev/video、dmabuf、sysfs的访问权限(device/vendor/sepolicy);
  5. VNDK稳定性:所有对外接口使用NDK稳定库,禁止直接链接system私有库,避免大版本升级兼容断裂。

七、开源参考工程(直接对照仿写)

  1. AOSP默认参考HAL:hardware/google/camera/aidl/(Google官方AIDL Camera HAL最简实现)
  2. 第三方开源V4L2 Camera AIDL HAL:android-v4l2-camera-hal(github)
  3. 车载厂商参考:高通QCOM Camera HAL、瑞芯微RK Camera AIDL HAL(vendor目录下可扒逻辑)

如果你需要,我可以:

  1. 给你完整可直接编译的全套Android.bp + rc + manifest.xml文件;
  2. 或者给一份Perfetto抓取Camera AIDL Binder卡顿的pbtxt配置
  3. 或者拆解车载360全景摄像头HAL同步逻辑。
相关推荐
summerkissyou19872 小时前
Android 16 架构图
android
神龙天舞20012 小时前
MySQL 备库为什么会延迟好几个小时
android·数据库·mysql
码农coding6 小时前
android12 systemUI 之锁屏
android
圆山猫6 小时前
[Virtualization](三):RISC-V H-extension 与 Guest 执行模式
android·java·risc-v
爱笑鱼6 小时前
Binder(七):getCallingUid() 读到的是谁?clearCallingIdentity() 又清掉了什么?
android
2501_9159090612 小时前
iOS 应用反调试技详解术 检测调试器的原理与防护实践
android·ios·小程序·https·uni-app·iphone·webview
Lvan的前端笔记12 小时前
AndroidX 完全入门指南
android·androidx
帅次13 小时前
Android 应用高级面试:Window 近1年高频追问 18 题
android·面试·职场和发展
总捣什么乱113 小时前
MySQL MySQL是怎么保证主备一致的?
android·mysql·adb