相机

Android Camera HAL icon

Android 的相机硬件抽象层 (HAL) 将 Camera 2 中更高级别的相机框架 API 连接到您的底层相机驱动程序和硬件。相机子系统包括相机流水线组件的实现,而相机 HAL 提供用于实现这些组件的您自己版本的接口。

架构

下图和列表描述了 HAL 组件。

Android camera architecture

图 1. 相机架构

应用框架
在应用框架层,是应用的代码,它使用 Camera 2 API 与相机硬件进行交互。在内部,此代码调用相应的 Binder 接口来访问与相机交互的原生代码。
AIDL
CameraService 关联的绑定器接口可在 frameworks/av/camera/aidl/android/hardware 中找到。生成的代码调用较低级别的原生代码以获取对物理摄像头的访问权限,并返回用于在框架级别创建 CameraDevice 和最终 CameraCaptureSession 对象的数据。
原生框架
此框架位于 frameworks/av/ 中,提供与 CameraDevice CameraCaptureSession 类等效的原生类。另请参阅 NDK camera2 参考
绑定器 IPC 接口
IPC 绑定器接口有助于跨进程边界进行通信。在 frameworks/av/camera/camera/aidl/android/hardware 目录中有多个调用摄像头服务的摄像头绑定器类。 ICameraService 是摄像头服务的接口; ICameraDeviceUser 是特定已打开摄像头设备的接口; ICameraServiceListener ICameraDeviceCallbacks 分别是 CameraServiceCameraDevice 到应用框架的回调。
摄像头服务
摄像头服务位于 frameworks/av/services/camera/libcameraservice/CameraService.cpp 中,是与 HAL 交互的实际代码。
HAL
硬件抽象层定义了摄像头服务调用的标准接口,您必须实现该接口才能使摄像头硬件正常工作。

实现 HAL

HAL 位于摄像头驱动程序和更高级别的 Android 框架之间,并定义了一个您必须实现的接口,以便应用可以正确操作摄像头硬件。HIDL 摄像头 HAL 的接口在 hardware/interfaces/camera 中定义。

典型的绑定器化 HAL 必须实现以下 HIDL 接口

参考 HIDL 实现可用于 CameraProvider.cpp CameraDevice.cppCameraDeviceSession.cpp。该实现封装了仍在使用 旧版 API 的旧 HAL。从 Android 8.0 开始,摄像头 HAL 实现必须使用 HIDL API;不支持使用旧版接口。

输入验证

由于 HAL 可以访问与摄像头服务不同的资源,因此两者之间的边界被视为安全边界。这意味着从摄像头服务传递的参数被视为不受信任且未经清理。为了防止攻击者升级权限或访问他们无权访问的数据的安全漏洞,摄像头 HAL 必须验证从摄像头服务传递到 HAL 的参数。这包括检查缓冲区长度值是否在允许的范围内,以及在使用之前和将参数传递到硬件或内核驱动程序之前对参数进行清理。

旧版 HAL 组件

本部分介绍旧版 HAL 组件的架构以及如何实现 HAL。Android 8.0 及更高版本上的摄像头 HAL 实现必须使用上述 HIDL API。

架构(旧版)

下图和列表描述了旧版摄像头 HAL 组件。

Android camera architecture

图 2. 旧版摄像头架构

应用框架
在应用框架级别是应用的代码,它使用 android.hardware.Camera API 与摄像头硬件交互。在内部,此代码调用相应的 JNI 粘合类来访问与摄像头交互的原生代码。
JNI
android.hardware.Camera 关联的 JNI 代码位于 frameworks/base/core/jni/android_hardware_Camera.cpp 中。此代码调用较低级别的原生代码以获取对物理摄像头的访问权限,并返回用于在框架级别创建 android.hardware.Camera 对象的数据。
原生框架
frameworks/av/camera/Camera.cpp 中定义的原生框架提供了与 android.hardware.Camera 类等效的原生类。此类调用 IPC 绑定器代理以获取对摄像头服务的访问权限。
绑定器 IPC 代理
IPC 绑定器代理有助于跨进程边界进行通信。在 frameworks/av/camera 目录中有三个调用摄像头服务的摄像头绑定器类。ICameraService 是摄像头服务的接口,ICamera 是特定已打开摄像头设备的接口,ICameraClient 是设备返回应用框架的接口。
摄像头服务
摄像头服务位于 frameworks/av/services/camera/libcameraservice/CameraService.cpp 中,是与 HAL 交互的实际代码。
HAL
硬件抽象层定义了摄像头服务调用的标准接口,您必须实现该接口才能使摄像头硬件正常工作。
内核驱动程序
摄像头的驱动程序与实际的摄像头硬件和您实现的 HAL 交互。摄像头和驱动程序必须支持 YV12 和 NV21 图像格式,以提供对在显示屏上预览摄像头图像和录制视频的支持。

实现 HAL(旧版)

HAL 位于摄像头驱动程序和更高级别的 Android 框架之间,并定义了一个您必须实现的接口,以便应用可以正确操作摄像头硬件。HAL 接口在 hardware/libhardware/include/hardware/camera.hhardware/libhardware/include/hardware/camera_common.h 头文件中定义。

camera_common.h 定义了 camera_module,这是一个用于获取有关摄像头的常规信息的标准结构,例如摄像头 ID 和所有摄像头通用的属性(即,它是前置摄像头还是后置摄像头)。

camera.h 包含与 android.hardware.Camera 相对应的代码。此头文件声明了一个 camera_device 结构,该结构又包含一个 camera_device_ops 结构,其中包含指向实现 HAL 接口的函数的指针。有关开发者可以设置的摄像头参数的文档,请参阅 frameworks/av/include/camera/CameraParameters.h。这些参数通过 HAL 中 int (*set_parameters)(struct camera_device *, const char *parms) 指向的函数设置。

有关 HAL 实现的示例,请参阅 hardware/ti/omap4xxx/camera 中 Galaxy Nexus HAL 的实现。

配置共享库

设置 Android 构建系统以将 HAL 实现正确打包到共享库中,并通过创建 Android.mk 文件将其复制到相应的位置

  1. 创建一个 device/<company_name>/<device_name>/camera 目录以包含库的源文件。
  2. 创建一个 Android.mk 文件以构建共享库。确保 makefile 包含以下行
    LOCAL_MODULE := camera.<device_name>
    LOCAL_MODULE_RELATIVE_PATH := hw
    

    您的库必须命名为 camera.<device_name>.so 会自动附加),以便 Android 可以正确加载该库。有关示例,请参阅 hardware/ti/omap4xxx/Android.mk 中 Galaxy Nexus 摄像头的 makefile。

  3. 通过将必要的特性 XML 文件复制到设备 makefile 的 frameworks/native/data/etc 目录中,指定您的设备具有摄像头特性。例如,要指定您的设备具有摄像头闪光灯并且可以自动对焦,请在您设备的 <device>/<company_name>/<device_name>/device.mk makefile 中添加以下行
    PRODUCT_COPY_FILES := \ ...
    
    PRODUCT_COPY_FILES += \
    frameworks/native/data/etc/android.hardware.camera.flash-autofocus.xml:system/etc/permissions/android.hardware.camera.flash-autofocus.xml \
    

    有关设备 makefile 的示例,请参阅 device/samsung/tuna/device.mk

  4. device/<company_name>/<device_name>/media_profiles.xmldevice/<company_name>/<device_name>/media_codecs.xml XML 文件中声明摄像头的媒体编解码器、格式和分辨率功能。有关详细信息,请参阅 向框架公开编解码器
  5. 在您设备的 device/<company_name>/<device_name>/device.mk makefile 中添加以下行,以将 media_profiles.xmlmedia_codecs.xml 文件复制到相应的位置
    # media config xml file
    PRODUCT_COPY_FILES += \
        <device>/<company>/<device>/media_profiles.xml:system/etc/media_profiles.xml
    
    # media codec config xml file
    PRODUCT_COPY_FILES += \
        <device>/<company>/<device>/media_codecs.xml:system/etc/media_codecs.xml
    
  6. 要在设备的系统映像中包含“相机”应用,请在设备 device/<company>/<device>/device.mk makefile 的 PRODUCT_PACKAGES 变量中指定它
    PRODUCT_PACKAGES := \
    Gallery2 \
    ...