24、车载存储与文件系统:存储权限、外部存储、分区管理、数据备份与恢复
车载系统的存储,跟手机完全是两码事。
我刚开始接触 Android Automotive OS 时,第一反应是:这不就是车机版 Android 吗?存储能有多大区别?结果被现实狠狠教育了一回。手机没电了可以关机重启,车机存储出问题,轻则导航卡死,重则倒车影像都出不来。嗯,这里面的门道,咱们得好好捋一捋。
24.1 车载存储的特殊性
车载存储,说白了就是「可靠性优先」。手机存储坏了,你换台手机。车机存储坏了,你可能得把整个中控台拆了。我见过某款车型因为 eMMC 寿命耗尽,车主不得不花八千块换整个娱乐主机。
车载存储的几个关键特点:
- 高可靠性要求:工作温度范围 -40°C 到 85°C,远超消费级
- 长寿命设计:至少 10 年以上的写入寿命
- 分区隔离:系统区、用户区、缓存区严格分离
- 掉电保护:突然断电不能丢数据
核心原则:车载存储的设计目标是「系统不会因为存储问题而崩溃」,而不是「存储空间越大越好」。
24.2 存储权限管理
Android Automotive OS 的权限模型,跟手机版有显著差异。手机上的 READ_EXTERNAL_STORAGE 权限,在车机上基本不适用。为什么?因为车机上的「外部存储」概念跟手机完全不同。
车载应用的存储权限分为三层:
| 权限级别 | 访问范围 | 典型场景 |
|---|---|---|
| 内部私有存储 | 仅本应用 | 应用配置、缓存数据 |
| 共享存储 | 多应用共享 | 音乐下载、地图离线包 |
| 系统分区 | 系统级应用 | OTA 升级包、系统日志 |
我个人习惯的做法是:能用内部私有存储就别碰共享存储。我在项目中遇到过一个问题——两个地图应用同时写入共享存储的离线地图目录,结果互相覆盖了对方的索引文件。排查了整整两天,最后发现是权限设计没做好隔离。
避坑指南:车载应用申请存储权限时,一定要明确告知用户「为什么需要这个权限」。我曾经见过一个音乐播放器,一启动就申请所有存储权限,用户直接给了差评。后来改成按需申请,评分就上来了。
24.3 外部存储管理
车载系统的「外部存储」通常指 USB 设备和 SD 卡。但这里有个坑:车机上的 USB 接口可能同时连接着 CarPlay、Android Auto、U 盘、甚至行车记录仪。你怎么知道哪个是存储设备?
我建议用 StorageManager 来识别:
StorageManager storageManager = getSystemService(StorageManager.class);
StorageVolume[] volumes = storageManager.getStorageVolumes();
for (StorageVolume volume : volumes) {
if (volume.isRemovable()) {
// 这是可移除存储设备
Log.d("Storage", "发现外部存储: " + volume.getDescription());
}
}
你想想看,如果用户插了个 U 盘,里面存着 500 首无损音乐。你的音乐播放器应该怎么做?直接扫描所有文件?那得卡死。正确的做法是:
- 先检测存储设备的文件系统类型(FAT32、exFAT、NTFS)
- 再按目录结构逐层扫描
- 最后建立索引缓存
注意:车载系统对 USB 设备的读写速度有限制。我曾经测试过,某些车机对 USB 2.0 设备的写入速度只有 8MB/s。如果你要拷贝大文件,一定要在后台线程操作,并且显示进度条。否则用户会以为车机死机了。
24.4 分区管理
车载系统的分区设计,是整车厂最看重的部分。一个典型的分区布局是这样的:
/boot - 引导分区
/system - 系统分区(只读)
/vendor - 厂商分区(只读)
/data - 用户数据分区(可读写)
/cache - 缓存分区
/odm - 原始设备制造商分区
/factory - 出厂恢复分区
这里我要强调一点:/system 分区必须是只读的。为什么?因为如果系统分区可写,恶意应用就能修改系统文件,后果不堪设想。我见过一个案例,某款车机因为 system 分区被意外写入,导致 OTA 升级后系统无法启动,最后只能返厂刷机。
分区大小怎么定?我给出一个参考值:
| 分区 | 建议大小 | 说明 |
|---|---|---|
| /system | 2-4 GB | 包含 Android 系统和预装应用 |
| /data | 16-64 GB | 用户数据、应用安装、离线地图 |
| /cache | 1-2 GB | OTA 升级包、系统缓存 |
| /factory | 512 MB | 出厂镜像,用于恢复 |
经验之谈:分区大小不是越大越好。我见过某厂商给 /data 分区分配了 128GB,结果用户根本用不完,反而浪费了宝贵的 eMMC 寿命。合理的做法是根据目标用户的使用习惯来定。比如主打导航的车机,离线地图可能占 20GB,那 /data 给 32GB 就够用了。
24.5 数据备份与恢复
车载系统的数据备份,比手机复杂得多。手机备份大不了恢复联系人、照片。车机要备份什么?
- 用户账户信息(音乐、视频会员)
- 导航历史记录和收藏地址
- 蓝牙配对信息
- 座椅、空调等车辆设置
- 驾驶行为数据(部分法规要求)
Android Automotive OS 提供了 BackupManager 机制,但说实话,这个机制在车机上不太够用。为什么?因为车机可能长时间处于休眠状态,BackupManager 的定时备份策略不一定能触发。
我建议的做法是:
// 自定义备份方案
public class VehicleBackupManager {
private static final String BACKUP_PATH = "/data/backup/";
public void backupUserData() {
// 1. 序列化用户配置
// 2. 写入备份分区
// 3. 校验完整性
// 4. 记录备份时间戳
}
public void restoreUserData() {
// 1. 检查备份文件是否存在
// 2. 验证签名
// 3. 恢复数据
// 4. 重启相关服务
}
}
避坑指南:我曾经遇到过一个很坑的问题——某款车机在 OTA 升级后,用户的所有蓝牙配对信息都丢了。排查后发现,是升级脚本把 /data/misc/bluetooth 目录给清空了。从那以后,我坚持在 OTA 升级前做一次完整的数据备份,升级后再恢复。虽然多了几步操作,但用户满意度提升了不少。
24.6 存储性能优化
车载存储的性能优化,核心就一句话:减少写入次数。
eMMC 和 UFS 的写入寿命是有限的。你想想看,如果某个应用每秒写一次日志,一年下来就是 3150 万次写入。再好的存储芯片也扛不住。
我总结了几条优化原则:
- 批量写入:把多次小写入合并成一次大写入
- 延迟写入:非关键数据可以等系统空闲时再写
- 避免频繁创建和删除文件:这会导致文件系统碎片化
- 使用 SQLite 替代文件存储:数据库的写入效率远高于文件操作
重要提醒:不要在车载系统上使用 swap 分区。我见过某厂商为了省成本,给车机配了 2GB RAM 加 4GB swap。结果呢?eMMC 的写入寿命在一年内就耗尽了。车载系统就该老老实实做内存管理,别拿存储当内存用。
24.7 知识体系总览
说了这么多,咱们用一张图来总结车载存储的核心知识体系:
这张图把车载存储的五个核心模块串起来了。你仔细看就会发现,所有模块都围绕着一个核心目标:可靠性和寿命。权限管理是为了安全,分区管理是为了隔离,备份恢复是为了容错,性能优化是为了延长寿命。外部存储管理则是为了兼容性。
好了,关于车载存储与文件系统,我就讲这么多。记住一句话:在车机上,存储不是用来「装东西」的,而是用来「保证系统稳定运行」的。这个思维转变,是做好车载开发的第一步。
公众号:蓝海资料掘金营,微信deep3321