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继承它后,无需重复实现服务注册的底层细节,只需专注于相机业务逻辑。
2. ::android::hardware::BnCameraService
- 核心作用:实现 Binder 通信的服务端接口,提供跨进程调用(IPC,进程通信)能力。
BnCameraService是相机服务的 Binder 接口基类(由ICameraService.aidl自动生成),其中定义了相机服务对外提供的所有接口(如打开相机、枚举相机设备等)。继承此类后,CameraService需实现这些纯虚函数,从而支持上层应用(如相机 App)通过 Binder 机制调用相机服务。
3. IBinder::DeathRecipient
- 核心作用:监听其他 Binder 对象的死亡通知,处理客户端或依赖服务崩溃的场景。
- 相机服务需要与多个客户端(如应用进程)、子服务(如相机提供商
CameraProvider)通过 Binder 交互。若对方进程崩溃,DeathRecipient的binderDied()方法会被回调,CameraService可通过重写该方法释放相关资源(如关闭相机设备、清理客户端状态),避免资源泄漏或野指针错误。
4. CameraProviderManager::StatusListener
- 核心作用:监听相机硬件提供商(
CameraProvider)的状态变化,同步硬件状态。 CameraProviderManager是管理相机 HAL 层提供商的模块(负责加载、管理相机硬件抽象)。StatusListener定义了硬件状态变化的回调接口(如相机设备连接 / 断开、硬件故障等)。CameraService继承此类后,可实时感知硬件状态变化(如外接相机插入),并同步更新服务内部状态(如刷新相机列表),确保上层获取的信息与硬件一致。
5. IServiceManager::LocalRegistrationCallback
- 核心作用:监听服务自身在
servicemanager中的注册状态,处理注册成功 / 失败的回调。 - 当
CameraService注册到系统服务管理器(servicemanager)时,LocalRegistrationCallback的方法(如onRegistrationCompleted())会被触发。通过重写这些方法,CameraService可在注册成功后执行初始化操作(如加载 HAL 模块),或在注册失败时进行错误处理(如重试、上报日志)。
为什么需要 “虚继承”?
代码中使用 public virtual 继承(虚继承),主要是为了解决多继承可能导致的 “菱形继承” 问题:
- 若多个父类间接继承自同一个基类(如 Binder 相关的父类可能共同继承自
IBinder),非虚继承会导致基类成员在子类中存在多份拷贝,引发二义性。 - 虚继承确保所有父类共享同一个基类实例,避免数据冗余和访问冲突,这在复杂的多继承场景(如 Android 服务框架)中是必要的设计。
CameraService 继承多个类是 **“组合复用” 设计原则 ** 的体现:每个父类封装特定功能(Binder 通信、死亡监听、硬件状态同步等),通过多继承将这些功能聚合到 CameraService 中,使其既能满足系统框架的接口规范,又能高效处理相机服务的核心业务(硬件交互、客户端管理、跨进程通信等)。这种设计避免了代码冗余,同时保证了系统各模块的解耦与可扩展性。
枚举Camera
在 Android 相机框架中,enumerateProviders() 是 CameraProviderManager 类的核心方法,其主要作用就是枚举系统中可用的相机提供商(Camera Provider),而相机提供商是连接相机硬件与框架层的关键组件,因此该方法间接实现了相机设备的枚举。
具体逻辑解析:
什么是 “相机提供商(Camera Provider)”?在 Android 8.0(API 26)引入的 Camera HAL 3.2+ 架构中,相机硬件的抽象被封装为 “相机提供商”(通常是运行在
camera-provider进程中的 HAL 服务),每个提供商负责管理一组物理相机(如手机的后置主摄、超广角、前置摄像头等)。例如,高通平台的camera-provider-2-4就是一个典型的相机提供商,管理该平台上的所有摄像头硬件。enumerateProviders()的核心作用该方法会通过 HIDL(Android 硬件接口定义语言) 扫描系统中已注册的所有相机提供商(通过IServiceManager查找符合相机接口规范的服务),并执行以下操作:- 收集每个提供商的信息(如名称、版本、支持的相机功能);
- 调用提供商的
getCameraIdList()接口,获取其管理的所有物理相机 ID(如 “0”“1”“2”,分别对应不同摄像头); - 将相机 ID 与提供商信息关联,形成 “相机设备列表”,供上层
CameraService使用。
与 “相机枚举” 的关系
enumerateProviders()本身不直接枚举物理相机,而是枚举管理相机的 “提供商”;- 但通过枚举提供商并调用其接口,间接完成了物理相机的枚举(获取所有可用相机的 ID 和基础信息);
- 最终,
CameraService会基于enumerateProviders()的结果,向上层应用(如相机 App)提供可用相机列表(即用户在 App 中看到的 “切换摄像头” 选项)。
调用时机与意义
enumerateProviders() 通常在 CameraService 初始化阶段被调用(如 CameraService::onFirstRef() 中),是系统启动时 “发现相机设备” 的关键步骤。如果该方法执行失败(如没有找到任何相机提供商),系统会提示 “无可用相机”。
enumerateProviders() 是 Android 相机框架中相机枚举的 “上游步骤”:通过枚举相机提供商,间接获取所有物理相机的信息,为上层提供可用相机列表。可以说,它是相机设备能够被系统识别和使用的基础。
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;
}
