Camera Service核心:启动、架构与Client管理

Camera Service,说白了就是整个相机框架的“大管家”。

我刚开始接触Android相机时,总觉得它就是个黑盒子——上层调个openCamera,底层就自动干活了。后来啃了半年源码才发现,CameraService才是真正承上启下的关键节点。今天咱们就把它拆开看看。

一、CameraService的启动流程

CameraService是在系统启动时,由init进程拉起来的。它注册为系统服务,等待客户端来调用。

具体启动路径是这样的:

  1. init进程解析init.rc,启动cameraserver进程
  2. cameraserver的main函数里,实例化CameraService
  3. 调用CameraService::instantiate(),注册到ServiceManager
  4. ServiceManager将其加入服务列表,供其他进程查询

嗯,这里要注意:CameraService是跑在独立的cameraserver进程里的,不是system_server。为什么这么设计?

我个人理解,是为了隔离。相机处理涉及大量内存和硬件操作,万一崩了不能拖垮整个系统。我在项目中就遇到过相机进程OOM,但系统其他功能完全不受影响——这就是独立进程的好处。

核心要点:CameraService的启动是系统级服务注册,它通过Binder与上层通信,通过HAL与底层硬件交互。

二、CameraService的架构设计

CameraService的架构,我习惯把它分成三层:

层级组件职责
接口层ICameraService定义Binder接口,供APP调用
核心层CameraService管理Client、处理权限、协调资源
设备层CameraDevice/Camera3Device封装HAL调用,管理流和请求

你想想看,上层APP调用connect()时,实际上走的是Binder跨进程调用。CameraService收到请求后,会做几件事:

  • 检查调用方权限(有没有CAMERA权限)
  • 检查设备是否可用(有没有被其他进程占用)
  • 创建CameraClient实例
  • 返回Binder代理给APP

我记得有一次排查问题,发现某个第三方应用一直拿不到相机。查了半天,原来是它没在manifest里声明CAMERA权限。CameraService在权限校验这步就直接拒绝了,连HAL都没碰——这种设计很合理,避免无效的硬件操作。

避坑指南:我曾经在调试多摄像头时,发现CameraService内部维护了一个mCameraMap,key是摄像头ID,value是Client实例。如果某个摄像头被占用了,其他进程再打开就会返回-EBUSY。所以上层一定要做好异常处理。

三、CameraClient管理

CameraClient是CameraService与上层APP之间的桥梁。每个打开的摄像头,都对应一个CameraClient实例。

Client的生命周期是这样的:

  1. 创建:APP调用connect(),CameraService创建CameraClient
  2. 初始化:Client内部创建CameraDevice,打开HAL
  3. 运行:处理上层发来的请求(拍照、预览等)
  4. 销毁:APP调用disconnect(),或者进程死亡,Client被清理

这里有个关键点:CameraService怎么管理多个Client?

说白了,就是用一个map来存。CameraService内部维护了:

// 伪代码,展示核心逻辑
sp<CameraClient> mClient;
status_t CameraService::connect(...) {
    // 检查是否已有Client
    if (mClient != nullptr) {
        // 如果是同一个APP,可以重新连接
        // 如果是不同APP,返回错误
        return -EBUSY;
    }
    // 创建新Client
    mClient = new CameraClient(this, cameraId, ...);
    return OK;
}

嗯,这里要注意:Android 9之后引入了并发相机(concurrent camera)的支持。多个APP可以同时打开不同的摄像头。但同一个摄像头,同一时刻只能被一个APP使用。这个限制是硬件层面的,CameraService只是做了调度。

重要提醒:Client销毁时,一定要释放HAL资源。我曾经遇到一个bug,APP闪退后Client没有正确清理,导致下次打开相机时HAL还处于占用状态。后来在CameraService的binderDied()回调里加了强制清理逻辑才解决。

四、Client与HAL的交互

CameraClient不直接操作硬件,它通过CameraDevice来调用HAL。这个设计很巧妙——Client只关心业务逻辑,设备管理交给下层。

交互流程大致是:

  • APP下发拍照请求 → CameraClient处理 → CameraDevice封装 → HAL执行
  • HAL返回数据 → CameraDevice解析 → CameraClient回调 → APP收到结果

我个人习惯把CameraClient看作一个“状态机”。它有这些状态:

状态含义常见操作
INITIAL刚创建,未打开设备initialize()
ACTIVE设备已打开,可以处理请求startPreview(), takePicture()
STOPPED停止流,但设备未关闭stopPreview()
DESTROYED已断开,等待回收disconnect()

你想想看,如果APP在ACTIVE状态下突然调用disconnect(),Client会先停止所有流,再关闭设备,最后把自己从CameraService的map里移除。这个顺序不能乱,否则容易出问题。

总结一下:CameraService是相机框架的中枢神经。它负责启动、注册、权限校验、Client管理。而CameraClient是每个相机会话的代言人,管理着从打开到关闭的完整生命周期。理解了这两层,你就掌握了Android相机框架的核心脉络。

下一章我们会深入CameraDevice和HAL的交互细节,看看底层到底是怎么处理每一帧数据的。到时候再聊。