相机系统(CameraService):Camera HAL3架构、Camera启动与预览流程、拍照与视频录制、Camera权限与安全

相机系统,说实话,是Android Framework里最复杂的一块之一。我早年刚接触Camera HAL3时,也被它的Pipeline设计绕得晕头转向。但一旦你理解了它的设计哲学,你会发现它其实非常优雅——它把控制权完全交给了上层,让App能精细控制每一帧的捕获参数。

Camera HAL3架构:从“黑盒”到“管道”

在HAL3之前,HAL1是个典型的黑盒。App调用open、startPreview、takePicture,底层驱动怎么干活,上层完全不知道。HAL3不一样,它把相机抽象成一条捕获管道(Capture Pipeline)

说白了,HAL3的核心就三个概念:CameraDeviceCaptureRequestCaptureResult

  • CameraDevice:代表物理相机设备。每个摄像头对应一个Device。
  • CaptureRequest:你告诉相机“我想要什么”。包含输出目标(Surface)、控制参数(AE、AF、AWB等)。
  • CaptureResult:相机告诉你“我拍到了什么”。包含实际使用的参数、时间戳、元数据。

我习惯把HAL3比作一个“可编程的流水线”。你可以往流水线上放不同的Request,每个Request可以指定不同的输出Surface。比如一个Request同时输出到预览Surface和拍照Surface,这就是“同帧输出”。

关键点:HAL3的Pipeline是异步的。你提交一个Request,不会阻塞等待结果。结果通过回调返回。这种设计让高帧率、低延迟成为可能。

下面这张图展示了HAL3的核心数据流:

Camera HAL3 核心数据流 App / Camera2 API CameraService Camera HAL3 Camera Driver / Sensor openCamera() configureStreams() processCaptureRequest() CaptureResult 回调 notify() 事件

Camera启动与预览流程:从App到Sensor的旅程

你按下App里的“打开相机”按钮,背后发生了什么?我拆解一下这个流程,你会发现每一步都有讲究。

  1. App调用CameraManager.openCamera():这其实是个异步调用。CameraService收到请求后,会去HAL层打开设备。
  2. CameraService创建CameraDevice:内部会初始化一个CameraDeviceClient,负责与App通信。
  3. App创建CaptureSession:通过createCaptureSession(),把预览Surface传进去。CameraService会调用HAL的configureStreams(),告诉底层“我要往这些Surface上送数据”。
  4. App提交重复Request:setRepeatingRequest(),告诉HAL“持续往预览Surface送帧”。
  5. HAL开始送帧:底层驱动每拿到一帧数据,就通过HAL回调往上送,最终到达SurfaceView或TextureView。

我的经验:预览启动慢,很多时候卡在configureStreams()这一步。尤其是当你同时配置了多个输出Surface(比如预览+拍照+视频),HAL需要重新协商Stream配置。我建议尽量复用Stream配置,不要每次拍照都重新创建Session。

这里有个细节:预览Surface必须是ANativeWindow。App端传过来的Surface,最终会映射到BufferQueue的生产者端。HAL作为消费者,从BufferQueue里拿Buffer填充数据。

拍照与视频录制:单帧与连续帧的博弈

拍照和视频录制,本质区别在于:拍照是单次CaptureRequest,视频是连续的CaptureRequest

拍照流程

  • App构造一个CaptureRequest,设置TEMPLATE_STILL_CAPTURE模板。
  • 调用capture()提交这个Request。注意,这不会中断预览的RepeatingRequest。
  • HAL处理完这个Request后,通过CaptureResult回调返回JPEG数据或YUV数据。
  • App拿到数据后,可以保存到文件或进一步处理。

视频录制流程

  • App需要创建一个MediaCodec或MediaRecorder的Surface,作为输出目标。
  • 在createCaptureSession时,把这个Surface加进去。
  • 提交RepeatingRequest,让HAL持续往这个Surface送帧。
  • MediaCodec/MediaRecorder从Surface读取数据,编码成视频流。

注意:我曾经遇到过一个坑——视频录制时预览卡顿。原因是预览Surface和录制Surface的Buffer格式不匹配。预览通常用RGBA_8888,录制用YUV_420_888。HAL需要做格式转换,如果硬件不支持,就会走软件转换,性能直接崩掉。解决办法是尽量让两个Surface使用相同的Buffer格式,或者确认硬件支持直接输出多种格式。

说到拍照,还有一个重要概念:ZSL(Zero Shutter Lag,零快门延迟)。ZSL的原理是:预览时HAL一直在内部环形缓冲区里缓存最近几帧。用户按下快门时,直接从缓冲区里取一帧,而不是重新捕获。这样快门延迟几乎为零。

但ZSL也有代价——它需要额外的内存和带宽。低端设备上,我建议关闭ZSL,否则拍照时预览帧率会掉得很厉害。

Camera权限与安全:别让相机成为后门

相机权限,不只是AndroidManifest里加个android.permission.CAMERA那么简单。从Android 6.0开始,权限变成了运行时权限。从Android 10开始,还有隐私保护的加强。

我整理了一下相机相关的权限体系:

权限 级别 说明
android.permission.CAMERA 危险权限 必须运行时申请。没有这个权限,CameraManager.openCamera()会抛SecurityException。
android.permission.RECORD_AUDIO 危险权限 录制视频时如果需要录音,必须申请。
android.permission.ACCESS_FINE_LOCATION 危险权限 如果App需要读取照片的EXIF地理位置信息,需要申请。
android.permission.CAPTURE_VIDEO_OUTPUT 系统权限 只有系统App才能用。用于截屏或录屏。

安全方面,Android Framework做了几层保护:

  • 进程隔离:CameraService运行在独立的mediaserver进程。App不能直接访问HAL,必须通过Binder IPC。
  • 权限检查:CameraService在openCamera()时会检查调用方的PID/UID是否有CAMERA权限。
  • Surface验证:App传过来的Surface,CameraService会验证它是否属于当前App的进程。防止恶意App通过传别人的Surface来偷数据。
  • 隐私指示灯:Android 12+要求,相机打开时必须有明显的指示(比如状态栏图标或LED灯)。

避坑指南:我曾经遇到一个Case——App在后台偷偷打开相机被系统杀掉。原因是Android 11引入了后台相机限制。除非App有android.permission.CAMERA且用户在前台可见,否则CameraService会拒绝打开相机。如果你的App需要在后台使用相机(比如视频通话的悬浮窗),必须使用MediaProjectionForeground Service

还有一个容易被忽略的点:相机元数据泄露。CaptureResult里包含了很多传感器信息,比如焦距、光圈、曝光时间。恶意App可以通过这些信息推断用户的环境。所以Google在Android 10+中,对非系统App隐藏了部分元数据字段。如果你在开发系统App,记得在android.hardware.camera2.params.SessionConfiguration里设置setSessionParameter来获取完整数据。

嗯,相机系统这块内容确实不少。但只要你把HAL3的Pipeline模型吃透,剩下的都是围绕这个模型展开的细节。我个人建议,初学者可以先从Camera2Basic这个官方Sample入手,跑通一遍预览+拍照+视频的流程,然后再去深究HAL层的实现。

记住一句话:相机系统,本质上就是“提交Request,拿到Result”的循环。理解了这个循环,你就掌握了Camera Framework的钥匙。


公众号:蓝海资料掘金营,微信deep3321