Earth Guardian

You are not LATE!You are not EARLY!

0%

Camera 其他

介绍 Camera build, system, vendor 等等其他相关知识。

编译与调试

Android 模块编译方法

Android 的编译系统最开始是 make, makefile 体系,但是从 7.0 开始切换到 Android.bp, ninja 等工具。部分源码目录中,Android.mk, Android.bp 两者都有,或者只有其中一个编译配置文件,这里简要介绍下编译区别。

  • Android.mk
    查看 LOCAL_MODULE 中定义的名字,在根目录下直接执行:make *** -j32
  • Android.bp
    cc_** 开头,比如: cc_library, cc_library_shared, cc_binary 等等,同样是执行 make *** -j32

当然也可以直接到该目录下执行 mm ,但如果该模块存在外部依赖可能会导致编译失败,所以最好还是在根目录下执行 make

常见模块的编译

下面是 Camera 中常见模块(注意已经发布的 .hal 文件是不能直接修改的,涉及到 hal 版本升级),对应的编译方法及生成文件路径如下:

  • frameworks/av/services/camera/libcameraservice
    编译命令:make libcameraservice -j32 ,生成文件路径:

    1
    2
    system/lib64/libcameraservice.so
    system/lib/libcameraservice.so
  • hardware/interfaces/camera/common/1.0/default/
    查看 Android.bp 可以看出,该模块编译后生成一个静态文件。

    1
    2
    3
    4
    5
    6
    7
    8
    // Android.bp ,静态库
    cc_library_static {
    name: "android.hardware.camera.common@1.0-helper",
    vendor_available: true,
    defaults: ["hidl_defaults"],
    srcs: [
    ...
    }

    编译命令:make android.hardware.camera.common@1.0-helper -j32,生成文件路径:

    1
    2
    3
    // 生成文件路径  
    ./obj/STATIC_LIBRARIES/android.hardware.camera.common@1.0-helper_intermediates/android.hardware.camera.common@1.0-helper.a
    ./obj_arm/STATIC_LIBRARIES/android.hardware.camera.common@1.0-helper_intermediates/android.hardware.camera.common@1.0-helper.a

    所有依赖静态文件的模块,都需要重新编译并 push 到手机中:

    1
    2
    3
    4
    5
    6
    7
    8
    // 查找其他 Android.bp 文件可以看到,有多处依赖它
    interfaces/camera/provider/2.4/vts/functional/Android.bp:34: "android.hardware.camera.common@1.0-helper",
    interfaces/camera/provider/2.4/default/Android.bp:29: "android.hardware.camera.common@1.0-helper"
    interfaces/camera/common/1.0/default/Android.bp:2: name: "android.hardware.camera.common@1.0-helper",
    interfaces/camera/device/3.2/default/Android.bp:22: "android.hardware.camera.common@1.0-helper"
    interfaces/camera/device/1.0/default/Android.bp:28: "android.hardware.camera.common@1.0-helper"
    interfaces/camera/device/3.3/default/Android.bp:24: "android.hardware.camera.common@1.0-helper"
    qcom/camera/QCamera2/Android.mk:121:LOCAL_STATIC_LIBRARIES := android.hardware.camera.common@1.0-helper
  • hardware/interfaces/camera/provider/2.4/default
    编译命令 make android.hardware.camera.provider@2.4-impl -j32 ,生成的文件路径:

    1
    2
    vendor/lib/hw/android.hardware.camera.provider@2.4-impl.so
    vendor/lib64/hw/android.hardware.camera.provider@2.4-impl.so
  • hardware/qcom/camera/QCamera2
    编译命令:make camera.msm8937 -j32; ,其中 msm8937 表示当前项目所属平台名称,生成文件路径:

    1
    2
    3
    4
    5
    6
    7
    8
    // hardware/qcom/camera/QCamera2/Android.mk
    LOCAL_MODULE_RELATIVE_PATH := hw
    LOCAL_MODULE := camera.$(TARGET_BOARD_PLATFORM)
    LOCAL_VENDOR_MODULE := true
    LOCAL_MODULE_TAGS := optional

    // 生成文件地址
    vendor/lib/hw/camera.msm8937.so
  • hardware/interfaces/camera/device/1.0/default/
    编译命令:make camera.device@1.0-impl -j32 ,生成文件路径:

    1
    2
    ./vendor/lib/camera.device@1.0-impl.so
    ./vendor/lib64/camera.device@1.0-impl.so
  • hardware/qcom/camera/QCamera2/stack/mm-camera-interface
    编译命令:make libmmcamera_interface -j32 ,生成文件路径:
    ./vendor/lib/libmmcamera_interface.so

  • vendor/qcom/proprietary/mm-camera/mm-camera2/server-imaging 目录
    编译命令:make mm-qcamera-daemon -j32 ,生成文件路径:
    ./vendor/bin/mm-qcamera-daemon

调试

  • Java 文件
    可以直接在 Log 中打印调用关系: Log.d("tag", "message", new Throwable());
  • cpp 文件
    堆栈打印需要添加 libutils ,如果是 Android P 及以上添加 libutilscallstack ,在 cpp 文件中,调用 android:CallStack cs 来打印堆栈。
    1
    2
    #include <utils/CallStack.h>
    android::CallStack cs("XMT:tag");
  • c 文件
    c 文件打印堆栈比较麻烦,需要先封装一个 cpp 文件,并使用 extern "C" 来给 c 调用。

如果出现堆栈错误,根据地址查找代码行数,使用 addr2line 工具来查看:
addr2line -C -f -e ./symbols/vendor/lib/libmmcamera_interface.so 00015414

Camera 分层设计

模块

Camera 是一个比较完整的模块,从 APP, Framework, Hardware, System, Vendor, Kernel Driver 每部分都会涉及到,主要关注的是 Framework, Hardware 两块。

  • APP 调用 Framework Java 提供的 API 实现对应功能
  • Framework Java 作为客户端通过 AIDLFramework Native 服务端完成跨进程通信
  • Framework 服务作为客户端通过 HIDLHardware AOSP.hal 接口服务完成跨进程通信
  • Hardware AOSP 通过 dlopen 加载 Hardware qcom 库,实现对应的功能
  • Hardware qcom 通过 socket (也有可能是一个 mshim 层直接加载库)以及 Kernel V4L2 DriverVendor 实现通信
  • System 目录中会提供一些公共的函数或数据结构,方便在各个模块中使用统一结构传递数据

分层设计中,我们只需要关心每一层之间的接口就行,而每层的逻辑处理都封装在这一层内部。

服务

Camera 相关一共会注册三个服务:

  • media.camera
    main_cameraserver.cpp 注册的, Framework camera 的核心,即 CameraService ,实现所有 api 对应功能。
  • media.camera.proxy
    CameraServiceProxy.java 注册的,是代理类,主要实现 CameraService 向系统发回的消息。
  • legacy/0
    HIDL 注册的服务,即 CameraProvider ,封装了 HAL 实现的功能;在 hardware/interfaces/camera/provider/2.4/default/service.cpp 中注册。

进程

Camera 相关主要涉及到三个进程的通信:

  • cameraserver
    CameraService 服务所在进程,实现 Framework 对应功能;代码所在位置:
    frameworks/av/camera/cameraserver/main_cameraserver.cpp
  • android.hardware.camera.provider@2.4-service
    CameraProvider 服务所在进程,实现 HAL 对应功能;代码所在位置:
    hardware/interfaces/camera/provider/2.4/default/service.cpp
  • mm-qcamera-daemon
    Camera Vendor 的进程,功能的最终实现;代码所在位置:
    vendor/qcom/proprietary/mm-camera/mm-camera2/server-imaging/server.c

Vendor Qcom

vendor qcom 中,并不区分 Camera API 1/2 ,也不区分 HAL 1/3 ;不管上面是什么接口,在 HAL qcom 中都会转换为对应的功能函数,而在 vendor qcom 只会有一套代码架构,不同的函数来响应他们。

mm-camera-daemon

mm-camera-daemon 进程源码所在目录:

1
2
3
4
5
server-imaging/
├── Android.mk
├── server.c
├── server_process.c
└── server_process.h

mm-camera-daemon 的服务进程是开机自动运行的,主要作用是介于应用和驱动之间翻译 ioctl 的中间层(委托处理),其目的是将 VFE/ISP 具体操作策略的私有化代码封闭等等。
在驱动设计中,存在 msm-config, msm-camera 两种 MCT ,前者用于获取事件通知 V4L2 驱动信息;后者用于获取 sensor 操作 V4L2 驱动信息。一个完整的调用流程大致是: app==>v4l2(stream)==>daemon==>v4l2(control)==>app

  • appdaemon 主要是在 v4l2(stream) 中事件通知方式进行的,对于 map/unmap 则直接通过 domain socket 方式进行
  • daemonapp 是通过 v4l2(control) 的事件通知机制进行的
  • v4l2(stream) 是通过 msm-camera 获取到相关信息的, v4l2(control) 是通过 msm-config 获取到相关信息的

mm-camera-daemon 是老版本的架构图,新版本中使用了 mct_shim_layer 来管理,取消了 IPC 通信,简化了流程。 mm-camera-daemon 老版本架构图:

0109-android-camera-6-extras-camera-daemon.png

mct_shim_layer 新版本架构图,通过 dlopen/dlsym 加载 vendor 库:

0109-android-camera-6-extras-mct_shim_layer.png

模块和端口

Camera 的所有功能划分为不同的模块,让模块自己来决定自己的事情(高内聚,低耦合),模块需要有统一的接口和格式。模块中有端口,通过端口把模块连接起来,又把模块挂在总线上。每一个端口的连接就是一个流,把这些流用 pipeline 来管理。每次启动一个 camera 就创建一个会话,由这个会话来管理此 Camera 的一切事物。对于每一个会话,模块是共享的,它可以是 Camera 的硬件资源也可以是其它资源(如一些软件算法等资源)。

  • 端口
    端口属于模块,如果这个模块只有 source 端口,那么它就是一个 src 模块;如果只有 sink 端口就是 sink 模块;如果都有就是中间模块。没有端口的模块是不能连接到流中的,但他可以完成一些其他的功能,比如接收引擎的设置,报告事件到 bus 等。连接到流中的端口,也就是说流事件 set/get 主要通过端口来处理。而来自于引擎的 set/get 通过模块来处理,当然端口也可以把事件交给模块来处理。
  • 模块线程
    每个模块可以有一个线程来处理模块的事情。一个线程对应一个队列,线程就是从队列中取出数据处理,然后应答回去。
  • 总线回调
    当一个模块向总线注册时,总线向其提供一个回调函数,当模块有事件发生时,调用这个函数向 bus 发消息,然后总线把这个消息提交给管道,管道把这个消息顺着流发下去。

核心控制代码路径如下,目录结构为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller
mct
├── Android.mk
├── bus
├── controller
├── debug
├── event
├── module
├── object
├── pipeline
├── port
├── stream
└── tools
mct_shim_layer
├── Android.mk
├── mct_shim_layer.c
└── mct_shim_layer.h
modules/
├── iface2
├── imglib // 主要是图片的一些后端处理,如 HDR 等
├── includes
├── isp
├── isp2
├── pproc
├── pproc-new
├── sensors
└── stats // 一些统计算法模块,如 3A,ASD,AFD,IS,GRRO 等数据统计的处理

高通控制模块架构图:

0109-android-camera-6-extras-imagingserver-mct.png

System

System 中定义的数据结构体,贯穿整个 Framework, HAL, Vendor ,在这三层中定义统一的数据传递格式。

目录结构

System 中和 Camera 相关的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
system/core/libsystem/include/system/camera.h
system/media/private/camera/include/camera_metadata_hidden.h
system/sepolicy/private/cameraserver.te
system/sepolicy/vendor/hal_camera_default.te
system/sepolicy/prebuilts/api/26.0/private/cameraserver.te
system/sepolicy/prebuilts/api/26.0/public/hal_camera.te
system/sepolicy/prebuilts/api/26.0/public/cameraserver.te
system/sepolicy/public/hal_camera.te
system/sepolicy/public/cameraserver.te
system/media/camera
system/media/camera/src/camera_metadata.c
system/media/camera/src/camera_metadata_tag_info.c
system/media/camera/docs/CameraDeviceInfo.mako
system/media/camera/docs/CameraMetadataEnums.mako
system/media/camera/docs/ndk_camera_metadata_tags.mako
system/media/camera/docs/camera_metadata_tags.mako
system/media/camera/docs/camera_device_info.proto
system/media/camera/docs/camera_device_info.mako
system/media/camera/docs/camera_metadata_tag_info.mako
system/media/camera/docs/CameraMetadataKeys.mako
system/media/camera/docs/ACameraMetadata.mako
system/media/camera/docs/CameraCharacteristicsKeys.mako
system/media/camera/docs/images/camera2
system/media/camera/include/system/camera_metadata.h
system/media/camera/include/system/camera_vendor_tags.h
system/media/camera/include/system/camera_metadata_tags.h
system/media/camera/tests/camera_metadata_tests.cpp
system/media/camera/tests/camera_metadata_tests_fake_vendor.h

分为几部分:

  • 头文件
    1
    2
    system/core/libsystem/include/system/camera.h
    system/media/private/camera/include/camera_metadata_hidden.h
  • 权限
    system/sepolicy/
  • 系统共有文件
    system/media/camera

生成 Metadata 文件

Camera Metadata 相关的属性,都是自动生成的,不能直接在代码中修改。这些属性是在 system/media/docs/ 中的 metadata_properties.xml, ndk_metadata_properties.xml 两个配置文件中定义的, .mako 指定了生成规则,通过解析工具解析后生成对应的 .java, .h 文件。

1
2
3
4
frameworks/base/core/java/android/hardware/camera2/CameraCharacteristics.java
frameworks/base/core/java/android/hardware/camera2/CaptureResult.java
frameworks/base/core/java/android/hardware/camera2/CaptureRequest.java
frameworks/av/camera/ndk/include/camera/NdkCameraMetadataTags.h

camera_metadata 数据结构

camera_metadata 数据结构贯穿整个 Camera 架构,用于传递 Camera 相关参数设置。
camera_metadata_tags.h 中定义了所有的枚举值,特别是 camera_metadata 数据段相关的性质:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// camera_metadata_tags.h
typedef enum camera_metadata_section {
ANDROID_COLOR_CORRECTION,
ANDROID_CONTROL,
ANDROID_DEMOSAIC,
ANDROID_EDGE,
ANDROID_FLASH,
ANDROID_FLASH_INFO,
ANDROID_HOT_PIXEL,
ANDROID_JPEG,
ANDROID_LENS,
ANDROID_LENS_INFO,
ANDROID_NOISE_REDUCTION,
ANDROID_QUIRKS,
ANDROID_REQUEST,
ANDROID_SCALER,
ANDROID_SENSOR,
ANDROID_SENSOR_INFO,
ANDROID_SHADING,
ANDROID_STATISTICS,
ANDROID_STATISTICS_INFO,
ANDROID_TONEMAP,
ANDROID_LED,
ANDROID_INFO,
ANDROID_BLACK_LEVEL,
ANDROID_SYNC,
ANDROID_REPROCESS,
ANDROID_DEPTH,
ANDROID_SECTION_COUNT,

VENDOR_SECTION = 0x8000
} camera_metadata_section_t;

主要包含如上几个数据段,且每个数据段大小为 1 << 1664K 大小,也是定义的枚举值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// camera_metadata_tags.h
typedef enum camera_metadata_section_start {
ANDROID_COLOR_CORRECTION_START = ANDROID_COLOR_CORRECTION << 16,
ANDROID_CONTROL_START = ANDROID_CONTROL << 16,
ANDROID_DEMOSAIC_START = ANDROID_DEMOSAIC << 16,
ANDROID_EDGE_START = ANDROID_EDGE << 16,
ANDROID_FLASH_START = ANDROID_FLASH << 16,
ANDROID_FLASH_INFO_START = ANDROID_FLASH_INFO << 16,
ANDROID_HOT_PIXEL_START = ANDROID_HOT_PIXEL << 16,
ANDROID_JPEG_START = ANDROID_JPEG << 16,
ANDROID_LENS_START = ANDROID_LENS << 16,
ANDROID_LENS_INFO_START = ANDROID_LENS_INFO << 16,
ANDROID_NOISE_REDUCTION_START = ANDROID_NOISE_REDUCTION << 16,
ANDROID_QUIRKS_START = ANDROID_QUIRKS << 16,
ANDROID_REQUEST_START = ANDROID_REQUEST << 16,
ANDROID_SCALER_START = ANDROID_SCALER << 16,
ANDROID_SENSOR_START = ANDROID_SENSOR << 16,
ANDROID_SENSOR_INFO_START = ANDROID_SENSOR_INFO << 16,
ANDROID_SHADING_START = ANDROID_SHADING << 16,
ANDROID_STATISTICS_START = ANDROID_STATISTICS << 16,
ANDROID_STATISTICS_INFO_START = ANDROID_STATISTICS_INFO << 16,
ANDROID_TONEMAP_START = ANDROID_TONEMAP << 16,
ANDROID_LED_START = ANDROID_LED << 16,
ANDROID_INFO_START = ANDROID_INFO << 16,
ANDROID_BLACK_LEVEL_START = ANDROID_BLACK_LEVEL << 16,
ANDROID_SYNC_START = ANDROID_SYNC << 16,
ANDROID_REPROCESS_START = ANDROID_REPROCESS << 16,
ANDROID_DEPTH_START = ANDROID_DEPTH << 16,
VENDOR_SECTION_START = VENDOR_SECTION << 16
} camera_metadata_section_start_t;

这里举例说明 ANDROID_FLASH 相关参数,都是从 ANDROID_FLASH_START 位置开始,并以 ANDROID_FLASH_END 结尾,在 64K 空间内包含了如下几个参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// camera_metadata_tags.h
typedef enum camera_metadata_tag {
...
ANDROID_EDGE_END,

ANDROID_FLASH_FIRING_POWER = // byte | system
ANDROID_FLASH_START,
ANDROID_FLASH_FIRING_TIME, // int64 | system
ANDROID_FLASH_MODE, // enum | public
ANDROID_FLASH_COLOR_TEMPERATURE, // byte | system
ANDROID_FLASH_MAX_ENERGY, // byte | system
ANDROID_FLASH_STATE, // enum | public
ANDROID_FLASH_END,

ANDROID_FLASH_INFO_AVAILABLE = // enum | public
ANDROID_FLASH_INFO_START,
...

0109-android-camera-6-extras-camera_metadata_section.png

camera_metadata 的内存结构体定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// camera_metadata.c
/**
* A packet of metadata. This is a list of entries, each of
* which may point to its values stored at an offset in data.
*
* It is assumed by the utility functions that the memory
* layout of the packet is as follows:
*
* |-----------------------------------------------|
* | camera_metadata_t |
* | |
* |-----------------------------------------------|
* | reserved for future expansion |
* |-----------------------------------------------|
* | camera_metadata_buffer_entry_t #0 |
* |-----------------------------------------------|
* | .... |
* |-----------------------------------------------|
* | camera_metadata_buffer_entry_t #entry_count-1 |
* |-----------------------------------------------|
* | free space for |
* | (entry_capacity-entry_count) entries |
* |-----------------------------------------------|
* | start of camera_metadata.data |
* | |
* |-----------------------------------------------|
* | free space for |
* | (data_capacity-data_count) bytes |
* |-----------------------------------------------|
*
* With the total length of the whole packet being
* camera_metadata.size bytes.
*
* In short, the entries and data are contiguous in memory
* after the metadata header.
*/
#define METADATA_ALIGNMENT ((size_t) 4)
struct camera_metadata {
metadata_size_t size;
uint32_t version;
uint32_t flags;
metadata_size_t entry_count;
metadata_size_t entry_capacity;
metadata_uptrdiff_t entries_start; //Offset from camera_metadata
metadata_size_t data_count;
metadata_size_t data_capacity;
metadata_uptrdiff_t data_start; // Offset from camera_metadata
uint32_t padding; // padding to 8 bytes boundary
metadata_vendor_id_t vendor_id;
};

常见调试对应属性

  • persist.camera.dumpimg
    设置为 1 时,每次拍照预览都会在 /data/misc/camera 目录记录当前帧图片。
  • persist.camera.global.debug 全局调试输出 LOG
  • persist.camera.hal.debug HAL 模块输出 LOG
  • persist.camera.mci.debug mci 模块输出 LOG
  • persist.camera.mmstill.logs JPEG 拍照输出 LOG

参考文档