☰
AOSP 13相机代码地图:从App到HAL的关键路径与实战技巧
2026/10/19 5:56:57 网站建设 项目流程

这个问题我在实际工作中被问过不止一次。很多人把"相机代码"默认理解成某个单一的目录,结果打开 AOSP 13 源码树之后一头雾水:packages/apps/Camera2、frameworks/av/services/camera、hardware/interfaces/camera、frameworks/base/core/java/android/hardware/camera2……到底哪个才是真正要改的地方?其实这些目录都属于 AOSP 13 相机相关代码,只是处在不同层级,职责完全不同。这篇文章我给出一份基于 android-13.0.0 分支的相机代码地图,把 App、Framework、Native Service、HAL、Metadata、Codec 这些关键位置指清楚,并顺带讲一些日常定位问题、加日志和增量编译的实操经验,适合刚接触相机模块的 AOSP 开发者,也适合需要修改相机 HAL 但总是找不到头绪的人。

1. 先理清层级再谈位置:相机代码在 AOSP 13 里的三条主线

1.1 一次拍照请求要经过哪几段代码

如果你只是在packages/apps/Camera2里改 UI,却不理解下面还有CameraService和CameraProvider,那很多问题会无从下手。一次普通的拍照,逻辑上至少要穿过四层代码:

  • App 层:packages/apps/Camera2,这是 AOSP 自带的相机应用,负责取景预览、快门按钮、拍照流程编排。
  • Framework Java 层:frameworks/base/core/java/android/hardware/camera2,这里定义了CameraManager、CameraDevice、CameraCaptureSession等公开 API,App 通过 Binder 调用到这里。
  • Native 服务层:frameworks/av/services/camera,核心是CameraService,它负责权限校验、客户端管理、Camera 资源分配,并把请求转给 HAL。
  • HAL 层:hardware/interfaces/camera定义了 CameraProvider 和 CameraDevice 的 HIDL/AIDL 接口,真正的硬件实现一般放在vendor/或hardware/google/这类设备相关目录中。

这四层缺一不可。很多开发者喜欢说“我去改 AOSP 相机 HAL”,但实际上 AOSP 自己并没有一套能跑在真实硬件上的完整 HAL 实现,它只提供了接口定义和参考框架。真实驱动逻辑普遍在 SoC 厂商的 vendor 目录里。这个认知差距,是很多“找不到代码”问题的根源。

1.2 AOSP 13 和 AOSP 12 在相机代码布局上的主要差异

AOSP 13 相机代码的整体骨架与 AOSP 12 大体一致,但有一个明显变化:HAL 接口开始从 HIDL 向 AIDL 迁移,hardware/interfaces/camera下面出现了aidl目录,与原来的 HIDL 版本并存。这直接导致你在 grep 某些接口时经常看到两个长得差不多的分支,比如ICameraDevice既有 HIDL 版本又有 AIDL 版本,具体使用哪个取决于设备指纹中的 manifest 配置。

另外,AOSP 13 中相机相关的模块化构建也进一步推进,部分代码被拆成modules或者通过Android.bp中的override方式组织。比如 Framework Java 层的相机库,在 Android 13 里已经逐渐把frameworks/base下的相机代码重构为独立模块,部分实现会出现在frameworks/base/packages/Camera2之外的地方。所以搜索时不要只盯死一两个固定路径。

2. 用户态入口:从 packages/apps/Camera2 到 framework 相机 API

2.1 packages/apps/Camera2 只是入口,不是全部

AOSP 自带的相机应用目录在packages/apps/Camera2。它的主要代码集中在src/com/android/camera2/下:

  • CameraActivity.java:应用主入口,负责生命周期和模式切换。
  • Camera2Module.java:封装了一整套基于 Camera2 API 的拍照与预览逻辑。
  • ui/:取景 UI、按钮、模式切换界面。
  • data/:拍照参数、模式配置数据。
  • settings/:相机相关设置项。

注意一点:packages/apps/Camera2在 Android 13 里只是一个完整应用,真正跟硬件交互的动作很少。你在这里修改 UI 布局或者拍照流程没问题,但如果要改 HDR、夜景、自动对焦策略,通常要下探到 framework 层甚至 HAL 层。还有个小坑:很多定制系统会直接删掉packages/apps/Camera2,改用厂商自己的相机应用。判断当前系统用的是哪套,在编译前先看产品的PRODUCT_PACKAGES配置即可。

2.2 frameworks/base 里的 Camera2 API 负责"翻译"请求

公开 API 的位置在frameworks/base/core/java/android/hardware/camera2/。这一层的特点是定义了大量接口和数据类:

  • CameraManager.java:负责系统相机服务的访问入口,打开相机、枚举相机列表、注册可用性回调。
  • CameraDevice.java:代表一个打开的物理/逻辑相机,负责创建 CaptureRequest、配置输出 Surface。
  • CameraCaptureSession.java:Session 管理,提交重复请求和单次捕获请求。
  • CaptureRequest.java/CaptureResult.java:携带 AE/AF/AWB、曝光、闪光灯等控制参数的键值集合。
  • params/:包括CaptureRequest的各个参数键,以及输出尺寸、FPS 范围等元数据类。

如果你做 CTS/VTS 或者自测工具,通常会直接接触这些类。AOSP 13 中 camera2 包的类数量比早期版本多不少,主要是支持了 multithread callbacks、advanced sessions 等特性。但整体依然保持对android.hardware.Camera丢弃逻辑的兼容,老的frameworks/base/core/java/android/hardware/Camera.java在 AOSP 13 里还保留着,只是地位边缘化。

2.3 JNI 层和 Binder 层是怎么衔接的

Java API 不能直接进 native,这里面有三个关键路径:

  1. frameworks/base/core/jni/android_hardware_Camera.cpp:这是比较老的 Camera API 的 JNI 桥。
  2. frameworks/base/core/jni/android_hardware_camera2_*.cpp:Camera2 API 的 JNI 层,负责把 Java 对象转成 native 对象,再调用 native 客户端。
  3. frameworks/av/camera/:native 客户端库,例如Camera2Client、CameraDeviceClient、ICameraService等,通过 Binder 进入CameraService进程。

所以如果你发现某个参数在 Java 层设置了,但 HAL 侧没生效,排查链路要顺着CameraManager -> CameraDeviceImpl -> JNI -> ICameraDevice.cpp -> CameraDeviceClient这一条线走,缺一段都不行。

3. 服务端核心:CameraService 与周边 Native 代码

3.1 frameworks/av/services/camera 的排布方式

真正决定相机资源分配、Session 调度、Capture 请求分发的核心服务,在frameworks/av/services/camera。其中最重要的目录是libcameraservice/:

  • CameraService.cpp:核心入口,实现BnCameraService,负责枚举 HAL、创建客户端、处理权限。
  • CameraDeviceClient.cpp:每个打开的相机设备对应一个客户端,负责把 CaptureRequest 从应用传递到 HAL,并回传 CaptureResult。
  • Camera3Device.cpp:相机 HAL3 设备的封装,跟 HAL 的ICameraDeviceSession直接交互。
  • device3/:Camera 3.x 设备相关实现,包括请求队列、结果处理、错误处理。
  • utils/:相机服务工具类,比如曝光、闪光灯、单摄/多摄策略。

如果你要加一个全局相机策略,比如限制某个进程的相机使用时长,CameraService.cpp是绕不开的切入点。注意这里面的线程模型:请求从客户端到达后并不是立刻发给 HAL,而是经过Camera3Device的 RequestQueue 排队,再通过 HAL 回调异步返回。多线程下的 state machine 比较复杂,改代码前先通读Camera3Device.cpp里的状态迁移逻辑,比盲改参数安全得多。

3.2 frameworks/av/camera 客户端库与 AIDL 接口定义

frameworks/av/camera/是 native 层的 camera client 库。它的源码文件很多以ICamera*或者Camera*开头:

  • ICameraService.cpp/.h:服务客户端接口,对应 AIDL 生成的 native 代理。
  • Camera.cpp/.h:旧版 Camera API 的 native 客户端。
  • Camera2Client相关文件和CameraDeviceClient的 native 实现。
  • aidl/或者aidl/android/hardware/...目录:AOSP 13 的 Binder 接口定义会在这里生成 Stub 和 Proxy 代码。

一个容易混淆的点:frameworks/av/camera里的ICameraService.h是 C++ 端使用的接口声明,但真正 Binder 编组和解组代码依赖 AIDL 文件,AIDL 文件一般放在frameworks/av/camera/aidl/android/hardware/下。改接口时如果只改 C++ 头文件、不改 AIDL,编译能过但运行时会出BAD_TYPE这类 binder 错误。

3.3 服务层调试:dumpsys 和日志开关

定位相机问题,先学会看服务状态。相机服务在 AOSP 13 里可以通过以下指令排错:

adb shell dumpsys camera adb shell dumpsys media.camera adb shell dumpsys camera 2>/dev/null | grep -i "error"

dumpsys camera会输出已打开的 Camera 设备、当前 Session、请求队列长度、pending 请求数量、HAL 返回的错误计数。日志方面,CameraService.cpp中大量使用ALOGV/ALOGD/ALOGE,默认只有 error 级打印。想看详细请求流,可以临时在对应cpp文件里把ALOGV改成ALOGD,或者在Android.bp的 cflags 中加上-DLOG_NDEBUG=0。AOSP 13 还支持通过adb shell setprop log.tag.cameraservice DEBUG开启部分 java 层日志,但 native 层并不完全受这个属性控制,最可靠的还是编译调试版。

4. HAL 层是绕不开的核心:hardware/interfaces/camera 与 vendor 实现

4.1 HIDL 目录 vs AIDL 目录,不能只看一半

在 AOSP 13 源码里,hardware/interfaces/camera下面既有老式的*@2.x、*@3.xHIDL 目录,又有新的aidl目录。几个主要子目录:

  • common/:公共类型定义,如CameraMetadata、CameraStatus。
  • device/:ICameraDevice、ICameraDeviceSession的 HIDL 接口定义,版本从3.2一直到3.7。
  • provider/:ICameraProvider接口,负责枚举和打开 Camera 设备,版本包括2.4、2.5等。
  • metadata/:相机 metadata 的 HIDL 定义和解析器。
  • aidl/:Android 13 中新增的 AIDL 版本,比如android.hardware.camera.provider,核心接口是ICameraProvider、ICameraDevice、ICameraDeviceSession。

这套接口只定义协议,不提供硬件实现。如果你在hardware/interfaces/camera/device/3.7/default/里看到一些实现示例,那只是参考代码或者模拟实现,生产设备一般不会直接用。

4.2 真正控制硬件的代码在哪:vendor 与 hardware/google

不同平台差异很大,但通常规律是这样:

  • vendor/qcom/.../camera:高通平台常见的 Camera HAL 实现,例如vendor/qcom/proprietary或某芯片厂商的camera/目录。
  • hardware/google/camera/:Pixel 等设备的 Google Camera HAL,包含devices/、metadata/、HAL/等子模块。
  • hardware/libhardware/modules/camera/:这个是老式 Camera HAL1 的参考代码和头文件定义,主要包括camera.h和最简单的实现示例。如果你做的是 HAL3 设备,这个目录基本只是历史遗留。
  • device/<vendor>/<board>/:板级配置、manifest.xml中的 HAL 版本声明、camera相关的ProductPackages和权限配置。

找厂商私有的代码确实要看具体源码交付方式。有时候 vendor 的 camera 代码并不在你的 AOSP 主工程里,而是一个单独的源码包,编译时通过device/下的BoardConfig.mk或Android.mk引进来。所以收到一套源码后先别急着 grepCameraProvider,先看device/目录下的soong_namespace和PRODUCT_PACKAGES,确认 camera HAL 的模块名。比如模块名是android.hardware.camera.provider@2.6-impl,就在包含它的那个.mk或.bp文件里顺藤摸瓜找到实现路径。

4.3 Android 13 里改 HAL 要关注的版本和接口变化

Android 13 的相机 HAL 开始强制支持 AIDL 接口选项。比如在manifest.xml中你可以同时声明 HIDL 的android.hardware.camera.provider@2.6和 AIDL 的android.hardware.camera.provider.ICameraProvider。实际加载哪个,由CameraService按优先级选择。这个双轨机制带来一个必须注意的问题:如果你在 AIDL 侧实现了某个新功能,但 manifest 里 HIDL 版本优先级高,那么新功能根本不生效。

AOSP 13 中另一个值得关注的接口变化是ICameraDeviceSession引入了更多关于 latency、concurrent camera 组合的能力定义。需要查阅对应版本头文件时,先看hardware/interfaces/camera/aidl/android/hardware/camera/device/下有没有.aidl文件,没有再去hardware/interfaces/camera/device/3.7/里找 HIDL 版本。

5. 最容易被忽略的两块:Metadata 定义与 Codec/图像编解码链路

5.1 system/media/camera/docs 里的 metadata 才是"契约"

相机控制参数不只是 Java 层那几个类。在 AOSP 13 中,system/media/camera/docs/目录维护了所有相机 Metadata 的文档和自动代码生成脚本:

  • docs/docs.html或.md:Camera Metadata 的完整说明文档。
  • system/media/camera/docs/metadata_definitions.xml:定义所有android.*控制项和静态特性。
  • 生成脚本把这些 XML 转成 C++ 头文件system/media/camera/include/system/camera_metadata.h,以及 Java 层使用的CameraMetadata相关类。

如果你想要给 HAL 增加一个自定义的控制项,比如"超级夜景模式开关",正确做法不是只在某个 HAL 实现里加一个字段,而是先在metadata_definitions.xml里定义android.control.superNightMode这样的 key,再运行生成脚本更新头文件和 Java API。否则 HAL 侧和 Framework 侧的 metadata tag 会完全对不上。

5.2 Frameworks/av/media/codec2:相机数据的编码出口

拍照完成后,照片要编码成 JPEG 或 HEIF;录像时,视频帧要经过编码器。这些实现主要落在frameworks/av/media/codec2/:

  • core/:Codec2 框架核心,包括Codec2Client、CCodec、Buffer 管理逻辑。
  • components/:内置软解软编组件,大量基于 C2 接口的 codec 实现。
  • vendor/:厂商编解码实现适配入口,指示hardware/interfaces/media/codec2的接口实现。

相机与编码器之间的数据流很有意思,现代 AOSP 架构上,相机输出 Surface 可以直接作为MediaCodec的输入 Surface,中间避免一次 CPU 拷贝。这套机制的核心代码大多数在libgui的BufferQueue和Surface类里,目录是frameworks/native/libs/gui/。如果你发现录像性能差、花屏或掉帧,不要只盯着相机 HAL,还要检查BufferQueue的 consumer/producer 配置,尤其是 buffer 数量、等待时间和 Format 是否匹配。

5.3 硬件编解码接口位置

HAL 侧有独立的hardware/interfaces/media/codec2/目录,它定义了IComponent、IInputBuffer、IOutputBuffer等接口。AOSP 13 的 Codec2 和相机 Provider 一样,也处在 HIDL 向 AIDL 迁移过程中,所以目录里同时有aidl/和/.../2.x子目录。很多人只搜 camera 却漏了 media 接口,结果在相机 HAL 里找不到编码回调,原因就是编码模块的实现其实挂在 Codec2 的 HAL 侧。搞清楚这个边界,改编码参数时才不会改错地方。

6. 实战定位技巧:那些让"找不到代码"的经验和步骤

6.1 拿到一个相机功能需求,先反向 grep 关键词

我自己的习惯是:只要听到一个相机功能名,先到源码里 grep 它的字符串键。比如你想找 AOSP 13 的夜景模式实现,先搜NIGHT或NIGHT_MODE,大概率会有三条路可选:

  • App 层:packages/apps/Camera2里有 night 模式 UI。
  • Framework 层:frameworks/base/core/java/android/hardware/camera2/params或CaptureRequest里有对应控制键。
  • HAL 层:hardware/interfaces/camera和 vendor 目录里有android.control.*的解析。

用grep -rn直接搜,比按目录猜快得多。遇到接口是 AIDL/HIDL 双版本的项目,记住先加-l列出所有文件,再人工判断哪些属于 HIDL 兼容层、哪些属于当前生效版本。

# 在所有 AOSP 目录搜索某个 camera metadata key grep -rn "SCENE_MODE_NIGHT" packages/ frameworks/ system/ hardware/ vendor/ 2>/dev/null | head -50 # 查找 CameraProvider 的 AIDL/HIDL 实现位置 grep -rn "ICameraProvider" --include="*.aidl" --include="*.hal" hardware/interfaces/ 2>/dev/null

6.2 四个最常见的"找不到"原因

  1. 只看单一分支,HIDL 和 AIDL 混在一起,新旧版本接口长得不一样。
  2. vendor 源码未合入主工程。很多设备开展工作时,源码仓库里根本没有QcomCamera或CameraHal等 softlink 指向的路径。
  3. 功能实现不在相机模块,而在 Media 或 Display 模块。比如 EIS、防抖、裁切、旋转,一部分逻辑在 camera provider 里,一部分在 codec 或 graphic buffer 转换中。
  4. 模块被裁剪。定制产品删除了 Camera2 app 或某个 Camera HAL 组件,导致源码里只剩一个.bp文件引用了不存在的模块。

遇到这些情况,先检查out/soong模块日志和vendor目录的软链情况,任何情况下都不要在大仓库里盲 grep 一整天之后直接放弃。

6.3 给相机相关框架代码加日志并增量编译

以在CameraService.cpp加日志为例。改完代码后,不需要整包重新构建,只需要编译对应的模块:

# 编译 camera service 模块 source build/envsetup.sh lunch <your_product>-userdebug m libcameraservice # 编译完成后 push 到设备 adb root adb remount adb push out/target/product/<device>/system/lib64/libcameraservice.so /system/lib64/ adb shell sync adb shell stop && adb shell start

如果改的是 Java 层,比如frameworks/base/core/java/android/hardware/camera2/CameraManager.java,则要编译 Framework:

m services.jar framework.jar

之后同样adb push到/system/framework/,并重启 system server 才会生效。

这里有个经验:AOSP 13 里相机服务的模块名有时候不止一个。libcameraservice只是核心,如果你改了ICameraDevice的 Binder 接口,还需要编译对应的libcamera_client和camera2相关模块,否则客户端和服务端代码版本不一致,会出现 Transaction 错误。批量编译时可以直接用m camera或者m camera2这种目标名,但最稳妥的方式还是逐个编译你实际改到源码所属模块。

6.4 验证环境:CTS/VTS 里的相机用例位置参考

最后补充一个参考位置:cts/tests/camera/和vts中camera相关测试源码,常常被我当作"接口调用示例"来读。就算你不跑 CTS,看它怎么调用CameraManager、怎么构造CaptureRequest、怎么等待CaptureResult,也能快速验证你改的 framework 接口是否兼容。另一个值得看的是frameworks/av/services/camera/tests/下的原生测试代码,它绕过 Java 层、直接以 native client 方式调用服务,非常适合用来定位服务端 Binder 层面的问题。

我自己在排查真实设备的相机问题时会格外注意一点:改代码之前,先确认目标设备的相机 HAL 到底是 HIDL 还是 AIDL、manifest 中注册的版本号是多少。因为同一个功能在两种接口下的实现细节差异很大,光看 AOSP 公共目录很容易得出"代码明明就在这"的结论,结果实际跑的却是另一套接口。按照本文列出的层级和目录,按 App -> Framework -> Service -> HAL -> Metadata -> Codec 的顺序逐段排查,绝大多数"找不到"和"改错地方"的问题都能被避免。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询