15、安全与权限管理:Android Automotive 安全模型、系统签名、SEAndroid 策略
各位同学,今天我们来聊聊车载系统里最“硬核”的部分——安全。说实话,做车机安全跟做手机安全完全是两码事。手机死机了重启就行,车机要是被攻破了,那可是人命关天。我在做某个量产项目时,就亲眼见过因为签名证书泄露,导致测试车被刷入恶意固件的惨案……嗯,从那以后我对安全这块就再也不敢马虎了。
15.1 Android Automotive 安全模型概览
Android Automotive 的安全模型,说白了就是“层层设防”。它继承了 Android 原生的沙箱机制,但针对车载场景做了大量增强。你想想看,车上有多个用户(驾驶员、乘客),还有各种 ECU 通信,权限模型必须更精细。
核心安全原则只有三条:
- 默认拒绝:没有明确授予的权限,一律视为禁止。
- 最小权限:每个进程只给够用的权限,多一点都不行。
- 职责分离:系统服务、应用、硬件驱动各司其职,互不信任。
我个人习惯把 Automotive 的安全架构画成下面这张图,方便理解:
每一层都依赖下一层提供的安全保证。应用层出了问题,框架层还能兜底;框架层被绕过,还有内核层的 SEAndroid 做最后一道防线。这就是所谓的“纵深防御”。
15.2 系统签名:车机的“身份证”
系统签名在 Automotive 里比手机重要得多。为什么?因为车机上很多系统级 API 只对签名应用开放。比如控制空调、读取车速、调用摄像头——这些接口如果被第三方应用拿到,后果不堪设想。
Android Automotive 使用四类签名:
| 签名类型 | 用途 | 保护级别 |
|---|---|---|
| 平台签名(platform) | 系统应用、核心服务 | 最高,可访问 system 权限 |
| 媒体签名(media) | 音视频相关应用 | 高,可访问媒体权限 |
| 共享签名(shared) | 同一开发者的多个应用 | 中,可共享 UID |
| 测试签名(testkey) | 开发调试阶段 | 低,仅用于 eng 版本 |
签名验证流程其实不复杂:
// 系统签名验证核心逻辑(简化)
public boolean verifySignature(ApplicationInfo appInfo) {
// 1. 读取应用签名证书
Signature[] signatures = appInfo.getSignatures();
// 2. 与系统预置的 platform 证书对比
if (Arrays.equals(signatures, PLATFORM_CERT)) {
return true; // 授予 platform 级别权限
}
// 3. 与 media 证书对比
if (Arrays.equals(signatures, MEDIA_CERT)) {
return true; // 授予 media 级别权限
}
// 4. 默认拒绝
return false;
}
你可能会问:“那我把 platform 证书偷出来不就行了?”嗯,理论上可以,但实际操作中,OEM 厂商会把私钥存储在硬件安全模块(HSM)里,物理上就无法导出。我建议你在项目初期就建立好密钥管理流程,别等到量产前才手忙脚乱。
15.3 SEAndroid 策略:强制访问控制
SEAndroid 是 Android 安全体系里我最欣赏的部分。它基于 Linux 的 SELinux,实现了强制访问控制(MAC)。什么意思呢?就是即使你拿到了 root 权限,也不能为所欲为。
举个例子:
# 一个典型的 SEAndroid 策略规则
allow system_app vehicle_service:service { start stop };
# 解释:允许 system_app 域的应用,对 vehicle_service 服务执行 start 和 stop 操作
这条规则意味着,只有被标记为 system_app 的进程才能控制车辆服务。其他进程,哪怕是 root 用户,也无法执行这个操作。
在 Automotive 中,SEAndroid 策略主要关注三个领域:
- 车辆服务访问:控制哪些应用可以读写车辆属性(车速、转向、空调等)
- 系统服务保护:防止未授权进程访问 ActivityManager、PackageManager 等核心服务
- 设备节点控制:限制对 /dev/vehicle、/dev/can 等硬件节点的访问
💡 个人经验: 我在调试一个车载信息娱乐系统时,发现第三方地图应用总是无法获取 GPS 数据。查了两天,最后发现是 SEAndroid 策略里忘了给该应用的 domain 添加 gps_device 的访问权限。加上一行 allow map_app gps_device:chr_file read; 就解决了。所以,遇到权限问题,先查 SEAndroid 的 avc 日志!
查看 avc 拒绝日志的命令:
adb logcat -b events | grep "avc: denied"
这条命令能帮你快速定位哪些操作被 SEAndroid 拦截了。我个人习惯在开发阶段把策略设为 permissive 模式(只记录不拦截),等调试完再切回 enforcing 模式。但注意,量产车必须 enforcing!
15.4 权限管理实战:车载特有的权限
Android Automotive 新增了一批车载专属权限,这些在手机上是没有的。我列几个常用的:
| 权限名称 | 保护级别 | 用途 |
|---|---|---|
| android.car.permission.CAR_SPEED | signature|privileged | 读取车辆速度 |
| android.car.permission.CAR_ENERGY | signature|privileged | 读取续航里程、油耗 |
| android.car.permission.CAR_INFO | signature | 读取 VIN 码、车辆配置 |
| android.car.permission.CAR_CONTROL_AUDIO_VOLUME | signature | 控制音量(包括导航混音) |
🔧 调试技巧: 如果你在开发车载应用时遇到权限拒绝,可以用 pm check-permission 命令检查应用是否拥有某个权限:
adb shell pm check-permission android.car.permission.CAR_SPEED com.example.myapp
返回 true 表示有权限,false 表示没有。
最后说一句,安全不是一次性工作。随着系统版本升级、新功能加入,SEAndroid 策略和权限定义都需要持续维护。我建议你在每个 sprint 结束时都跑一遍安全审计脚本,确保没有遗漏的开放端口或过度授权的应用。
好了,这一章的内容就到这里。安全是车机的生命线,希望各位同学在实际项目中能把这些原则落到实处。