Android Camera 从应用到硬件之- 枚举Camera - 1

缘起何处

废话不多说, 相信时间的力量,开干!

从五年前就开始认识camera到目前的一知半解,实在是惭愧.于是决定再上路.可能是有点晚了, 但是later is bettern than never!

最早接触camera是高通的660 mm-camera结构.已经全部忘了, 但是Android9 从上到下的camera架构毕竟还是走过看过的.

那就从,API说起. 翻一下Android15的源码, 走一下核心接口的过程.

以下内容很多是基于AI生成内容进行的二次改动!

CameraService继承多虚父类的设计目的

CameraService 继承多个类(包括虚基类,即带有 virtual 关键字的父类)是 Android 框架设计中功能聚合与接口适配 的典型体现。这些父类分别提供了不同的核心能力,通过多继承,CameraService 能够整合多种功能,同时满足系统框架对接口规范、通信机制、生命周期管理等多方面的要求。

具体继承的类及其作用分析

  1. BinderService<CameraService>
  • 核心作用:提供 Binder 服务的基础框架,简化服务注册、生命周期管理等流程。
  • BinderService 是一个模板类,封装了 Binder 服务的通用逻辑(如通过 instantiate() 方法注册服务到 servicemanager)。CameraService 继承它后,无需重复实现服务注册的底层细节,只需专注于相机业务逻辑。
  1. ::android::hardware::BnCameraService
  • 核心作用 :实现 Binder 通信的服务端接口,提供跨进程调用(IPC,进程通信)能力。
  • BnCameraService 是相机服务的 Binder 接口基类(由 ICameraService.aidl 自动生成),其中定义了相机服务对外提供的所有接口(如打开相机、枚举相机设备等)。继承此类后,CameraService 需实现这些纯虚函数,从而支持上层应用(如相机 App)通过 Binder 机制调用相机服务。
  1. IBinder::DeathRecipient
  • 核心作用:监听其他 Binder 对象的死亡通知,处理客户端或依赖服务崩溃的场景。
  • 相机服务需要与多个客户端(如应用进程)、子服务(如相机提供商 CameraProvider)通过 Binder 交互。若对方进程崩溃,DeathRecipientbinderDied() 方法会被回调,CameraService 可通过重写该方法释放相关资源(如关闭相机设备、清理客户端状态),避免资源泄漏或野指针错误。
  1. CameraProviderManager::StatusListener
  • 核心作用 :监听相机硬件提供商(CameraProvider)的状态变化,同步硬件状态。
  • CameraProviderManager 是管理相机 HAL 层提供商的模块(负责加载、管理相机硬件抽象)。StatusListener 定义了硬件状态变化的回调接口(如相机设备连接 / 断开、硬件故障等)。CameraService 继承此类后,可实时感知硬件状态变化(如外接相机插入),并同步更新服务内部状态(如刷新相机列表),确保上层获取的信息与硬件一致。
  1. IServiceManager::LocalRegistrationCallback
  • 核心作用 :监听服务自身在 servicemanager 中的注册状态,处理注册成功 / 失败的回调。
  • CameraService 注册到系统服务管理器(servicemanager)时,LocalRegistrationCallback 的方法(如 onRegistrationCompleted())会被触发。通过重写这些方法,CameraService 可在注册成功后执行初始化操作(如加载 HAL 模块),或在注册失败时进行错误处理(如重试、上报日志)。

为什么需要 "虚继承"?

代码中使用 public virtual 继承(虚继承),主要是为了解决多继承可能导致的 "菱形继承" 问题

  • 若多个父类间接继承自同一个基类(如 Binder 相关的父类可能共同继承自 IBinder),非虚继承会导致基类成员在子类中存在多份拷贝,引发二义性。
  • 虚继承确保所有父类共享同一个基类实例,避免数据冗余和访问冲突,这在复杂的多继承场景(如 Android 服务框架)中是必要的设计。

CameraService 继承多个类是 **"组合复用" 设计原则 ** 的体现:每个父类封装特定功能(Binder 通信、死亡监听、硬件状态同步等),通过多继承将这些功能聚合到 CameraService 中,使其既能满足系统框架的接口规范,又能高效处理相机服务的核心业务(硬件交互、客户端管理、跨进程通信等)。这种设计避免了代码冗余,同时保证了系统各模块的解耦与可扩展性。

枚举Camera

在 Android 相机框架中,enumerateProviders()CameraProviderManager 类的核心方法,其主要作用就是枚举系统中可用的相机提供商(Camera Provider),而相机提供商是连接相机硬件与框架层的关键组件,因此该方法间接实现了相机设备的枚举。

具体逻辑解析:

  1. 什么是 "相机提供商(Camera Provider)"? 在 Android 8.0(API 26)引入的 Camera HAL 3.2+ 架构 中,相机硬件的抽象被封装为 "相机提供商"(通常是运行在 camera-provider 进程中的 HAL 服务),每个提供商负责管理一组物理相机(如手机的后置主摄、超广角、前置摄像头等)。例如,高通平台的 camera-provider-2-4 就是一个典型的相机提供商,管理该平台上的所有摄像头硬件。

  2. enumerateProviders() 的核心作用 该方法会通过 HIDL(Android 硬件接口定义语言) 扫描系统中已注册的所有相机提供商(通过 IServiceManager 查找符合相机接口规范的服务),并执行以下操作:

    • 收集每个提供商的信息(如名称、版本、支持的相机功能);
    • 调用提供商的 getCameraIdList() 接口,获取其管理的所有物理相机 ID(如 "0""1""2",分别对应不同摄像头);
    • 将相机 ID 与提供商信息关联,形成 "相机设备列表",供上层 CameraService 使用。
  3. 与 "相机枚举" 的关系

    • enumerateProviders() 本身不直接枚举物理相机,而是枚举管理相机的 "提供商"
    • 但通过枚举提供商并调用其接口,间接完成了物理相机的枚举(获取所有可用相机的 ID 和基础信息);
    • 最终,CameraService 会基于 enumerateProviders() 的结果,向上层应用(如相机 App)提供可用相机列表(即用户在 App 中看到的 "切换摄像头" 选项)。

调用时机与意义

enumerateProviders() 通常在 CameraService 初始化阶段 被调用(如 CameraService::onFirstRef() 中),是系统启动时 "发现相机设备" 的关键步骤。如果该方法执行失败(如没有找到任何相机提供商),系统会提示 "无可用相机"。

enumerateProviders() 是 Android 相机框架中相机枚举的 "上游步骤":通过枚举相机提供商,间接获取所有物理相机的信息,为上层提供可用相机列表。可以说,它是相机设备能够被系统识别和使用的基础。

cpp 复制代码
status_t CameraService::enumerateProviders() {  //provider是连接相机硬件和框架层的关键组件,该方法间接的实现了相机的枚举.
    status_t res;
    std::vector<std::string> deviceIds;
    std::unordered_map<std::string, std::set<std::string>> unavailPhysicalIds;
    {
        Mutex::Autolock l(mServiceLock);

        if (nullptr == mCameraProviderManager.get()) {
            mCameraProviderManager = new CameraProviderManager();
            res = mCameraProviderManager->initialize(this); //初始化接口.
            if (res != OK) {
                ALOGE("%s: Unable to initialize camera provider manager: %s (%d)",
                        __FUNCTION__, strerror(-res), res);
                logServiceError(String8::format("Unable to initialize camera provider manager"),
                ERROR_DISCONNECTED);
                return res;
            }
        }

        // Setup vendor tags before we call get_camera_info the first time because HAL might need to setup static vendor keys in get_camera_info TODO: maybe put this into CameraProviderManager::initialize()?
        mCameraProviderManager->setUpVendorTags();
        if (nullptr == mFlashlight.get()) {
            mFlashlight = new CameraFlashlight(mCameraProviderManager, this);
        }
        res = mFlashlight->findFlashUnits();
        if (res != OK) {
            ALOGE("Failed to enumerate flash units: %s (%d)", strerror(-res), res);
        }

        deviceIds = mCameraProviderManager->getCameraDeviceIds(&unavailPhysicalIds);
    }


    for (auto& cameraId : deviceIds) {
        String8 id8 = String8(cameraId.c_str());
        if (getCameraState(id8) == nullptr) {
            onDeviceStatusChanged(id8, CameraDeviceStatus::PRESENT);
        }
        if (unavailPhysicalIds.count(cameraId) > 0) {
            for (const auto& physicalId : unavailPhysicalIds[cameraId]) {
                String8 physicalId8 = String8(physicalId.c_str());
                onDeviceStatusChanged(id8, physicalId8, CameraDeviceStatus::NOT_PRESENT);
            }
        }
    }

    // Derive primary rear/front cameras, and filter their charactierstics.
    // This needs to be done after all cameras are enumerated and camera ids are sorted.
    if (SessionConfigurationUtils::IS_PERF_CLASS) {
        // Assume internal cameras are advertised from the same
        // provider. If multiple providers are registered at different time,
        // and each provider contains multiple internal color cameras, the current
        // logic may filter the characteristics of more than one front/rear color
        // cameras.
        Mutex::Autolock l(mServiceLock);
        filterSPerfClassCharacteristicsLocked();
    }

    return OK;
}
相关推荐
xiangpanf4 小时前
Laravel 10.x重磅升级:五大核心特性解析
android
robotx7 小时前
安卓线程相关
android
消失的旧时光-19437 小时前
Android 面试高频:JSON 文件、大数据存储与断电安全(从原理到工程实践)
android·面试·json
dalancon8 小时前
VSYNC 信号流程分析 (Android 14)
android
dalancon8 小时前
VSYNC 信号完整流程2
android
dalancon8 小时前
SurfaceFlinger 上帧后 releaseBuffer 完整流程分析
android
用户69371750013849 小时前
不卷AI速度,我卷自己的从容——北京程序员手记
android·前端·人工智能
程序员Android10 小时前
Android 刷新一帧流程trace拆解
android
墨狂之逸才10 小时前
解决 Android/Gradle 编译报错:Comparison method violates its general contract!
android
阿明的小蝴蝶11 小时前
记一次Gradle环境的编译问题与解决
android·前端·gradle