Expected 3 arguments but found 2package com.kotei.overseas.navi.update;
import static com.kotei.overseas.navi.security.DecryptUtil.dataVerification;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import java.util.concurrent.Future;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import androidx.annotation.NonNull;
import com.here.sdk.core.engine.SDKNativeEngine;
import com.here.sdk.maploader.MapDownloader;
import com.here.sdk.maploader.MapDownloaderConstructionCallback;
import com.kotei.overseas.navi.business.data.MapDataController;
import com.kotei.overseas.navi.security.DecryptUtil;
import com.kotei.overseas.navi.security.DfCert;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import java.util.stream.Stream;
/**
* USB离线更新系统
*/
public class USBOfflineUpdater {
// 日志标签
private static final String TAG = "USBOfflineUpdater";
// 操作成功状态码
public static final int SUCCESS = 0;
// 错误状态码
public static final int ERROR_NO_USB = 1; // 未检测到USB设备
public static final int ERROR_NO_UPDATE_PACKAGE = 2; // 未找到升级包
public static final int ERROR_BATTERY_LOW = 3; // 电池电量不足
public static final int ERROR_STORAGE_INSUFFICIENT = 4; // 存储空间不足
public static final int ERROR_UPDATE_IN_PROGRESS = 5; // 升级任务冲突
public static final int ERROR_COPY_FAILED = 6; // 文件复制失败
public static final int ERROR_EXTRACT_FAILED = 7; // 解压失败
public static final int ERROR_USER_CANCELED = 8; // 用户取消
public static final int ERROR_UNEXPECTED = 9; // 未预期异常
public static final int ERROR_USB_REMOVED = 10; // USB设备移除
public static final int ERROR_VEHICLE_SHIFTED = 11; // 非P档状态
public static final int ERROR_BATTERY_TOO_LOW = 12; // 电池极低
public static final int ERROR_FILE_VERIFY_FAILED = 13; // 文件校验失败
public static final int ERROR_DECRYPT_OR_SIGN_FAILED = 14; // 解密/验签失败
// 更新阶段常量
private static final int PHASE_IDLE = 0; // 空闲
private static final int PHASE_DETECTING = 1; // 设备检测
private static final int PHASE_CHECKING = 2; // 校验
private static final int PHASE_BACKUP = 3; // 备份
private static final int PHASE_COPYING = 4; // 复制
private static final int PHASE_EXTRACTING = 5; // 解压
private static final int PHASE_CLEANUP = 6; // 清理
private static final int PHASE_ROLLBACK = 7; // 回滚
// 进度权重分配
private static final float BACKUP_WEIGHT = 0.1f; // 备份阶段权重
private static final float PACKAGE_COPY_WEIGHT = 0.29f; // 拷贝阶段权重
private static final float PACKAGE_VERIFY_WEIGHT = 0.31f; // 验签阶段权重
private static final float PACKAGE_EXTRACT_WEIGHT = 0.29f; // 解压阶段权重
private static final float VERIFICATION_WEIGHT = 0.01f; // 校验阶段权重
// 文件名正则表达式
private static final String FILE_NAME_PATTERN = "^KVM_Navi_EU_"
+ "(?<version>\\d{1,3})" // 版本号(1-3位数字)
+ "_"
+ "(?<serial>\\d{1,2})" // 1-2位序列号
+ "(\\.\\w+)?$"; // 可选扩展名
// 当前进度值(0~1)
private float mProgress = 0;
// 单例实例
private static USBOfflineUpdater instance;
// 上下文对象
private final Context context;
// 当前更新任务
private UpdateTask currentTask;
// 更新监听器
private UpdateListener updateListener;
// 原生引擎接口
private SDKNativeEngine sdkNativeEngine;
// 地图数据控制器
private MapDataController mapDataController;
// USB根目录
private File usbRoot;
// 缓存目录(备份文件)
private File cacheDir;
// 存储目录(升级目标)
private File storageDir;
// 暂停状态标志
public boolean isPaused = false;
// 取消状态标志(volatile保证线程可见性)
public volatile boolean isCancelled = false;
// 当前阶段(原子操作)
public final AtomicInteger currentPhase = new AtomicInteger(PHASE_IDLE);
// 最后错误信息
private String lastErrorMessage = "";
// 最低电量阈值(安全)
private static final int MIN_BATTERY_LEVEL = 30;
// 最低电量阈值(严重)
private static final int MIN_BATTERY_LEVEL_CRITICAL = 15;
// 总升级包大小
private long totalUpdateSize = 0;
// 当前升级包大小
private long UpdateSize = 0;
// 已拷贝字节数(原子操作)
private final AtomicLong currentCopiedBytes = new AtomicLong(0);
// 已验签字节数(原子操作)
private final AtomicLong currentVerifiedBytes = new AtomicLong(0);
// 已解压字节数(原子操作)
private final AtomicLong currentExtractedBytes = new AtomicLong(0);
// 备份数据大小
private long backupSize = 0;
// 当前处理的升级包索引
private int currentPackageIndex = 0;
// 总升级包数量
private int totalPackageCount = 0;
// 回滚状态
public boolean isRollingBack = false;
// 回滚总大小
private long rollbackTotalSize = 0;
// 回滚已处理大小
private long rollbackProcessedSize = 0;
// 包级锁对象
private final Object packageLock = new Object();
// 更新成功标志(volatile保证线程可见性)
private volatile boolean updateSuccess = true;
// 下一个待处理包索引
private int nextPackageIndex = 0;
// 主线程Handler
private Handler mainHandler = new Handler(Looper.getMainLooper());
// 包处理完成信号量
private volatile CountDownLatch allPackagesLatch;
// 更新线程池
private volatile ExecutorService updateExecutor;
// 总包大小(原子操作)
private final AtomicLong totalPackageSize = new AtomicLong(0);
// 每个包的最大进度(百分比)
private static final double MAX_PACKAGE_PROGRESS = 17.8;
// 总进度中包处理部分(百分比)
private static final double TOTAL_PACKAGE_PROGRESS = 89.0;
// 包进度映射(线程安全)
private final Map<String, Double> packageProgressMap = new ConcurrentHashMap<>();
// 包总大小映射(线程安全)
private final Map<String, Long> packageTotalSizeMap = new ConcurrentHashMap<>();
// 包阶段映射(线程安全)
private final Map<String, Integer> packageStageMap = new ConcurrentHashMap<>();
// 阶段标识
private static final int STAGE_COPY = 0; // 拷贝阶段
private static final int STAGE_VERIFY = 1; // 验签阶段
private static final int STAGE_EXTRACT_ONLY = 2; // 仅解压阶段
// 解密验签阶段
private static final int PHASE_DECRYPT_VERIFY = 4;
// 仅解压阶段
private static final int PHASE_EXTRACTING_ONLY = 5;
private CountDownLatch verifyLatch; // 解密验签阶段的同步信号量
// 在 USBOfflineUpdater 类中添加缺失的变量
private CountDownLatch backupLatch = new CountDownLatch(1); // 备份任务同步信号量
//-----------------------------zwxend----------------
// USB监听器
private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_MEDIA_MOUNTED.equals(action)) {
File usbPath = new File(intent.getData().getPath());
if (usbPath.exists() && usbPath.canRead()) {
usbRoot = usbPath;
Log.i(TAG, "USB mounted: " + usbRoot.getAbsolutePath());
}
} else if (Intent.ACTION_MEDIA_EJECT.equals(action) ||
Intent.ACTION_MEDIA_UNMOUNTED.equals(action)) {
if (currentTask != null && currentPhase.get() > PHASE_CHECKING) {
cancelUpdate(ERROR_USB_REMOVED, "USB设备被移除");
}
usbRoot = null;
Log.e(TAG, "USB removed");
}
}
};
// // 车辆状态监听器(模拟)
private final BroadcastReceiver vehicleReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if ("com.example.ACTION_SHIFT_CHANGE".equals(intent.getAction())) {
String shift = intent.getStringExtra("shift");
if (!"P".equals(shift) && currentPhase.get() > PHASE_CHECKING) {
// cancelUpdate(ERROR_VEHICLE_SHIFTED, "车辆已退出P挡");
}
}
}
};
// 单例模式
public static synchronized USBOfflineUpdater getInstance(Context context) {
if (instance == null) {
instance = new USBOfflineUpdater(context);
}
return instance;
}
public static synchronized USBOfflineUpdater getInstance() {
return instance;
}
private USBOfflineUpdater(Context context) {
this.context = context.getApplicationContext();
// 初始化SDK
sdkNativeEngine = SDKNativeEngine.getSharedInstance();
mapDataController = MapDataController.getInstance();
try {
DfCert.getInstance().getService();
} catch (Exception e) {
Log.e(TAG, "Exception:" + e.toString());
}
// 初始化目录(默认值)
cacheDir = this.context.getCacheDir();
storageDir = new File(sdkNativeEngine.getOptions().persistentMapStoragePath);
// 注册USB监听器
IntentFilter usbFilter = new IntentFilter();
usbFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
usbFilter.addAction(Intent.ACTION_MEDIA_EJECT);
usbFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
usbFilter.addDataScheme("file");
context.registerReceiver(usbReceiver, usbFilter);
// 注册车辆状态监听器(模拟)
IntentFilter vehicleFilter = new IntentFilter("com.example.ACTION_SHIFT_CHANGE");
context.registerReceiver(vehicleReceiver, vehicleFilter);
//清除数据存储目录下的预留数据
removeLegacy();
}
public void initialization(UpdateListener listener) {
isRollingBack = true;
this.updateListener = listener;
Thread USBOfflineUpdaterInitialization = new Thread(new Runnable() {
@Override
public void run() {
// 启动时检查恢复
checkRecoveryOnStartup();
}
});
USBOfflineUpdaterInitialization.setName("USBOfflineUpdaterInitialization");
USBOfflineUpdaterInitialization.start();
}
// 动态设置目录
public void setDirectories(File usbRoot, File cacheDir, File storageDir) {
if (usbRoot != null) {
this.usbRoot = usbRoot;
}
if (cacheDir != null) {
this.cacheDir = cacheDir;
}
if (storageDir != null) {
this.storageDir = storageDir;
}
}
/**
* 检测升级包
*
* @return 状态码 (SUCCESS 或错误码)
*/
public int detectUpdatePackages() {
// 1. 检测USB是否插入
if (usbRoot == null || !usbRoot.exists() || !usbRoot.isDirectory()) {
return ERROR_NO_USB;
}
File[] tempPackages = usbRoot.listFiles();
// 2. 查找升级包 (命名格式: update_v{版本号}_{日期}.zip)
File[] packages = usbRoot.listFiles(file ->
file.isFile() && file.getName().matches(FILE_NAME_PATTERN)
);
return (packages != null && packages.length > 0) ? SUCCESS : ERROR_NO_UPDATE_PACKAGE;
}
/**
* 环境检测
*
* @return 状态码 (SUCCESS 或错误码)
*/
public int checkEnvironment() {
// 1. 检测电量
int batteryLevel = PowerUtils.getBatteryLevel(context);
if (batteryLevel < MIN_BATTERY_LEVEL) {
return batteryLevel < MIN_BATTERY_LEVEL_CRITICAL ?
ERROR_BATTERY_TOO_LOW : ERROR_BATTERY_LOW;
}
// 2. 检测缓存空间 (需大于15GB)
long requiredSpace = 15L * 1024 * 1024 * 1024; // 15GB
long availableSpace = StorageUtils.getAvailableSpace(cacheDir);
if (availableSpace < requiredSpace) {
Log.e(TAG, "缓存空间剩余:【" + availableSpace + "】");
return ERROR_STORAGE_INSUFFICIENT;
}
return SUCCESS;
}
/**
* 判读是否正在进行离线更新
*/
public boolean isOfflineUpdate() {
return currentTask != null && !currentTask.isCancelled();
}
/**
* 开始更新
*/
public void startUpdate(UpdateListener listener) {
int result = checkEnvironment();
if (result != SUCCESS) {
notifyListener(result, "环境检测不合格");
return;
}
if (isOfflineUpdate()) {
notifyListener(ERROR_UPDATE_IN_PROGRESS, "已有更新任务正在进行");
return;
}
if (isRollingBack) {
notifyListener(ERROR_UPDATE_IN_PROGRESS, "正在进行数据回滚");
return;
}
Log.i(TAG, "检测到更新任务触发,开始进行地图更新");
notifyProgress("开始进行更新");
// 计算总工作量(新增)
calculateTotalWorkload();
this.updateListener = listener;
currentTask = new UpdateTask();
currentTask.execute();
}
// 计算总工作量(新增)
private void calculateTotalWorkload() {
totalUpdateSize = 0;
File[] packages = getUpdatePackages();
totalPackageCount = packages != null ? packages.length : 0;
if (packages != null) {
for (File pkg : packages) {
totalUpdateSize += pkg.length();
}
}
backupSize = estimateBackupSize();
Log.i(TAG, "总工作量计算: 升级包数量=" + totalPackageCount +
", 升级包大小=" + formatSize(totalUpdateSize) +
", 备份大小=" + formatSize(backupSize));
}
// 估算备份大小方法(避免返回0导致除0错误)
private long estimateBackupSize() {
long storageSize = FileUtilszwx.getDirectorySize(storageDir);
long size = (long) (storageSize * 1.2);
return size > 0 ? size : 1; // 确保不为0
}
// 获取更新包(新增)
private File[] getUpdatePackages() {
if (usbRoot == null) return new File[0];
return usbRoot.listFiles(file ->
file.isFile() && file.getName().matches(FILE_NAME_PATTERN)
);
}
// 格式化文件大小(新增)
public static String formatSize(long size) {
if (size < 1024) return size + "B";
else if (size < 1024 * 1024) return String.format("%.1fKB", size / 1024.0);
else if (size < 1024 * 1024 * 1024) return String.format("%.1fMB", size / (1024.0 * 1024));
else return String.format("%.1fGB", size / (1024.0 * 1024 * 1024));
}
/**
* 暂停更新
*/
public void pauseUpdate() {
isPaused = true;
notifyProgress("更新已暂停");
}
/**
* 恢复更新
*/
public void resumeUpdate() {
isPaused = false;
notifyProgress("更新已恢复");
}
/**
* 取消更新
*/
public void cancelUpdate() {
cancelUpdate(ERROR_USER_CANCELED, "用户取消更新");
}
private void cancelUpdate(int errorCode, String message) {
isCancelled = true;
lastErrorMessage = message;
notifyListener(errorCode, message);
}
// 进度通知
private void notifyProgress(String message) {
new Handler(Looper.getMainLooper()).post(() -> {
if (updateListener != null) {
// 计算当前总进度(修改)
float progress = calculateOverallProgress();
updateListener.onProgress(currentPhase.get(), progress, message);
}
});
}
private float calculateOverallProgress() {
if (isRollingBack) {
// 回滚阶段:直接计算回滚进度
if (rollbackTotalSize > 0) {
mProgress = 99;
return mProgress;
}
return 0;
}
if (totalPackageCount == 0 && currentPhase.get() != PHASE_ROLLBACK) return 0;
// 每个包的总权重(拷贝+验签+解压)
// float packageTotalWeight = PACKAGE_COPY_WEIGHT +
// PACKAGE_VERIFY_WEIGHT +
// PACKAGE_EXTRACT_WEIGHT;
float packageTotalWeight = PACKAGE_COPY_WEIGHT + PACKAGE_VERIFY_WEIGHT; // 不再包含解压
//再次确认totalPackageCount是否等于0
if (totalPackageCount == 0) {
throw new IllegalStateException("totalPackageCount should not be 0 here!");
}
// 每个包的阶段权重
float packageCopyWeight = PACKAGE_COPY_WEIGHT / totalPackageCount;
float packageVerifyWeight = PACKAGE_VERIFY_WEIGHT / totalPackageCount;
float packageExtractWeight = PACKAGE_EXTRACT_WEIGHT / totalPackageCount;
switch (currentPhase.get()) {
case PHASE_BACKUP:
if(backupSize > 0) {
mProgress = BACKUP_WEIGHT * (currentCopiedBytes.get() / (float) backupSize);
}else{
mProgress = BACKUP_WEIGHT;
}
if(mProgress > BACKUP_WEIGHT) {
mProgress = BACKUP_WEIGHT;
}
break;
case PHASE_COPYING:
// 基础:备份 + 已完成包的完整进度
float copyBase = BACKUP_WEIGHT +
(packageTotalWeight * currentPackageIndex) / totalPackageCount;
// 增量:当前包拷贝进度
float copyProgress = currentCopiedBytes.get() / (float) UpdateSize;
mProgress = copyBase + packageCopyWeight * copyProgress;
break;
case PHASE_CHECKING:
// 基础:备份 + 已完成包的完整进度 + 当前包拷贝完成
float verifyBase = BACKUP_WEIGHT +
(packageTotalWeight * currentPackageIndex) / totalPackageCount +
packageCopyWeight;
// 增量:当前包验签进度
float verifyProgress = currentVerifiedBytes.get() / (float) UpdateSize;
mProgress = verifyBase + packageVerifyWeight * verifyProgress;
break;
case PHASE_EXTRACTING:
// 修复:添加当前包验签完成
float extractBase = BACKUP_WEIGHT +
(packageTotalWeight * currentPackageIndex) / totalPackageCount +
packageCopyWeight +
packageVerifyWeight; // 添加这行
// 增量:当前包解压进度
float extractProgress = currentExtractedBytes.get() / (float) UpdateSize;
mProgress = extractBase + packageExtractWeight * extractProgress;
break;
case PHASE_DETECTING:
mProgress = BACKUP_WEIGHT + packageTotalWeight +
VERIFICATION_WEIGHT * (currentVerifiedBytes.get() / (float) totalUpdateSize);
break;
case PHASE_CLEANUP:
case PHASE_ROLLBACK:
mProgress = 0.99f;
break;
}
return Math.min(Math.round(mProgress * 10000) / 100.00f, 100.00f);
}
// 结果通知
private void notifyListener(int resultCode, String message) {
new Handler(Looper.getMainLooper()).post(() -> {
if (updateListener != null) {
updateListener.onResult(resultCode, message);
}
});
}
// 获取当前进度百分比
private int getCurrentProgress() {
// 此处可添加子任务进度计算
return (int) mProgress;
}
// =============================== 核心更新逻辑 ===============================
private class UpdateTask extends AsyncTask<Void, Void, Integer> {
private File backupFile;
private File[] updatePackages;
@Override
protected void onPreExecute() {
currentPhase.set(PHASE_DETECTING);
isCancelled = false;
isPaused = false;
currentCopiedBytes.set(0);
currentExtractedBytes.set(0);
mProgress = 0; // 重置进度为0
}
@Override
protected Integer doInBackground(Void... voids) {
try {
// 阶段1: 备份数据
currentPhase.set(PHASE_BACKUP);
notifyProgress("开始备份数据...");
// 创建备份线程池(T1)
ExecutorService backupExecutor = Executors.newSingleThreadExecutor();
Future<Boolean> backupFuture = backupExecutor.submit(() -> performBackup());
// 阶段2a: 拷贝 + 解密验签(TS2a)
ExecutorService serialCopyExecutor = Executors.newSingleThreadExecutor();
ExecutorService parallelVerifyExecutor = Executors.newFixedThreadPool(3);
// 阶段2b: 解压(T2b)
ExecutorService serialExtractExecutor = Executors.newSingleThreadExecutor();
// 等待备份完成
backupLatch.await(); // 等待 T1 完成
boolean backupSuccess = backupFuture.get();
if (!backupSuccess || isCancelled()) {
return ERROR_UNEXPECTED;
}
// 并行处理拷贝 + 解密验签(TS2a)
processUpdatePackagesInParallel(updatePackages, serialCopyExecutor, parallelVerifyExecutor);
// 等待 TS2a 完成
verifyLatch.await(); // 等待所有解密验签完成
// 阶段2b: 解压(T2b)
for (File packageFile : updatePackages) {
if (isCancelled()) break;
serialExtractExecutor.submit(new SerialExtractTask(packageFile));
}
// 关闭解压线程池
serialExtractExecutor.shutdown();
if (!serialExtractExecutor.awaitTermination(1, TimeUnit.HOURS)) {
return ERROR_UNEXPECTED;
}
// 校验
if (!mapDataController.checkInstallationStatus()) {
return ERROR_FILE_VERIFY_FAILED;
}
return SUCCESS;
} catch (Exception e) {
return ERROR_UNEXPECTED;
}
}
@Override
protected void onPostExecute(Integer resultCode) {
if (resultCode == SUCCESS) {
notifyListener(SUCCESS, "更新成功,请重启车机");
currentPhase.set(PHASE_IDLE);
currentTask = null;
} else {
// 只有备份完成时才进行回滚(场景2)
if (backupFile != null && backupFile.exists()) {
// 场景2:进入回滚流程
isRollingBack = true;
currentPhase.set(PHASE_ROLLBACK);
// 先发送回滚进度通知(99%)
notifyProgress("更新失败,正在回滚数据...");
// 保存错误消息,因为回滚完成后还需要使用
final String errorMessage = lastErrorMessage;
// 启动回滚线程
new Thread(new Runnable() {
@Override
public void run() {
try {
// 执行回滚
performRollback(backupFile);
} finally {
// 回滚完成后删除备份
// backupFile.delete();
if (backupFile.exists() && !backupFile.delete()) {
Log.w(TAG, "删除备份文件失败: " + backupFile.getAbsolutePath());
}
if (!isCancelled) {
// 回滚完成后发送最终结果
notifyListener(resultCode, getErrorMessage(resultCode));
}
// 重置状态
currentPhase.set(PHASE_IDLE);
currentTask = null;
isRollingBack = false;
}
}
}).start();
} else {
// 场景1:没有备份文件,直接报告错误
notifyListener(resultCode, lastErrorMessage);
currentPhase.set(PHASE_IDLE);
currentTask = null;
}
}
}
}
// ================== 启动时恢复检查 ==================
private void checkRecoveryOnStartup() {
File backupFile = findLatestBackupFile();
// 存在备份文件说明上次更新中断
if (backupFile != null && backupFile.exists()) {
long fileSize = backupFile.length();
long expectedSize = estimateBackupSize();
// 场景3:备份未完成(文件大小小于预期大小的90%)
if (fileSize < expectedSize * 0.9) {
isRollingBack = true;
Log.i(TAG, "检测到未完成的备份,删除: " + backupFile.getName());
// backupFile.delete();
if (backupFile.exists() && !backupFile.delete()) {
Log.w(TAG, "删除备份文件失败: " + backupFile.getAbsolutePath());
}
return;
}else {
// 场景4:备份已完成,启动回滚
Log.i(TAG, "检测到完整的备份,开始回滚: " + backupFile.getName());
currentPhase.set(PHASE_ROLLBACK);
notifyProgress("检测到未完成更新,正在恢复数据...");
// 执行回滚
performRollback(backupFile);
// 删除备份文件
// backupFile.delete();
if (backupFile.exists() && !backupFile.delete()) {
Log.w(TAG, "删除备份文件失败: " + backupFile.getAbsolutePath());
}
notifyProgress("数据恢复完成");
}
}
isRollingBack = false;
this.updateListener = null;
}
private void checkStoragePerformance() {
long writeSpeed = StorageUtils.measureWriteSpeed(storageDir);
Log.d(TAG, "存储写入速度: " + formatSize(writeSpeed) + "/s");
if (writeSpeed < 50 * 1024 * 1024) { // 低于 50MB/s
Log.w(TAG, "检测到低速存储设备,还原操作可能较慢");
}
}
// 新增回滚方法
private void performRollback(File backupFile) {
try {
// 1. 设置回滚进度为99%
rollbackProcessedSize = backupFile.length() * 99 / 100;
notifyProgress("开始恢复备份...");
// 2. 删除更新后的数据
FileUtilszwx.deleteRecursive(storageDir);
if (!storageDir.mkdirs()) {
Log.w(TAG, "创建存储目录失败");
}
// 3. 恢复备份
rollbackTotalSize = backupFile.length();
rollbackProcessedSize = 0;
boolean restoreSuccess = FileUtilszwx.extractZipWithProgress(
backupFile,
storageDir,
(extracted, total) -> {
rollbackProcessedSize = extracted;
notifyProgress(String.format("恢复备份 %s: %s/%s",
backupFile.getName(),
formatSize(extracted),
formatSize(total)));
}
);
if (!restoreSuccess) {
Log.e(TAG, "备份恢复失败");
}
} catch (Exception e) {
Log.e(TAG, "回滚过程中发生错误", e);
}
}
private File findLatestBackupFile() {
File[] backups = cacheDir.listFiles(file ->
file.isFile() && file.getName().startsWith("backup.zip")
);
if (backups == null || backups.length == 0) {
return null;
}
return backups[0];
}
// 释放资源
public void release() {
try {
context.unregisterReceiver(usbReceiver);
context.unregisterReceiver(vehicleReceiver);
} catch (Exception e) {
Log.w(TAG, "释放资源时出错", e);
}
}
// ================== 接口定义 ==================
public interface UpdateListener {
void onProgress(int phase, float progress, String message);
void onResult(int resultCode, String message);
}
public interface ProgressCallback {
void onProgress(long progress, long total) throws InterruptedException;
}
public File getUsbRoot() {
return usbRoot;
}
public File getCacheDir() {
return cacheDir;
}
public File getStorageDir() {
return storageDir;
}
public String getErrorMessage(int code) {
return switch (code) {
case ERROR_NO_USB -> "未检测到USB设备,请检查连接状态或更换接口";
case ERROR_NO_UPDATE_PACKAGE -> "升级包文件缺失,请确认存储路径";
case ERROR_BATTERY_LOW -> "电池电量不足(需≥20%)";
case ERROR_STORAGE_INSUFFICIENT -> "存储空间不足(需预留500MB以上)";
case ERROR_UPDATE_IN_PROGRESS -> "系统正在执行其他升级任务";
case ERROR_COPY_FAILED -> "文件复制失败,请检查存储权限";
case ERROR_EXTRACT_FAILED -> "升级包解压失败(可能文件损坏)";
case ERROR_USER_CANCELED -> "用户已取消升级操作";
case ERROR_UNEXPECTED -> "发生未预期的系统异常";
case ERROR_USB_REMOVED -> "升级过程中USB设备被移除";
case ERROR_VEHICLE_SHIFTED -> "请将车辆档位切换至P档";
case ERROR_BATTERY_TOO_LOW -> "电池电量极低(需≥10%)";
case ERROR_FILE_VERIFY_FAILED -> "文件校验失败(MD5/SHA256不匹配)";
case ERROR_DECRYPT_OR_SIGN_FAILED -> "文件解密/验签失败";
default -> "未知错误导致更新失败";
};
}
void removeLegacy() {
if (storageDir == null || !storageDir.exists() || !storageDir.isDirectory()) {
return;
}
Pattern pattern = Pattern.compile(FILE_NAME_PATTERN);
File[] files = storageDir.listFiles();
if (files == null) return;
for (File file : files) {
if (file.isFile() && pattern.matcher(file.getName()).matches()) {
// 删除匹配的文件
try {
Files.deleteIfExists(file.toPath());
} catch (IOException | SecurityException e) {
// 处理异常(记录日志等)
}
}
}
// 删除sign文件夹(如果存在)
Path signDir = Paths.get(storageDir.getAbsolutePath(), "sign");
if (Files.exists(signDir)) {
try {
// 递归删除整个目录
deleteDirectoryRecursively(signDir);
} catch (IOException | SecurityException e) {
// 处理异常
}
}
}
private void deleteDirectoryRecursively(Path path) throws IOException {
if (Files.isDirectory(path)) {
// 使用 try-with-resources 确保 Stream 关闭
try (Stream<Path> children = Files.list(path)) {
children.forEach(child -> {
try {
deleteDirectoryRecursively(child);
} catch (IOException e) {
// 处理子项删除异常
throw new UncheckedIOException(e); // 转换为 RuntimeException 以便在 Stream 中抛出
}
});
} catch (UncheckedIOException e) {
// 重新抛出原始 IOException
throw e.getCause();
}
}
// 删除空目录或文件
Files.deleteIfExists(path);
}
//-----------------------------------多线程私有类------------------------
/**
* 并行更新管道,用于并发处理多个升级包
*/
/**
* 并行更新管道,用于并发处理多个升级包
*/
/**
* 并行处理升级包
*/
private void shutdownUpdateExecutor() {
if (updateExecutor != null && !updateExecutor.isShutdown()) {
updateExecutor.shutdownNow();
}
}
private boolean performBackup() {
try {
File backupFile = new File(cacheDir, "backup.zip");
if (backupFile.exists() && !backupFile.delete()) {
Log.w(TAG, "删除旧备份文件失败");
}
backupSize = estimateBackupSize();
Log.i(TAG, "需要备份的数据大小: [" + formatSize(backupSize) + "]");
try {
boolean result = FileUtilszwx.compressDirectoryWithProgress(
storageDir,
backupFile,
(copied, total) -> {
currentCopiedBytes.set(copied);
notifyProgress("备份数据: " + USBOfflineUpdater.formatSize(copied) + "/" + USBOfflineUpdater.formatSize(total));
if (isCancelled) {
throw new RuntimeException(new InterruptedException("用户取消备份"));
}
}
);
return result;
} catch (RuntimeException e) {
if (e.getCause() instanceof InterruptedException) {
Log.d(TAG, "备份任务被用户取消");
return false;
} else {
Log.e(TAG, "未知异常", e);
throw e;
}
}
} catch (Exception e) {
Log.e(TAG, "备份失败", e);
return false;
} finally {
backupLatch.countDown(); // 无论成功与否,触发备份完成信号
}}
private void updateProgress(String format, String packageName, long processed, long total) {
String message = String.format(format, packageName,
formatSize(processed),
formatSize(total));
mainHandler.post(() -> notifyProgress(message));
}
private void processUpdatePackagesInParallel(
File[] packages,
ExecutorService serialCopyExecutor,
ExecutorService parallelVerifyExecutor) {
if (packages == null || packages.length == 0) {
notifyListener(SUCCESS, "无升级包");
return;
}
// 初始化每个包的进度信息
for (File packageFile : packages) {
packageTotalSizeMap.put(packageFile.getName(), packageFile.length());
packageProgressMap.put(packageFile.getName(), 0.0);
packageStageMap.put(packageFile.getName(), STAGE_COPY);
}
allPackagesLatch = new CountDownLatch(packages.length);
verifyLatch = new CountDownLatch(packages.length); // 重新初始化
// 串行提交拷贝任务
for (File packageFile : packages) {
if (isCancelled) break;
serialCopyExecutor.submit(new SerialCopyTask(packageFile, parallelVerifyExecutor));
}
// 关闭线程池后触发 verifyLatch
serialCopyExecutor.shutdown();
parallelVerifyExecutor.shutdown();
new Thread(() -> {
try {
serialCopyExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
parallelVerifyExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
verifyLatch.countDown(); // 触发 TS2a 完成信号
} catch (InterruptedException e) {
Log.e(TAG, "线程池关闭异常", e);
}
}).start();
}
/**
* 更新包的进度,并限制最大为 MAX_PACKAGE_PROGRESS
*/
private void updatePackageProgress(String packageName, long processed, long total, int stage) {
double stageRatio = (double) processed / total;
double progress = 0.0;
switch (stage) {
case STAGE_COPY:
progress = MAX_PACKAGE_PROGRESS / 3 * stageRatio;
break;
case STAGE_VERIFY:
progress = MAX_PACKAGE_PROGRESS / 3 + MAX_PACKAGE_PROGRESS / 3 * stageRatio;
break;
case STAGE_EXTRACT_ONLY:
progress = MAX_PACKAGE_PROGRESS / 3 * 2 + MAX_PACKAGE_PROGRESS / 3 * stageRatio;
break;
}
packageProgressMap.put(packageName, Math.min(progress, MAX_PACKAGE_PROGRESS));
}
/**
* 串行拷贝任务
*/
private class SerialCopyTask implements Runnable {
private final File packageFile;
private final ExecutorService parallelExecutor;
private final File destFile; // 添加 destFile
public SerialCopyTask(File packageFile, File destFile, ExecutorService parallelExecutor) {
this.packageFile = packageFile;
this.destFile = destFile;
this.parallelExecutor = parallelExecutor;
}
@Override
public void run() {
if (isCancelled) {
allPackagesLatch.countDown();
return;
}
String packageName = packageFile.getName();
// 阶段2: 解密验签
try {
boolean verifyResult = dataVerification(destFile.getAbsolutePath(), new DecryptUtil.ProgressCallback() {
@Override
public void onProgress(long processed, long total) {
packageStageMap.put(packageName, STAGE_VERIFY);
updatePackageProgress(packageName, processed, total, STAGE_VERIFY);
updateProgress("解密验签 %s: %s/%s", packageName, processed, total);
}
});
if (!verifyResult || isCancelled) {
updateSuccess = false;
allPackagesLatch.countDown();
return;
}
} catch (Exception e) {
Log.e(TAG, "解密验签失败", e);
updateSuccess = false;
allPackagesLatch.countDown();
return;
}
// 解密验签完成,触发 verifyLatch
verifyLatch.countDown();
allPackagesLatch.countDown();
}
/**
* 并行处理任务(解密验签、解压)
*/
private class PostCopyProcessingTask implements Runnable {
private final File packageFile;
private final File destFile;
public PostCopyProcessingTask(File packageFile, File destFile) {
this.packageFile = packageFile;
this.destFile = destFile;
}
@Override
public void run() {
if (isCancelled) {
allPackagesLatch.countDown();
return;
}
String packageName = packageFile.getName();
// 阶段2: 解密验签
try {
boolean verifyResult = dataVerification(destFile.getAbsolutePath(), new DecryptUtil.ProgressCallback() {
@Override
public void onProgress(long processed, long total) {
packageStageMap.put(packageName, STAGE_VERIFY);
updatePackageProgress(packageName, processed, total, STAGE_VERIFY);
updateProgress("解密验签 %s: %s/%s", packageName, processed, total);
}
});
if (!verifyResult || isCancelled) {
updateSuccess = false;
allPackagesLatch.countDown();
return;
}
} catch (Exception e) {
Log.e(TAG, "解密验签失败", e);
updateSuccess = false;
allPackagesLatch.countDown();
return;
}
// 不执行解压,只更新状态
packageProgressMap.put(packageName, MAX_PACKAGE_PROGRESS * 2 / 3); // 解密验签完成
allPackagesLatch.countDown();
}
}
}
private class SerialExtractTask implements Runnable {
private final File packageFile;
public SerialExtractTask(File packageFile) {
this.packageFile = packageFile;
}
@Override
public void run() {
if (isCancelled) {
allPackagesLatch.countDown();
return;
}
String packageName = packageFile.getName();
File destFile = new File(storageDir, packageName);
// 阶段3: 解压
try {
boolean extractResult = FileUtilszwx.extractZipWithProgress(destFile, storageDir, (extracted, total) -> {
packageStageMap.put(packageName, STAGE_EXTRACT_ONLY);
updatePackageProgress(packageName, extracted, total, STAGE_EXTRACT_ONLY);
updateProgress("解压 %s: %s/%s", packageName, extracted, total);
});
if (!extractResult || isCancelled) {
updateSuccess = false;
allPackagesLatch.countDown();
return;
}
} catch (Exception e) {
Log.e(TAG, "解压失败", e);
updateSuccess = false;
allPackagesLatch.countDown();
return;
}
// 删除升级包
if (!destFile.delete()) {
Log.w(TAG, "删除升级包失败: " + destFile.getName());
}
// 最终进度设为最大值
packageProgressMap.put(packageName, MAX_PACKAGE_PROGRESS);
allPackagesLatch.countDown(); // 任务完成
}
}
}
最新发布