2. CameraService 进程启动:init.rc 解析与 cameraserver 进程创建

CameraService 作为 Android 相机子系统的核心服务,运行在独立的 cameraserver 进程中。该进程由 init 进程根据 init.rc 脚本解析并启动。理解这一启动流程,是后续分析 CameraService 初始化、HAL 加载以及 CameraProvider 通信的基础。

2.1 init.rc 中的 cameraserver 声明

在 Android 系统中,cameraserver 进程的启动入口定义在 /system/etc/init/cameraserver.rc 文件中。init 进程在启动时会解析所有 .rc 文件,并根据其中的 service 声明创建对应的进程。

关键文件路径: /system/etc/init/cameraserver.rc
service cameraserver /system/bin/cameraserver
    class main
    user cameraserver
    group audio camera input drmrpc
    ioprio rt 4
    task_profiles CameraServiceCapacity MaxPerformance
    rlimit rtprio 10 10
    onrestart restart audioserver
    writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks

上述配置的关键字段解析如下表所示:

字段 值 说明
service cameraserver 定义服务名称,用于进程管理和依赖引用
/system/bin/cameraserver 可执行文件路径 实际启动的二进制文件,编译自 frameworks/av/camera/cameraserver/
class main 主服务类 属于 main 类,随系统核心服务一同启动
user cameraserver 专用用户 以 cameraserver 用户身份运行,隔离权限
group audio camera input drmrpc 加入多个用户组以获取对应设备节点的访问权限
onrestart restart audioserver 当 cameraserver 重启时,同时重启 audioserver(音视频同步依赖)
调试提示: 若 cameraserver 进程频繁重启,可通过 logcat -b events | grep cameraserver 查看 init 进程触发的重启事件,同时检查 onrestart 链是否导致 audioserver 也被连带重启。

2.2 init 进程解析与进程创建流程

init 进程解析 cameraserver.rc 并创建进程的完整流程如下:

  1. 解析阶段: init 读取 /system/etc/init/ 目录下所有 .rc 文件,将 service cameraserver 注册到服务列表中。
  2. 触发阶段: 当 class main 对应的触发条件满足(系统启动进入 core 或 main 阶段),init 开始启动 cameraserver 服务。
  3. fork 执行: init 进程调用 fork() 创建子进程,子进程执行 execve() 加载 /system/bin/cameraserver 可执行文件。
  4. 权限设置: 在 fork 之后、exec 之前,init 根据 rc 配置设置子进程的 user、group、ioprio、rlimit 等属性。
  5. 进程注册: 子进程启动成功后,init 将其 PID 写入 /dev/cpuset/camera-daemon/tasks 和 /dev/stune/top-app/tasks,完成 cgroup 绑定。
常见问题: 若 /system/bin/cameraserver 文件缺失或 SELinux 策略阻止执行,init 将无法启动该进程,导致 CameraService 不可用。此时 logcat 中会出现 init: Service 'cameraserver' is being killed 或 init: cannot find '/system/bin/cameraserver' 等错误。

2.3 cameraserver 进程创建与初始化流程图

下图展示了从 init 解析 rc 文件到 cameraserver 进程启动并注册 CameraService 的完整流程:

cameraserver 进程创建与初始化流程 init 解析 cameraserver.rc fork() 创建子进程 设置 user/group/ioprio exec() 加载 cameraserver main() → CameraService::instantiate() addService("media.camera") 关键依赖文件 • /system/etc/init/cameraserver.rc • /system/bin/cameraserver • /vendor/etc/seccomp_policy/ cameraserver-seccomp.policy 调试命令 • ps -A | grep cameraserver • lsof -p [PID] • cat /proc/[PID]/cgroup • dumpsys media.camera

2.4 cameraserver 进程的权限与安全模型

cameraserver 进程的权限设计遵循 Android 的 最小权限原则,其安全模型包含以下层次:

  • 用户隔离: 使用独立的 cameraserver 用户,避免与 system、root 等共享 UID。
  • 组权限: 加入 audio(音频设备)、camera(视频设备节点)、input(输入事件)、drmrpc(DRM 相关通信)等组,仅获取必要设备访问权。
  • SELinux 策略: 通过 cameraserver.te 文件定义进程的域转换和访问规则,限制其对文件、属性、binder 服务的操作范围。
  • seccomp 过滤: 通过 cameraserver-seccomp.policy 限制可用的系统调用,防止内核漏洞利用。
  • CAP 能力: cameraserver 进程默认不持有任何 CAP(能力),进一步缩小攻击面。
调试技巧: 当 cameraserver 因权限不足无法访问 HAL 服务时,可通过 adb shell dmesg | grep cameraserver 查看 SELinux 拒绝日志,或使用 adb shell su root cat /proc/kmsg | grep avc 捕获 AVC 审计信息。

2.5 进程启动后的关键初始化步骤

cameraserver 进程启动后,main() 函数会依次执行以下初始化操作:

步骤 函数/操作 说明
1 ProcessState::self()->startThreadPool() 启动 Binder 线程池,准备接收 IPC 调用
2 defaultServiceManager()->addService() 将 CameraService 注册到 ServiceManager,服务名为 "media.camera"
3 CameraService::onFirstRef() 首次引用时触发,初始化 HAL 管理器、枚举 CameraProvider
4 IPCThreadState::self()->joinThreadPool() 主线程进入 Binder 循环,等待客户端请求
关键观察点: 在 onFirstRef() 中,CameraService 会通过 ICameraProviderService 接口与 HAL 层的 CameraProvider 建立连接。若此阶段失败,dumpsys media.camera 将显示 "No cameras found" 或连接超时错误。

至此,cameraserver 进程已成功创建并运行,CameraService 已注册到 ServiceManager,等待来自上层框架(如 CameraManager)的 binder 调用。下一阶段将深入分析 CameraService 如何通过 HAL 接口与底层 CameraProvider 建立通信链路。