第九板块:Android 多媒体体系 | 第二十四篇:Camera Service 与 HAL3 成像流水线
所属板块:第九板块 --- Android 多媒体体系
前置知识:第二十三篇中的 AudioFlinger 音频架构、Linux 内核驱动(V4L2)、Binder IPC、内存共享机制(Ashmem/ION)、SurfaceFlinger 显示合成
本篇定位 :这是 Android 设备视觉采集的精密仪器 。如果说屏幕是输出,那么相机就是最高带宽的输入 。本篇将彻底拆解 Camera Service 的架构、HAL3 (Camera HAL 3.x) 的请求/响应模型、Capture Request 的流水线化处理、3A 算法(AF/AE/AWB) 的控制闭环、RAW 域与 YUV 域 的图像处理流程。我们将深入 Camera HAL Interface 、Kernel V4L2 Driver 与 Framework Service,揭示 Android 如何在 30ms 内完成从光子到比特的转换。全程无相机拍照代码、无参数调优指南,仅保留 Android 相机系统的底层定义与系统级调度规范。
1. 核心结论先行(Thesis Statement)
Android 的相机系统是一个基于流水线的请求-响应系统。
- Camera Service 的本质 :相机资源的仲裁者与调度器 。它运行在 System Server 中,管理物理相机设备的生命周期,接收应用层的
CaptureRequest,并将其转换为 HAL 层能理解的指令。 - HAL3 的本质 :无状态的流水线 。它抛弃了旧的 API 模型,采用请求驱动 的模式。应用发送一个
CaptureRequest(包含参数和输出 Surface),HAL 处理并返回CaptureResult(包含元数据和图像缓冲区)。 - 成像的本质 :光信号 -> 电信号 -> 数字信号 -> 图像处理 。这是一个从 Sensor (RAW) 经过 ISP (Image Signal Processor) 处理,最终输出 YUV/JPEG 的过程。
- 零拷贝的本质 :跨进程共享内存 。应用通过
Surface提供缓冲区(Buffer),Camera Service 将图像数据直接写入这些缓冲区,避免数据拷贝。
2. 相机架构全景图
2.1 从应用预览到 Sensor 曝光
#mermaid-svg-GtTMErfDuk1nVusb{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-GtTMErfDuk1nVusb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GtTMErfDuk1nVusb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GtTMErfDuk1nVusb .error-icon{fill:#552222;}#mermaid-svg-GtTMErfDuk1nVusb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GtTMErfDuk1nVusb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GtTMErfDuk1nVusb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GtTMErfDuk1nVusb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GtTMErfDuk1nVusb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GtTMErfDuk1nVusb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GtTMErfDuk1nVusb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GtTMErfDuk1nVusb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GtTMErfDuk1nVusb .marker.cross{stroke:#333333;}#mermaid-svg-GtTMErfDuk1nVusb svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GtTMErfDuk1nVusb p{margin:0;}#mermaid-svg-GtTMErfDuk1nVusb .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-GtTMErfDuk1nVusb .cluster-label text{fill:#333;}#mermaid-svg-GtTMErfDuk1nVusb .cluster-label span{color:#333;}#mermaid-svg-GtTMErfDuk1nVusb .cluster-label span p{background-color:transparent;}#mermaid-svg-GtTMErfDuk1nVusb .label text,#mermaid-svg-GtTMErfDuk1nVusb span{fill:#333;color:#333;}#mermaid-svg-GtTMErfDuk1nVusb .node rect,#mermaid-svg-GtTMErfDuk1nVusb .node circle,#mermaid-svg-GtTMErfDuk1nVusb .node ellipse,#mermaid-svg-GtTMErfDuk1nVusb .node polygon,#mermaid-svg-GtTMErfDuk1nVusb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GtTMErfDuk1nVusb .rough-node .label text,#mermaid-svg-GtTMErfDuk1nVusb .node .label text,#mermaid-svg-GtTMErfDuk1nVusb .image-shape .label,#mermaid-svg-GtTMErfDuk1nVusb .icon-shape .label{text-anchor:middle;}#mermaid-svg-GtTMErfDuk1nVusb .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-GtTMErfDuk1nVusb .rough-node .label,#mermaid-svg-GtTMErfDuk1nVusb .node .label,#mermaid-svg-GtTMErfDuk1nVusb .image-shape .label,#mermaid-svg-GtTMErfDuk1nVusb .icon-shape .label{text-align:center;}#mermaid-svg-GtTMErfDuk1nVusb .node.clickable{cursor:pointer;}#mermaid-svg-GtTMErfDuk1nVusb .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-GtTMErfDuk1nVusb .arrowheadPath{fill:#333333;}#mermaid-svg-GtTMErfDuk1nVusb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GtTMErfDuk1nVusb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GtTMErfDuk1nVusb .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GtTMErfDuk1nVusb .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-GtTMErfDuk1nVusb .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GtTMErfDuk1nVusb .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-GtTMErfDuk1nVusb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GtTMErfDuk1nVusb .cluster text{fill:#333;}#mermaid-svg-GtTMErfDuk1nVusb .cluster span{color:#333;}#mermaid-svg-GtTMErfDuk1nVusb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-GtTMErfDuk1nVusb .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-GtTMErfDuk1nVusb rect.text{fill:none;stroke-width:0;}#mermaid-svg-GtTMErfDuk1nVusb .icon-shape,#mermaid-svg-GtTMErfDuk1nVusb .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-GtTMErfDuk1nVusb .icon-shape p,#mermaid-svg-GtTMErfDuk1nVusb .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-GtTMErfDuk1nVusb .icon-shape .label rect,#mermaid-svg-GtTMErfDuk1nVusb .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-GtTMErfDuk1nVusb .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-GtTMErfDuk1nVusb .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-GtTMErfDuk1nVusb :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 硬件模组
Linux 内核
硬件抽象层
System Server
应用进程
- createCaptureSession()
- 配置 Stream
- submitCaptureRequest()
- processCaptureRequest()
- 配置寄存器
- 控制硬件
- 曝光/对焦
- 光子 -> 电子
- 图像处理 (Bayer -> YUV)
- 填充 Buffer
- onCaptureCompleted()
- 图像数据
- 图像数据
Camera2 API
Preview Surface (SurfaceView/TextureView)
Capture Surface (ImageReader)
CameraService
CameraDeviceClient
Camera HAL 3.x
ISP (图像信号处理)
V4L2 Driver
Sub-devices (Sensor/Lens/Flash)
CMOS Sensor
镜头
闪光灯
2.2 核心组件职责表
| 组件 | 层级 | 职责 | 学术定义 |
|---|---|---|---|
| CameraService | Framework | 仲裁者 | 管理相机设备,处理并发访问,分发请求。 |
| CameraDeviceClient | Framework | 会话管理者 | 代表一个应用打开的相机设备,管理 Capture Session。 |
| HAL3 (ICameraDevice) | HAL | 执行者 | 厂商实现的接口,接收 Request,返回 Result。 |
| RequestProcessor | HAL | 流水线调度 | 将 Request 分解为 ISP 可以执行的原子操作。 |
| Metadata | 通用 | 配置与反馈 | 键值对(Key-Value),用于配置参数(AE_MODE)和返回状态(SENSOR_EXPOSURE_TIME)。 |
3. HAL3 的请求-响应模型
3.1 CaptureRequest 的构成
应用发送的每一个请求都是一个完整的指令集。
| 组成部分 | 学术定义 | 示例 |
|---|---|---|
| Target Surfaces | 输出目标 | Preview Surface, Capture Surface, Analysis Surface。 |
| Parameters (Metadata) | 配置参数 | CONTROL_AF_MODE = CONTINUOUS_PICTURE, SENSOR_EXPOSURE_TIME = 10ms。 |
| Template | 预设模板 | TEMPLATE_PREVIEW, TEMPLATE_STILL_CAPTURE。 |
3.2 流水线处理(Pipeline)
HAL3 将图像处理视为一个流水线。
#mermaid-svg-5olo7D0FsbtT4IhP{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5olo7D0FsbtT4IhP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5olo7D0FsbtT4IhP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5olo7D0FsbtT4IhP .error-icon{fill:#552222;}#mermaid-svg-5olo7D0FsbtT4IhP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5olo7D0FsbtT4IhP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5olo7D0FsbtT4IhP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5olo7D0FsbtT4IhP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5olo7D0FsbtT4IhP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5olo7D0FsbtT4IhP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5olo7D0FsbtT4IhP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5olo7D0FsbtT4IhP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5olo7D0FsbtT4IhP .marker.cross{stroke:#333333;}#mermaid-svg-5olo7D0FsbtT4IhP svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5olo7D0FsbtT4IhP p{margin:0;}#mermaid-svg-5olo7D0FsbtT4IhP .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5olo7D0FsbtT4IhP .cluster-label text{fill:#333;}#mermaid-svg-5olo7D0FsbtT4IhP .cluster-label span{color:#333;}#mermaid-svg-5olo7D0FsbtT4IhP .cluster-label span p{background-color:transparent;}#mermaid-svg-5olo7D0FsbtT4IhP .label text,#mermaid-svg-5olo7D0FsbtT4IhP span{fill:#333;color:#333;}#mermaid-svg-5olo7D0FsbtT4IhP .node rect,#mermaid-svg-5olo7D0FsbtT4IhP .node circle,#mermaid-svg-5olo7D0FsbtT4IhP .node ellipse,#mermaid-svg-5olo7D0FsbtT4IhP .node polygon,#mermaid-svg-5olo7D0FsbtT4IhP .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5olo7D0FsbtT4IhP .rough-node .label text,#mermaid-svg-5olo7D0FsbtT4IhP .node .label text,#mermaid-svg-5olo7D0FsbtT4IhP .image-shape .label,#mermaid-svg-5olo7D0FsbtT4IhP .icon-shape .label{text-anchor:middle;}#mermaid-svg-5olo7D0FsbtT4IhP .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5olo7D0FsbtT4IhP .rough-node .label,#mermaid-svg-5olo7D0FsbtT4IhP .node .label,#mermaid-svg-5olo7D0FsbtT4IhP .image-shape .label,#mermaid-svg-5olo7D0FsbtT4IhP .icon-shape .label{text-align:center;}#mermaid-svg-5olo7D0FsbtT4IhP .node.clickable{cursor:pointer;}#mermaid-svg-5olo7D0FsbtT4IhP .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5olo7D0FsbtT4IhP .arrowheadPath{fill:#333333;}#mermaid-svg-5olo7D0FsbtT4IhP .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5olo7D0FsbtT4IhP .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5olo7D0FsbtT4IhP .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5olo7D0FsbtT4IhP .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5olo7D0FsbtT4IhP .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5olo7D0FsbtT4IhP .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5olo7D0FsbtT4IhP .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5olo7D0FsbtT4IhP .cluster text{fill:#333;}#mermaid-svg-5olo7D0FsbtT4IhP .cluster span{color:#333;}#mermaid-svg-5olo7D0FsbtT4IhP div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5olo7D0FsbtT4IhP .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5olo7D0FsbtT4IhP rect.text{fill:none;stroke-width:0;}#mermaid-svg-5olo7D0FsbtT4IhP .icon-shape,#mermaid-svg-5olo7D0FsbtT4IhP .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5olo7D0FsbtT4IhP .icon-shape p,#mermaid-svg-5olo7D0FsbtT4IhP .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5olo7D0FsbtT4IhP .icon-shape .label rect,#mermaid-svg-5olo7D0FsbtT4IhP .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5olo7D0FsbtT4IhP .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5olo7D0FsbtT4IhP .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5olo7D0FsbtT4IhP :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 成像流水线
Sensor 输出 (RAW Bayer)
黑电平校正 (BLC)
镜头阴影校正 (LSC)
去马赛克 (Demosaic)
噪声抑制 (NR)
边缘增强 (Sharpening)
色彩校正 (CCM)
伽马校正 (Gamma)
输出 (YUV/JPEG)
学术定义:
- Bayer Pattern: 传感器输出的原始格式(RGGB, BGGR 等)。
- Demosaic: 将单通道的 Bayer 数据插值成三通道的 RGB 数据。
- 3A Algorithms: 自动对焦(AF)、自动曝光(AE)、自动白平衡(AWB)算法在流水线中实时调整参数。
3.3 请求与结果的异步性
HAL3 是完全异步的。
时序:
- App 发送 Request 1。
- App 发送 Request 2。
- HAL 处理 Request 1,返回 Result 1。
- HAL 处理 Request 2,返回 Result 2。
关键 :Result 的顺序不一定与 Request 的顺序一致(虽然通常一致),系统通过 frameNumber 来关联。
4. Camera Service 的调度机制
4.1 设备状态管理
CameraService 维护着物理相机的状态机。
#mermaid-svg-eVkMlnLlucAA5tkh{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-eVkMlnLlucAA5tkh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eVkMlnLlucAA5tkh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eVkMlnLlucAA5tkh .error-icon{fill:#552222;}#mermaid-svg-eVkMlnLlucAA5tkh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eVkMlnLlucAA5tkh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eVkMlnLlucAA5tkh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eVkMlnLlucAA5tkh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eVkMlnLlucAA5tkh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eVkMlnLlucAA5tkh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eVkMlnLlucAA5tkh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eVkMlnLlucAA5tkh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eVkMlnLlucAA5tkh .marker.cross{stroke:#333333;}#mermaid-svg-eVkMlnLlucAA5tkh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eVkMlnLlucAA5tkh p{margin:0;}#mermaid-svg-eVkMlnLlucAA5tkh defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-eVkMlnLlucAA5tkh g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-eVkMlnLlucAA5tkh g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-eVkMlnLlucAA5tkh g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-eVkMlnLlucAA5tkh g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-eVkMlnLlucAA5tkh g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-eVkMlnLlucAA5tkh .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-eVkMlnLlucAA5tkh .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-eVkMlnLlucAA5tkh .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-eVkMlnLlucAA5tkh .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-eVkMlnLlucAA5tkh .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-eVkMlnLlucAA5tkh .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-eVkMlnLlucAA5tkh .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-eVkMlnLlucAA5tkh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eVkMlnLlucAA5tkh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-eVkMlnLlucAA5tkh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eVkMlnLlucAA5tkh .edgeLabel .label text{fill:#333;}#mermaid-svg-eVkMlnLlucAA5tkh .label div .edgeLabel{color:#333;}#mermaid-svg-eVkMlnLlucAA5tkh .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-eVkMlnLlucAA5tkh .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-eVkMlnLlucAA5tkh .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-eVkMlnLlucAA5tkh .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-eVkMlnLlucAA5tkh .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-eVkMlnLlucAA5tkh .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eVkMlnLlucAA5tkh .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eVkMlnLlucAA5tkh #statediagram-barbEnd{fill:#333333;}#mermaid-svg-eVkMlnLlucAA5tkh .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eVkMlnLlucAA5tkh .cluster-label,#mermaid-svg-eVkMlnLlucAA5tkh .nodeLabel{color:#131300;}#mermaid-svg-eVkMlnLlucAA5tkh .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-eVkMlnLlucAA5tkh .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-eVkMlnLlucAA5tkh .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-eVkMlnLlucAA5tkh .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-eVkMlnLlucAA5tkh .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-eVkMlnLlucAA5tkh .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-eVkMlnLlucAA5tkh .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-eVkMlnLlucAA5tkh .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-eVkMlnLlucAA5tkh .note-edge{stroke-dasharray:5;}#mermaid-svg-eVkMlnLlucAA5tkh .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-eVkMlnLlucAA5tkh .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-eVkMlnLlucAA5tkh .statediagram-note text{fill:black;}#mermaid-svg-eVkMlnLlucAA5tkh .statediagram-note .nodeLabel{color:black;}#mermaid-svg-eVkMlnLlucAA5tkh .statediagram .edgeLabel{color:red;}#mermaid-svg-eVkMlnLlucAA5tkh #dependencyStart,#mermaid-svg-eVkMlnLlucAA5tkh #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-eVkMlnLlucAA5tkh .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eVkMlnLlucAA5tkh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 设备未打开
openCamera()
configureStreams()
setRepeatingRequest()
stopRepeating()
重新配置
close()
Closed
Opened
Configured
Active
Idle
4.2 并发访问控制
Android 支持多应用同时访问相机吗?不支持。
学术定义:
- 独占访问:CameraService 保证同一时间只有一个进程能打开相机设备。
- 高优先级抢占 :如果后台应用正在使用相机,前台应用请求打开,CameraService 会强制关闭后台应用(发送
onDisconnected回调)。
5. 图像缓冲区管理(Buffer Management)
5.1 Surface 与 BufferQueue
应用通过 Surface 向 Camera Service 提供缓冲区。
| Surface 类型 | 用途 | 缓冲区数量 |
|---|---|---|
| SurfaceView | 预览显示 | 3 个 (Triple Buffering) |
| ImageReader | 拍照/分析 | 1-5 个 (取决于 Max Images) |
| MediaCodec | 视频录制 | 2-3 个 |
5.2 零拷贝流程
- App 创建
Surface,背后是一个BufferQueue。 - App 调用
createCaptureSession,CameraService 获取BufferQueue的句柄。 - App 发送
CaptureRequest,指定 Target 为上述Surface。 - HAL 处理完图像,直接将数据写入
BufferQueue中的一个空闲 Buffer。 - App 从
Surface中获取 Buffer,无需拷贝。
6. 3A 算法的控制闭环
6.1 AE(自动曝光)闭环
AE 是一个动态调整的过程。
#mermaid-svg-7kCuZGCQM3P1scth{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7kCuZGCQM3P1scth .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7kCuZGCQM3P1scth .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7kCuZGCQM3P1scth .error-icon{fill:#552222;}#mermaid-svg-7kCuZGCQM3P1scth .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7kCuZGCQM3P1scth .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7kCuZGCQM3P1scth .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7kCuZGCQM3P1scth .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7kCuZGCQM3P1scth .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7kCuZGCQM3P1scth .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7kCuZGCQM3P1scth .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7kCuZGCQM3P1scth .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7kCuZGCQM3P1scth .marker.cross{stroke:#333333;}#mermaid-svg-7kCuZGCQM3P1scth svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7kCuZGCQM3P1scth p{margin:0;}#mermaid-svg-7kCuZGCQM3P1scth .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7kCuZGCQM3P1scth .cluster-label text{fill:#333;}#mermaid-svg-7kCuZGCQM3P1scth .cluster-label span{color:#333;}#mermaid-svg-7kCuZGCQM3P1scth .cluster-label span p{background-color:transparent;}#mermaid-svg-7kCuZGCQM3P1scth .label text,#mermaid-svg-7kCuZGCQM3P1scth span{fill:#333;color:#333;}#mermaid-svg-7kCuZGCQM3P1scth .node rect,#mermaid-svg-7kCuZGCQM3P1scth .node circle,#mermaid-svg-7kCuZGCQM3P1scth .node ellipse,#mermaid-svg-7kCuZGCQM3P1scth .node polygon,#mermaid-svg-7kCuZGCQM3P1scth .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7kCuZGCQM3P1scth .rough-node .label text,#mermaid-svg-7kCuZGCQM3P1scth .node .label text,#mermaid-svg-7kCuZGCQM3P1scth .image-shape .label,#mermaid-svg-7kCuZGCQM3P1scth .icon-shape .label{text-anchor:middle;}#mermaid-svg-7kCuZGCQM3P1scth .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7kCuZGCQM3P1scth .rough-node .label,#mermaid-svg-7kCuZGCQM3P1scth .node .label,#mermaid-svg-7kCuZGCQM3P1scth .image-shape .label,#mermaid-svg-7kCuZGCQM3P1scth .icon-shape .label{text-align:center;}#mermaid-svg-7kCuZGCQM3P1scth .node.clickable{cursor:pointer;}#mermaid-svg-7kCuZGCQM3P1scth .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7kCuZGCQM3P1scth .arrowheadPath{fill:#333333;}#mermaid-svg-7kCuZGCQM3P1scth .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7kCuZGCQM3P1scth .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7kCuZGCQM3P1scth .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7kCuZGCQM3P1scth .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7kCuZGCQM3P1scth .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7kCuZGCQM3P1scth .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7kCuZGCQM3P1scth .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7kCuZGCQM3P1scth .cluster text{fill:#333;}#mermaid-svg-7kCuZGCQM3P1scth .cluster span{color:#333;}#mermaid-svg-7kCuZGCQM3P1scth div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7kCuZGCQM3P1scth .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7kCuZGCQM3P1scth rect.text{fill:none;stroke-width:0;}#mermaid-svg-7kCuZGCQM3P1scth .icon-shape,#mermaid-svg-7kCuZGCQM3P1scth .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7kCuZGCQM3P1scth .icon-shape p,#mermaid-svg-7kCuZGCQM3P1scth .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7kCuZGCQM3P1scth .icon-shape .label rect,#mermaid-svg-7kCuZGCQM3P1scth .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7kCuZGCQM3P1scth .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7kCuZGCQM3P1scth .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7kCuZGCQM3P1scth :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 调整
Request: 设定曝光参数
Sensor 曝光
ISP 处理
输出图像
统计亮度值
计算误差
学术定义:
- Exposure Value (EV): 由光圈、快门、ISO 共同决定。
- Metering Region: 测光区域(如中心权重、平均测光)。
6.2 AF(自动对焦)状态机
#mermaid-svg-rTSEi3XKAd1b2O4n{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rTSEi3XKAd1b2O4n .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rTSEi3XKAd1b2O4n .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rTSEi3XKAd1b2O4n .error-icon{fill:#552222;}#mermaid-svg-rTSEi3XKAd1b2O4n .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rTSEi3XKAd1b2O4n .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rTSEi3XKAd1b2O4n .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rTSEi3XKAd1b2O4n .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rTSEi3XKAd1b2O4n .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rTSEi3XKAd1b2O4n .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rTSEi3XKAd1b2O4n .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rTSEi3XKAd1b2O4n .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rTSEi3XKAd1b2O4n .marker.cross{stroke:#333333;}#mermaid-svg-rTSEi3XKAd1b2O4n svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rTSEi3XKAd1b2O4n p{margin:0;}#mermaid-svg-rTSEi3XKAd1b2O4n defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-rTSEi3XKAd1b2O4n g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-rTSEi3XKAd1b2O4n g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-rTSEi3XKAd1b2O4n g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-rTSEi3XKAd1b2O4n g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-rTSEi3XKAd1b2O4n g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-rTSEi3XKAd1b2O4n .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-rTSEi3XKAd1b2O4n .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-rTSEi3XKAd1b2O4n .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-rTSEi3XKAd1b2O4n .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-rTSEi3XKAd1b2O4n .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-rTSEi3XKAd1b2O4n .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-rTSEi3XKAd1b2O4n .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-rTSEi3XKAd1b2O4n .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rTSEi3XKAd1b2O4n .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rTSEi3XKAd1b2O4n .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rTSEi3XKAd1b2O4n .edgeLabel .label text{fill:#333;}#mermaid-svg-rTSEi3XKAd1b2O4n .label div .edgeLabel{color:#333;}#mermaid-svg-rTSEi3XKAd1b2O4n .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-rTSEi3XKAd1b2O4n .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-rTSEi3XKAd1b2O4n .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-rTSEi3XKAd1b2O4n .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-rTSEi3XKAd1b2O4n .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-rTSEi3XKAd1b2O4n .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rTSEi3XKAd1b2O4n .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rTSEi3XKAd1b2O4n #statediagram-barbEnd{fill:#333333;}#mermaid-svg-rTSEi3XKAd1b2O4n .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rTSEi3XKAd1b2O4n .cluster-label,#mermaid-svg-rTSEi3XKAd1b2O4n .nodeLabel{color:#131300;}#mermaid-svg-rTSEi3XKAd1b2O4n .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-rTSEi3XKAd1b2O4n .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-rTSEi3XKAd1b2O4n .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-rTSEi3XKAd1b2O4n .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-rTSEi3XKAd1b2O4n .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-rTSEi3XKAd1b2O4n .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-rTSEi3XKAd1b2O4n .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-rTSEi3XKAd1b2O4n .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-rTSEi3XKAd1b2O4n .note-edge{stroke-dasharray:5;}#mermaid-svg-rTSEi3XKAd1b2O4n .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-rTSEi3XKAd1b2O4n .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-rTSEi3XKAd1b2O4n .statediagram-note text{fill:black;}#mermaid-svg-rTSEi3XKAd1b2O4n .statediagram-note .nodeLabel{color:black;}#mermaid-svg-rTSEi3XKAd1b2O4n .statediagram .edgeLabel{color:red;}#mermaid-svg-rTSEi3XKAd1b2O4n #dependencyStart,#mermaid-svg-rTSEi3XKAd1b2O4n #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-rTSEi3XKAd1b2O4n .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rTSEi3XKAd1b2O4n :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 未激活
被动扫描 (预览中)
主动扫描 (点击对焦)
合焦成功
合焦失败
锁定焦点
取消锁定
Inactive
PassiveScan
ActiveScan
Focused
Locked
7. 关键源码深度解析
7.1 CameraService 的请求分发
cpp
// frameworks/av/services/camera/libcameraservice/CameraDeviceClient.cpp
status_t CameraDeviceClient::submitRequest(...) {
// 1. 检查请求合法性
if (!isRequestValid(request)) {
return BAD_VALUE;
}
// 2. 将 Framework 请求转换为 HAL 请求
halRequest = convertToHalRequest(request);
// 3. 调用 HAL 接口
mHalDevice->processCaptureRequest(halRequest);
// 4. 更新帧号
mFrameNumber++;
}
7.2 HAL3 的返回结果
cpp
// hardware/interfaces/camera/device/3.2/default/CameraDeviceSession.cpp
void CameraDeviceSession::processCaptureResult(...) {
// 1. 填充元数据
result.metadata = mLatestMetadata;
// 2. 填充图像缓冲区
result.outputBuffers[0].buffer = mFilledBuffer;
// 3. 通过回调返回给 Framework
mCallback->processCaptureResult(result);
}
8. 相机系统的常见误区
| 误区 | 学术解释 |
|---|---|
| 分辨率越高,画质越好 | 不一定。高分辨率可能牺牲帧率和进光量,导致噪点增加。 |
| 数码变焦是放大像素 | 是的。数码变焦只是裁剪图像中心区域并插值放大,会损失细节。 |
| 夜景模式是全靠算法 | 不全是。夜景模式需要长曝光(降低 ISO)或多帧合成(提高信噪比)。 |
| 前置摄像头比后置差 | 通常是。物理上,前置摄像头的 Sensor 尺寸、光圈、镜片素质通常低于后置。 |
9. 本篇总结(Knowledge Closure)
| 关键点 | 纯学术定义 |
|---|---|
| Camera Service 的本质 | 相机资源的仲裁者与调度器,管理设备生命周期。 |
| HAL3 的本质 | 无状态的请求-响应流水线,基于 Metadata 配置。 |
| 成像流水线 | 从 RAW Bayer 经过 ISP 处理(BLC, Demosaic, NR, CCM)到 YUV。 |
| 3A 算法 | 自动对焦、曝光、白平衡的实时闭环控制系统。 |
| 零拷贝机制 | 通过 Surface/BufferQueue 实现跨进程共享内存,避免数据搬运。 |
10. 第九板块结语
至此,第九板块:Android 多媒体体系 已全部完结。
我们从 AudioFlinger 的音频合成 出发,深入 AudioPolicyService 的策略仲裁 ,探索 Camera Service 的请求流水线 ,最终抵达 HAL3 的成像处理。
我们揭示了 Android 多媒体系统的核心逻辑:用流水线处理高带宽数据,用策略隔离应用,用共享内存消除拷贝。
下一篇预告 :第十板块:Android 系统稳定性与调试 | 第二十五篇:Watchdog 与 ANR 的系统级监控