4. Camera Provider 服务:HIDL 服务启动流程、ICameraProvider 接口实现、CameraService 与 HAL 的绑定机制
Camera Provider 是 Android Camera HAL3 架构中连接 Framework 与底层硬件驱动的核心桥梁。它作为独立进程运行,通过 HIDL(HAL Interface Definition Language)接口向 CameraService 提供设备枚举、打开、流配置等能力。本章深入剖析 Provider 服务的启动生命周期、ICameraProvider 接口的实现要点,以及 CameraService 与 HAL 之间的绑定握手过程。
4.1 HIDL 服务启动流程
Camera Provider 进程的启动由 init.rc 脚本触发,经过 HIDL 服务注册、Transport 层初始化、设备发现三个阶段,最终对外暴露服务。
| 阶段 | 关键动作 | 涉及组件 |
|---|---|---|
| 1. 进程启动 | init 解析 android.hardware.camera.provider@2.x-service.rc,fork 出 provider 进程 |
init、servicemanager |
| 2. HIDL 注册 | 调用 defaultPassthroughServiceImplementation() 或显式 registerAsService() |
libhidlbase、hwservicemanager |
| 3. 设备枚举 | 实现 ICameraProvider::getCameraIdList(),扫描底层驱动节点 |
CameraModule、V4L2 / MIPI 驱动 |
移植要点: 在 Android 12+ 中,Camera Provider 必须使用 Passthrough 模式注册,否则 CameraService 无法通过
getService() 发现 Provider。检查 manifest.xml 中是否声明了正确的 fqName 和 version。
4.2 ICameraProvider 接口实现
ICameraProvider 是 HIDL 定义的核心接口,Provider 必须实现以下关键方法:
- getCameraIdList():返回当前设备上所有可用的 Camera ID 列表(字符串数组)。
- getCameraDeviceInterface():根据 Camera ID 返回对应的
ICameraDeviceHIDL 接口实例。 - setCallback():注册
ICameraProviderCallback,用于通知 CameraService 设备热插拔事件。 - getVendorTags():返回厂商自定义的元数据标签描述。
实现建议: 在
getCameraDeviceInterface() 中,建议使用 懒加载 策略——只有首次请求时才打开 HAL 模块,避免 Provider 启动时占用过多资源。
// ICameraProvider 核心方法实现示例(C++)
Return<Status> CameraProvider::getCameraIdList(
hidl_vec<hidl_string> *_aidl_return) {
std::vector<std::string> camera_ids;
// 扫描 /dev/video* 或读取 camera_module 配置
for (int i = 0; i < mModule->getNumberOfCameras(); i++) {
camera_ids.push_back(std::to_string(i));
}
*_aidl_return = camera_ids;
return Status::OK;
}
Return<Status> CameraProvider::getCameraDeviceInterface(
const hidl_string& cameraId,
sp<ICameraDevice>* device) {
// 根据 cameraId 创建对应的 CameraDevice HIDL 对象
*device = new CameraDevice(cameraId, mModule);
return Status::OK;
}
4.3 CameraService 与 HAL 的绑定机制
CameraService 作为系统服务运行在 cameraserver 进程中,通过 HIDL 的 服务发现 机制与 Camera Provider 建立绑定。绑定过程分为以下步骤:
- 服务查询: CameraService 调用
ICameraProvider::getService(),hwservicemanager 根据 fqName 返回对应的 Provider Binder 对象。 - 版本协商: 通过
getInterfaceVersion()确认 Provider 实现的 HIDL 版本(如 2.4、2.5)。 - 回调注册: CameraService 实现
ICameraProviderCallback并调用setCallback()注册到 Provider。 - 设备枚举: 调用
getCameraIdList()获取可用 Camera 列表,随后逐个调用getCameraDeviceInterface()获取设备接口。
| 步骤 | 调用方 | HIDL 方法 | 返回/回调 |
|---|---|---|---|
| 1 | CameraService | ICameraProvider::getService() |
Provider Binder 对象 |
| 2 | CameraService | getInterfaceVersion() |
uint32_t 版本号 |
| 3 | CameraService | setCallback(callback) |
Status::OK |
| 4 | CameraService | getCameraIdList() |
hidl_vec<hidl_string> |
| 5 | CameraService | getCameraDeviceInterface(id) |
sp<ICameraDevice> |
常见绑定失败原因:
- SELinux 策略缺失: Provider 进程没有
hwservice_manager的 find 权限,导致getService()返回 null。 - manifest.xml 版本不匹配: Provider 注册的版本与 CameraService 请求的版本不一致,导致类型转换失败。
- Transport 层崩溃: 如果 Provider 进程在注册后立即 crash,hwservicemanager 会移除服务注册,CameraService 无法绑定。
4.4 热插拔与回调机制
Camera Provider 通过 ICameraProviderCallback 接口向 CameraService 通知设备状态变化。当物理 Camera 被插入或拔出时,Provider 调用 cameraDeviceStatusChange() 或 physicalCameraDeviceStatusChange() 方法,CameraService 据此更新内部设备列表并通知上层应用。
// Provider 端通知热插拔事件
void CameraProvider::onCameraPluggedIn(const std::string& cameraId) {
if (mCallback != nullptr) {
mCallback->cameraDeviceStatusChange(
cameraId,
CameraDeviceStatus::PRESENT);
}
}
void CameraProvider::onCameraUnplugged(const std::string& cameraId) {
if (mCallback != nullptr) {
mCallback->cameraDeviceStatusChange(
cameraId,
CameraDeviceStatus::NOT_PRESENT);
}
}
移植调试技巧: 在 Provider 启动日志中增加
ALOGI 输出 getCameraIdList() 返回的 ID 数量和 setCallback() 的调用状态。使用 lshal 命令验证 Provider 是否成功注册:adb shell lshal | grep camera.provider。