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;
}
相关推荐
4Forsee3 小时前
【Android】View 事件分发机制与源码解析
android·java·前端
咕噜签名分发冰淇淋3 小时前
苹果ios安卓apk应用APP文件怎么修改手机APP显示的名称
android·ios·智能手机
应用市场3 小时前
从零开始打造Android桌面Launcher应用:原理剖析与完整实现
android
叶羽西3 小时前
Android15增强型视觉系统(EVS)
android
沅霖3 小时前
android kotlin语言中的协程
android·开发语言·kotlin
齊家治國平天下3 小时前
Android 14 系统启动流程深度解析:rc文件的语法、解析及常见语法详解
android·init·rc·init.rc
shaominjin1233 小时前
Android Studio 代码注释模板设置指南
android
红宝村村长3 小时前
Golang交叉编译到Android上运行
android·开发语言·golang
游戏开发爱好者84 小时前
iOS 开发推送功能全流程详解 从 APNs 配置到上架发布的完整实践(含跨平台上传方案)
android·macos·ios·小程序·uni-app·cocoa·iphone