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 形式返回。
三、关键参数与权限对照
下表汇总四层权限的核心控制对象、典型拒绝表现与排查入口,便于快速定位问题层级。
| 层级 | 控制对象 | 典型拒绝表现 | 排查入口 |
|---|---|---|---|
| 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。按层排查:
- Android 权限层:确认
AndroidManifest.xml已声明android.car.permission.CAR_SPEED,且为运行时权限已授予。 - Car Service 层:车速属于
VehiclePropertyGroup.SYSTEM,普通应用可能无读权限,需系统签名或特权应用。 - SELinux 层:查看
dmesg是否有avc: denied,确认 HAL 域对vehicle_prop类型的许可。 - 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 文件属主与模式。四层逐级确认,避免在错误层级反复试错。