4. CameraService构造函数:服务注册、监听器初始化、HAL设备枚举准备

CameraService 的构造函数是整个相机框架启动的核心入口。它不仅要完成自身状态的初始化,还需要完成三个关键任务:向 ServiceManager 注册服务、初始化内部监听器、以及为后续 HAL 设备枚举做好准备。本章将深入分析构造函数中每一行关键代码的执行逻辑与调试要点。

4.1 构造函数整体流程

CameraService 构造函数位于 frameworks/av/services/camera/libcameraservice/CameraService.cpp,其核心执行顺序如下表所示:

步骤 执行函数/操作 关键作用 调试关注点
1 CameraService() 入口 初始化成员变量、mutex、condition 检查是否重复构造
2 registerService() 将 CameraService 注册到 ServiceManager 确认服务名 "media.camera" 是否注册成功
3 initializeListener() 创建并启动内部监听线程 监听线程是否正常轮询
4 enumerateHALDevices() 准备 初始化 HAL 客户端、准备设备枚举 HAL 服务是否可达
调试要点: 构造函数执行期间如果发生异常(如 HAL 服务未启动),CameraService 将无法正常启动。建议在 onFirstRef() 中增加日志标记,确认构造是否完整执行。

4.2 服务注册:向 ServiceManager 注册 CameraService

CameraService 继承自 BnCameraService,通过 defaultServiceManager()->addService() 将自身注册到 ServiceManager。注册成功后,其他进程(如 Camera2 应用)可以通过 getService("media.camera") 获取代理。

// CameraService.cpp 关键代码片段
void CameraService::onFirstRef() {
    ALOGI("CameraService started (pid=%d)", getpid());

    // 注册服务
    status_t err = defaultServiceManager()->addService(
            String16("media.camera"), this, false);
    if (err != OK) {
        ALOGE("Failed to register camera service: %d", err);
        return;
    }
    ALOGI("CameraService registered successfully");
    // ... 后续初始化
}

服务注册的流程可以用下面的 SVG 图表示:

CameraService 服务注册流程 CameraService addService() ServiceManager 返回 status_t 注册服务名:"media.camera" 注册失败时 CameraService 将无法对外提供服务
调试技巧: 使用 adb shell dumpsys media.camera 可以验证 CameraService 是否已注册。如果返回 "Service not found",说明注册失败,需要检查 SELinux 权限或 ServiceManager 是否正常。

4.3 监听器初始化:内部事件监听线程

CameraService 内部维护了一个 CameraServiceListener,用于监听系统事件(如设备热插拔、权限变化等)。监听器在构造函数中通过 initializeListener() 初始化,并启动一个独立的 ListenerThread 进行事件轮询。

// CameraService.cpp 监听器初始化
status_t CameraService::initializeListener() {
    mListener = new CameraServiceListener(this);
    mListenerThread = new ListenerThread("CameraListener", mListener);
    status_t err = mListenerThread->run("CameraListener");
    if (err != OK) {
        ALOGE("Failed to start listener thread: %d", err);
        return err;
    }
    ALOGI("Camera listener thread started");
    return OK;
}

监听器线程的工作模式如下:

  • 事件源: 来自 HAL 层的设备状态变化通知、系统广播(如屏幕状态变化)。
  • 处理方式: 线程内部维护一个 Looper,通过 MessageQueue 异步处理事件。
  • 关键回调: onDeviceStatusChanged()、onTorchStatusChanged()。
常见问题: 监听器线程如果因为死锁或阻塞导致无法处理事件,会导致相机设备状态更新延迟。在调试时可以通过 adb shell ps -A | grep camera 查看线程是否存活。

4.4 HAL 设备枚举准备:初始化 HAL 客户端

在构造函数末尾,CameraService 会为 HAL 设备枚举做准备。这包括创建 CameraProviderManager 实例,并注册 CameraServiceProxy 用于与 HAL 服务通信。

// CameraService.cpp 枚举准备
void CameraService::enumerateHALDevices() {
    // 创建 CameraProviderManager
    mProviderManager = new CameraProviderManager();
    mProviderManager->initialize(this);

    // 注册 HAL 服务监听
    mProviderManager->setCameraServiceListener(mListener);

    // 准备枚举所有 HAL 设备
    status_t err = mProviderManager->enumerateProviders();
    if (err != OK) {
        ALOGE("Failed to enumerate HAL providers: %d", err);
    }
}

枚举准备阶段的核心数据结构如下表所示:

组件 类型 作用 初始化状态
CameraProviderManager 核心管理类 管理所有 HAL Provider 的注册与枚举 创建后立即初始化
CameraServiceProxy Binder 代理 与 HAL 服务进程通信 延迟初始化(首次枚举时)
HALDeviceInfo 设备信息结构体 存储每个 HAL 设备的元数据 枚举完成后填充

下面的 SVG 图展示了枚举准备阶段的组件关系:

HAL 设备枚举准备阶段组件关系 CameraService CameraProviderManager CameraServiceProxy HAL Provider 枚举准备阶段关键操作: 1. CameraProviderManager 初始化并注册监听器 2. CameraServiceProxy 建立与 HAL 的 Binder 连接 3. 调用 enumerateProviders() 触发实际枚举

4.5 构造函数执行时序总结

CameraService 构造函数的完整执行时序可以归纳为以下步骤:

  1. 成员初始化: 设置默认值、初始化 mutex 和 condition 变量。
  2. 服务注册: 调用 addService("media.camera"),使 CameraService 对外可见。
  3. 监听器启动: 创建 CameraServiceListener 并启动监听线程。
  4. HAL 枚举准备: 初始化 CameraProviderManager,注册代理,准备枚举。
调试检查清单:
  • 确认 logcat 中是否输出 "CameraService started" 和 "CameraService registered successfully"。
  • 检查监听器线程是否正常启动,无 "Failed to start listener thread" 错误。
  • 确认 HAL 枚举准备阶段没有 "Failed to enumerate HAL providers" 日志。
  • 使用 adb shell dumpsys media.camera 验证服务是否可用。

构造函数执行完毕后,CameraService 进入就绪状态,等待来自应用层的绑定请求和来自 HAL 层的设备状态通知。下一阶段将进入实际的 HAL 设备枚举流程。