20、车载安全与权限:Android Automotive安全模型
说实话,车载系统的安全,跟手机完全不是一个量级。
手机死机了,你重启一下就行。车机要是被攻破了,那可是要命的事。我在做第一个IVI项目时,就被安全合规折腾得够呛。当时客户要求通过某国际安全认证,我们团队光是SELinux策略就改了十几版。
今天这一章,我把Android Automotive的安全体系拆开来讲。你理解了这个框架,后面做权限设计、启动校验、数据加密,心里就有底了。
核心观点:车载安全不是「加把锁」,而是「造个保险柜」。从芯片上电到应用运行,每一层都要有防护。
20.1 SELinux:强制访问控制
SELinux,说白了就是给系统里的每个进程、每个文件都贴上「身份证」。没有通行证,天王老子来了也不让访问。
Android从5.0开始全面启用SELinux enforcing模式。车载系统上,这个要求更严格。我记得有一次,我们集成了一个第三方导航SDK,结果它想直接读GPS硬件节点。SELinux直接把它拦了,日志里全是「avc: denied」——嗯,那场面,排查了一下午。
我的习惯:开发阶段先用permissive模式跑,收集所有denied日志。等稳定了再切enforcing。千万别一上来就enforcing,否则你连问题出在哪都找不到。
车载系统里,SELinux策略主要管这几类:
- 域(domain):每个进程属于一个域,比如system_app、bluetooth、hal_vehicle
- 类型(type):每个文件、设备节点都有类型标签
- 规则(rule):定义哪个域能访问哪个类型,做什么操作
举个例子,车载的车辆硬件服务(Vehicle HAL)通常跑在 hal_vehicle 域。普通App想直接访问CAN总线?门都没有。
# 一个典型的车载SELinux规则片段
type hal_vehicle, domain;
type hal_vehicle_device, dev_type;
# 允许hal_vehicle域访问车辆设备节点
allow hal_vehicle hal_vehicle_device:chr_file rw_file_perms;
# 禁止普通app域访问车辆设备
neverallow appdomain hal_vehicle_device:chr_file ~{ read };
你看,最后一行 neverallow 是硬约束。就算你root了,这条规则也改不了——除非你重新编译内核。
20.2 权限管理:从普通到车载特有
Android的权限模型,大家应该不陌生。但车载系统里,多了几个「狠角色」。
20.2.1 标准Android权限
- 普通权限:安装时自动授予,比如访问网络
- 危险权限:运行时弹窗询问,比如定位、麦克风
- 签名权限:只有相同签名的App才能用,比如系统API
车载系统里,危险权限的弹窗要特别小心。你想想看,司机正在高速上开车,突然弹个「是否允许获取位置?」——这不是找骂吗?
避坑指南:我曾经见过一个项目,把定位权限弹窗设成了「每次启动都询问」。结果用户投诉说导航用不了。后来我们改成了「安装时预授权+设置里可撤回」,才消停。
20.2.2 车载特有权限
Android Automotive定义了几个专属权限,这些在手机AOSP里是没有的。
| 权限名称 | 保护级别 | 说明 |
|---|---|---|
| android.car.permission.CAR_DRIVING_STATE | signature|system | 获取驾驶模式(停车/行驶/自动驾驶) |
| android.car.permission.CAR_CONTROL_AUDIO_VOLUME | signature|system | 控制音量、静音等音频设置 |
| android.car.permission.CAR_CONTROL_CLIMATE | signature|system | 控制空调温度、风向等 |
| android.car.permission.CAR_INFO | signature|system | 读取车辆基本信息(VIN、车速等) |
| android.car.permission.CAR_POWERTRAIN | privileged | 访问动力系统数据(转速、电池状态) |
注意看保护级别。大部分车载权限都是 signature|system,意味着只有系统应用或同签名的应用才能申请。第三方App?想都别想。
驾驶模式权限是个典型例子。我做过一个功能:车辆行驶时自动锁定视频播放。实现方式就是监听驾驶状态:
// 申请驾驶模式权限(需要在AndroidManifest中声明)
<uses-permission android:name="android.car.permission.CAR_DRIVING_STATE" />
// 代码中监听驾驶状态变化
Car car = Car.createCar(context);
CarDrivingStateManager manager = (CarDrivingStateManager)
car.getCarManager(Car.CAR_DRIVING_STATE_SERVICE);
manager.registerListener(event -> {
int state = event.getDrivingState();
switch (state) {
case CarDrivingStateEvent.DRIVING_STATE_PARKED:
// 停车,可以播放视频
enableVideoPlayback(true);
break;
case CarDrivingStateEvent.DRIVING_STATE_MOVING:
// 行驶中,禁止视频
enableVideoPlayback(false);
showWarning("行驶中请勿观看视频");
break;
}
});
这里有个细节:CarDrivingStateManager 是系统服务,普通App拿不到。只有系统应用或者有系统签名的应用才能调用。
20.3 安全启动:从芯片到系统的信任链
安全启动(Verified Boot),说白了就是「上查三代」。从BootROM开始,每一级都要校验下一级的签名。只要有一级不对,系统就不启动。
流程大概是这样的:
- BootROM:固化在芯片里,不可篡改。它校验Bootloader的签名。
- Bootloader:校验Boot分区(Linux内核)的签名。
- Linux内核:校验system分区的dm-verity哈希树。
- system分区:每个块都有哈希值,读的时候实时校验。
我在项目中遇到过一个问题:客户自己刷了一个第三方内核,结果启动到一半就黑屏了。为什么?因为Bootloader校验内核签名失败,直接拒绝启动。这就是安全启动在起作用。
关键点:dm-verity是内核的一个特性。它把system分区映射成一个只读设备,每次读取都会校验哈希。如果有人改了system里的文件,哈希对不上,内核就会返回I/O错误。
车载系统里,安全启动是强制要求。很多车规级芯片(比如高通SA8155、瑞萨R-Car)出厂就锁死了BootROM,你想关都关不掉。
20.4 数据加密与隐私保护
车上的数据比手机敏感得多。想想看:你的行车轨迹、常用地址、甚至家里的车库门禁码——这些都在车机里。
20.4.1 文件级加密
Android从7.0开始支持文件级加密(FBE)。每个用户的文件用不同的密钥加密。车载系统里,通常给「车主」和「访客」模式分配不同的密钥。
// 文件级加密的密钥管理(简化示意)
// 每个用户目录 /data/user/0/ 下的文件,使用该用户的密钥加密
// 切换用户时,旧用户的密钥被卸载,新用户的密钥加载
// 系统服务中设置用户加密策略
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
UserHandle user = Process.myUserHandle();
if (um.isUserUnlocked()) {
// 用户已解锁,可以读写加密文件
File privateFile = new File(context.getFilesDir(), "secret.dat");
// 这个文件自动使用当前用户的密钥加密
}
20.4.2 全盘加密
全盘加密(FDE)在车载上用得不多,因为启动时需要输入密码——车机哪有这个交互?所以大部分车厂选择FBE,配合硬件密钥存储(如TEE或SE)。
我建议:如果做车载数据加密,优先用Android的EncryptedFile API。它基于文件级加密,而且对开发者透明。你读写文件时,系统自动加解密,不用自己操心密钥管理。
20.4.3 隐私保护策略
车载系统有几个特殊的隐私场景:
- 驾驶行为数据:急加速、急刹车等数据,不能随意上传。需要用户明确同意。
- 位置数据:即使App有定位权限,在「访客模式」下也应该模糊化处理。
- 语音数据:车载语音助手录制的音频,处理完就要删除,不能长期保存。
我记得有个项目,客户要求「访客模式」下不能保存任何历史记录。我们怎么做的?给访客用户创建一个独立的加密空间,退出时直接销毁密钥。这样数据物理上还在,但永远解不开了。
注意:隐私保护不是「加个开关」那么简单。你需要从架构层面设计。比如,所有敏感数据的读写都走一个PrivacyManager服务,由它统一控制是否允许访问、是否记录日志。
20.5 小结
车载安全,说到底就是「信任」两个字。你信任硬件不会骗你(安全启动),信任系统不会乱跑(SELinux),信任App不会乱来(权限管理),信任数据不会泄露(加密)。
这一套组合拳打下来,虽然开发时麻烦点,但用户坐在车里才安心。嗯,这就是我们做车载系统的责任。
公众号:蓝海资料掘金营,微信deep3321