8、Android Camera Framework层:CameraService启动与架构

各位同学,今天我们来啃一块硬骨头——Camera Framework层。说实话,这部分内容我第一次接触时也头大,代码调用链长得像蜘蛛网。但别怕,我带你一层层剥开它。

Framework层说白了就是连接App和HAL的桥梁。你想想看,App调用一个openCamera,中间要经过多少环节?我数过,至少七八个关键节点。今天我们就从CameraService的启动开始讲起。

8.1 CameraService启动流程

CameraService是系统服务,它在Android启动时由SystemServer拉起。我习惯把它的启动分成三个阶段:

  1. 注册服务:向ServiceManager注册CameraService
  2. 初始化Provider:加载CameraProviderManager
  3. 等待客户端:监听来自App的请求

代码层面,启动入口在frameworks/av/services/camera/libcameraservice/CameraService.cpp。核心函数是onFirstRef()

void CameraService::onFirstRef() {
    ALOGI("CameraService started");
    
    // 1. 初始化CameraProviderManager
    mCameraProviderManager = new CameraProviderManager();
    mCameraProviderManager->initialize(this);
    
    // 2. 枚举所有Camera设备
    status_t res = enumerateProviders();
    if (res != OK) {
        ALOGE("Failed to enumerate providers");
    }
    
    // 3. 注册服务
    publish();
}

这里有个坑,我曾经遇到过:如果HAL层某个Provider初始化超时,整个CameraService启动就会卡住。嗯,后来我们在项目中加了超时保护,才解决这个问题。

8.2 CameraProviderManager架构

CameraProviderManager是CameraService的"眼睛",它负责发现和管理所有Camera HAL Provider。说白了,它就是个中介,帮CameraService找到可用的Camera设备。

它的核心职责有三点:

  • 发现Provider:通过HIDL服务发现所有Camera HAL实现
  • 管理设备:维护每个Camera设备的生命周期
  • 权限控制:检查App是否有权限访问Camera

关键点:CameraProviderManager内部维护了一个mProviders列表,每个Provider对应一个HAL实现。比如高通平台可能有QtiCameraProvider,MTK平台有MtkCameraProvider

我建议你重点关注CameraProviderManager::initialize()这个函数,它里面调用了HIDL的ICameraProvider::getCameraIdList()来获取设备列表。这个调用是跨进程的,所以会有一定的延迟。

8.3 CameraDeviceClient与CameraDeviceImpl

当App通过CameraManager打开一个Camera设备时,Framework会创建两个关键对象:

对象 所在进程 职责
CameraDeviceClient CameraService进程 作为服务端,处理来自App的请求
CameraDeviceImpl App进程 作为客户端,封装对Camera的操作

这两个对象通过Binder通信。我记得有一次调试时,发现App发送的CaptureRequest总是丢失,查了半天才发现是Binder缓冲区满了。后来我们调整了Binder线程池大小才解决。

来看一下CameraDeviceClient的创建流程:

// CameraService中
sp<CameraDeviceClient> client = new CameraDeviceClient(
    this,           // CameraService
    cameraId,       // 设备ID
    clientPackage,  // App包名
    clientUid,      // App UID
    remoteCallback  // App的回调接口
);

// 初始化
status_t err = client->initialize(mCameraProviderManager);
if (err != OK) {
    // 处理错误
}

避坑指南:我曾经遇到一个案例,App在onResume中频繁打开关闭Camera,导致CameraDeviceClient创建失败。原因是上一个client还没完全销毁。解决方案是在关闭Camera时加入同步等待。

8.4 CaptureRequest与CaptureResult的Framework流转

这是Camera Framework最核心的数据流。我画了一张图,帮你理解整个流转过程:

CaptureRequest/CaptureResult Framework流转图 App (Camera2 API) CameraManager/CaptureSession CameraService CameraDeviceClient Camera HAL CameraDevice@3.x CaptureRequest CaptureRequest CaptureResult CaptureResult 流转步骤 1. App创建CaptureRequest CameraManager.createCaptureRequest() 2. 通过Binder发送到CameraService CameraDeviceImpl.submitCaptureRequest() 3. CameraService转发到HAL CameraDeviceClient.processCaptureRequest() 4. HAL处理并返回CaptureResult processCaptureRequest()回调 5. CameraService回调给App CameraDeviceImpl.onCaptureResult() 6. App在CaptureCallback中收到结果 onCaptureCompleted()

你看这个图,Request是向下流的,Result是向上流的。我刚开始做Camera开发时,总搞混这两个方向。后来记住一句话:"请求往下走,结果往上走",再也没错过。

8.5 Camera2 API详解

Camera2 API是Android 5.0引入的,相比Camera1,它更灵活但也更复杂。核心有三个类:

  • CameraManager:管理Camera设备,负责枚举和打开
  • CameraDevice:代表一个Camera设备,负责创建CaptureSession
  • CaptureSession:管理拍照会话,负责提交CaptureRequest

典型的调用流程是这样的:

// 1. 获取CameraManager
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);

// 2. 打开Camera设备
manager.openCamera(cameraId, new CameraDevice.StateCallback() {
    @Override
    public void onOpened(CameraDevice device) {
        // 3. 创建CaptureSession
        device.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
            @Override
            public void onConfigured(CameraCaptureSession session) {
                // 4. 创建CaptureRequest
                CaptureRequest request = device.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                request.addTarget(surface);
                
                // 5. 提交请求
                session.setRepeatingRequest(request, new CameraCaptureSession.CaptureCallback() {
                    @Override
                    public void onCaptureCompleted(CaptureRequest request, TotalCaptureResult result) {
                        // 6. 处理结果
                    }
                }, backgroundHandler);
            }
        }, backgroundHandler);
    }
}, backgroundHandler);

注意:Camera2 API的所有回调都在Binder线程中执行。如果你在回调中做耗时操作,会阻塞整个CameraService。我建议你使用独立的HandlerThread来处理回调。

8.6 Framework与HAL的Binder通信机制

Framework和HAL之间的通信,在Android 8.0之后主要走HIDL。说白了,HIDL就是Android为硬件抽象层设计的Binder通信协议。

通信链路是这样的:

  1. App通过Binder调用CameraService
  2. CameraService通过HIDL调用Camera HAL
  3. HAL处理完后,通过HIDL回调返回结果
  4. CameraService再通过Binder回调给App

这里有个性能问题,我实际项目中遇到过:每次拍照都要经过两次Binder调用,延迟大概在5-10ms。对于高速连拍场景,这个延迟不可接受。解决方案是使用HIDL的passthrough模式,让CameraService直接加载HAL的so库,减少一次跨进程通信。

来看一下HIDL接口的定义:

// ICameraDevice.hal
interface ICameraDevice {
    // 提交CaptureRequest
    submitRequest(CaptureRequest request) 
        generates (Status status, int64_t frameNumber);
    
    // 取消请求
    cancelRequest(int64_t frameNumber) 
        generates (Status status);
    
    // 关闭设备
    close() generates (Status status);
};

嗯,这里要注意,HIDL接口的返回值是异步的。你调用submitRequest后,HAL会通过回调函数返回CaptureResult。这个回调也是通过Binder传递的,所以同样有线程安全问题。

我的经验:调试Binder通信问题时,可以用adb shell dumpsys binder查看Binder线程池状态。如果发现线程池满了,多半是某个回调卡住了。我曾经靠这个命令定位过一个顽固的ANR问题。

好了,Framework层的内容就讲到这里。这部分知识比较抽象,我建议你结合源码来理解。特别是CameraDeviceClient.cppCameraDeviceImpl.java这两个文件,值得反复阅读。


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