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 并创建进程的完整流程如下:
- 解析阶段: init 读取
/system/etc/init/目录下所有.rc文件,将service cameraserver注册到服务列表中。 - 触发阶段: 当
class main对应的触发条件满足(系统启动进入 core 或 main 阶段),init 开始启动 cameraserver 服务。 - fork 执行: init 进程调用
fork()创建子进程,子进程执行execve()加载/system/bin/cameraserver可执行文件。 - 权限设置: 在 fork 之后、exec 之前,init 根据 rc 配置设置子进程的 user、group、ioprio、rlimit 等属性。
- 进程注册: 子进程启动成功后,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 的完整流程:
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 建立通信链路。