3. 权限模型总览

在 Android Automotive 中,一次看似简单的“打开空调”或“读取车速”操作,往往要连续穿过四道权限关卡:Linux 内核的 UID/GID 与文件模式、Android 应用框架的运行时权限、SELinux 的强制访问控制,以及 Car Service 自身的业务级权限校验。它们不是彼此替代的关系,而是层层叠加、各管一段的协作体系。理解这四层的分工与衔接顺序,是排查“权限被拒”类问题的起点。

一、四层权限的分工定位

可以把这四层理解为从“内核”到“业务”的纵深防御:

  • Linux 权限(DAC):最底层,基于 UID/GID 和文件 rwx 模式,决定进程能否打开设备节点、socket、文件。它是自主访问控制,资源属主可自行授权。
  • Android 权限:应用框架层,通过 AndroidManifest.xml 声明、安装时授予或运行时弹窗授予,控制 API 级能力,如定位、蓝牙、存储。
  • SELinux(MAC):强制访问控制,基于“主体域—客体类型—许可”策略,即使 root 也不能绕过。它约束的是进程域能对哪些类型执行哪些操作。
  • Car Service 权限:业务层,在 Automotive 特有的 Car API 中做细粒度校验,例如车辆属性读写、驾驶状态限制、乘客区域隔离。

四层的关系是“与”逻辑:任何一层拒绝,操作即失败。因此排障时必须逐层确认,而不是只盯着最上层报错。

二、协作机制与调用链

以应用读取车辆速度属性为例,调用链大致如下:应用调用 CarPropertyManager.getProperty() → Binder 进入 Car Service → Car Service 校验调用方权限与属性访问级别 → 通过 Vehicle HAL 下发 → HAL 进程访问内核设备节点 → SELinux 检查 HAL 域对设备类型的许可 → Linux DAC 检查设备文件权限。任一环节不通过,都会以 SecurityException 或 EACCES 形式返回。

Android Automotive 四层权限协作链 从应用调用到内核访问,逐层校验,任一拒绝即失败 ① 应用层 App 调用 CarPropertyManager / Car API,声明 uses-permission Android 权限校验 运行时 / 安装时授予 Binder IPC ② Car Service 业务层 校验调用方 UID/PID、属性访问级别、驾驶状态、乘客区域 Car 专属权限 如 CAR_SPEED 读写级别 Vehicle HAL 调用 ③ SELinux 强制访问控制 检查 HAL 域对设备节点类型的 allow 规则,root 亦不可绕过 域—类型—许可 avc: denied 日志 open / ioctl ④ Linux DAC 内核层 UID/GID 与文件 rwx 模式决定设备节点、socket 的最终可访问性 EACCES / EPERM 文件模式与属主 校验顺序:Android 权限 → Car Service → SELinux → Linux DAC,逐层放行才成功

三、关键参数与权限对照

下表汇总四层权限的核心控制对象、典型拒绝表现与排查入口,便于快速定位问题层级。

层级 控制对象 典型拒绝表现 排查入口
Linux DAC UID/GID、文件 rwx EACCES、EPERM ls -lZ、id
Android 权限 API 能力、运行时授权 SecurityException dumpsys package
SELinux 域—类型—许可 avc: denied dmesg | grep avc
Car Service 车辆属性访问级别 IllegalArgumentException / 权限异常 logcat | grep CarProperty

四、典型场景:车速读取被拒的复盘

某应用调用车速属性时抛出 SecurityException。按层排查:

  1. Android 权限层:确认 AndroidManifest.xml 已声明 android.car.permission.CAR_SPEED,且为运行时权限已授予。
  2. Car Service 层:车速属于 VehiclePropertyGroup.SYSTEM,普通应用可能无读权限,需系统签名或特权应用。
  3. SELinux 层:查看 dmesg 是否有 avc: denied,确认 HAL 域对 vehicle_prop 类型的许可。
  4. Linux DAC 层:确认 HAL 进程对 /dev/vehicle* 设备节点的属主与模式。
# 查看 SELinux 拒绝日志
adb shell dmesg | grep "avc: denied"

# 查看应用已授予权限
adb shell dumpsys package com.example.carapp | grep -A5 "granted=true"

# 查看设备节点权限与 SELinux 上下文
adb shell ls -lZ /dev/vehicle*

常见误区:很多开发者认为“root 就能绕过一切”。实际上 SELinux 是强制访问控制,即使 UID=0,若域策略未放行,仍会被 avc: denied 拦截。另一个误区是只检查 Android 权限而忽略 Car Service 的业务校验,导致“权限已授予却仍失败”。

排查口诀:先看应用权限声明,再看 Car Service 业务规则,然后查 SELinux 拒绝日志,最后核对 Linux 文件属主与模式。四层逐级确认,避免在错误层级反复试错。