17、预条件检查与数据备份:电池电量检查、存储空间检查、用户数据备份策略
系统升级这事儿,最怕什么?
怕升级到一半,手机没电了。怕存储空间不够,解压到一半卡死了。更怕用户数据丢了,回头来找你拼命。
所以,在真正开始升级之前,我们得做一套「预条件检查」。说白了,就是给系统做个全面体检。体检不合格,坚决不让升级流程往下走。
我个人习惯,把这部分代码叫做 PreconditionsChecker。它就像个守门员,把各种风险挡在门外。
17.1 电池电量检查:别让升级变成「砖」
为什么电量检查是第一道关?
你想想看,升级过程中如果突然断电,系统可能处于一个「半升级」状态。bootloader 刷了一半,或者 system 分区写了一半。下次开机,大概率变砖。
我在项目中遇到过,有用户插着充电线升级,但充电线接触不良。电量从 60% 一路掉到 5%,升级还没完成,手机直接黑屏了。嗯,从那以后,我坚持要做「实时电量监控」。
- 最低阈值:我一般设 30%。低于这个值,直接弹窗提示,拒绝升级。
- 安全阈值:30%~50%,允许升级,但会提示「建议充电」。同时后台持续监控电量变化。
- 理想阈值:50% 以上,直接放行。
代码实现上,我们通过 BatteryManager 获取电量。注意,这里有个坑:
// 获取电量百分比
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = context.registerReceiver(null, ifilter);
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
float batteryPct = level * 100 / (float) scale;
// 检查是否在充电
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING
|| status == BatteryManager.BATTERY_STATUS_FULL;
17.2 存储空间检查:给升级包留足「余粮」
升级包本身要占空间,解压出来的文件也要占空间,系统备份还要占空间。这三者加起来,才是你真正需要的空间。
我见过一个案例:升级包 1.5GB,用户手机还剩 2GB 空间。看起来够了吧?结果解压时需要临时文件,加上系统备份,直接撑爆了。升级失败,系统回滚,用户数据差点丢了。
所以,我的计算方式是:
| 项目 | 所需空间 | 说明 |
|---|---|---|
| 升级包本身 | 包大小 × 1.2 | 留 20% 余量,防止碎片化 |
| 解压临时空间 | 包大小 × 2 | OTA 包通常是压缩的,解压后更大 |
| 系统备份空间 | 系统分区大小 × 0.3 | 备份关键分区(boot、system) |
| 用户数据备份 | 用户数据大小 × 0.5 | 视备份策略而定 |
代码里,我习惯这样检查:
// 获取 data 分区可用空间
StatFs stat = new StatFs(Environment.getDataDirectory().getPath());
long availableBytes = stat.getAvailableBlocksLong() * stat.getBlockSizeLong();
// 计算所需空间
long requiredBytes = otaPackageSize * 3 + systemPartitionSize / 3 + userDataSize / 2;
if (availableBytes < requiredBytes) {
// 提示用户清理空间
showStorageWarning(requiredBytes - availableBytes);
return false;
}
/cache 分区。很多 OTA 升级会把临时文件放在 cache 分区。如果 cache 分区满了,升级也会失败。
17.3 用户数据备份策略:给数据上「保险」
升级过程中,最怕的就是数据丢失。虽然现在的 OTA 升级很少会擦除用户数据,但万一呢?
我个人的原则是:宁可备而不用,不可用而不备。
备份策略分三种级别:
17.3.1 轻量级备份:只备份关键配置
适合日常小版本升级。备份内容:
- WiFi 密码、蓝牙配对信息
- 系统设置(亮度、音量、壁纸等)
- 应用列表(不备份应用数据)
// 备份系统设置到 /data/backup/settings_backup.xml
private void backupSystemSettings() {
// 读取 Settings.System、Settings.Secure、Settings.Global
// 序列化为 XML 文件
// 存储到 /data/backup/ 目录
}
17.3.2 中等备份:备份应用数据
适合跨版本升级(比如 Android 12 升到 13)。备份内容:
- 所有用户安装的应用及其数据
- 联系人、短信、通话记录
- 相册、下载文件
android:allowBackup="true",系统不会备份它的数据。我在项目中就踩过这个坑,升级后用户发现某个应用的数据全丢了,后来才发现是应用没开备份权限。
17.3.3 全量备份:整机镜像
适合重大升级或用户主动要求。备份内容:
- 整个
/data分区 - 使用
dd命令或fs_mgr工具 - 备份到外置存储或 OTG 设备
// 全量备份 data 分区(需要 root 权限)
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes("dd if=/dev/block/by-name/userdata of=/sdcard/userdata_backup.img bs=4M\n");
os.writeBytes("exit\n");
os.flush();
17.4 预条件检查的完整流程
说了这么多,我们把这些检查串起来。下面是我常用的流程图:
这个流程看起来简单,但实际落地时,每个环节都有不少细节。我建议你把检查结果都记录到日志里,方便排查问题。
好了,预条件检查和数据备份就聊到这儿。这些代码写起来不难,但考虑周全了,能帮你省掉很多售后麻烦。
公众号:蓝海资料掘金营,微信deep3321