一、问题来源
二、问题优化
一、问题来源
我们都知道Android上如果升级包data区的话,会有解密的过程,这个过程uncryt.cpp中有详细的说明,大致意思就是recovery不能挂载并修改data分区,所以把包放在了dev/block/userdata节点上,并使用block.map文件知名在节点上的存储信息,大部分解密失败的问题在生成block.map时候就失败了
针对常规的解密流程错误我们可以在最初去除,那么针对非常规操作造成的解密失败呢,例如线程中断,强制关机等等,那么首先我们说明下这个问题
在installpackage方法最初,执行了setupBcb方法也就是将包的路径和语言写入到了misc分区,以备重启之后进入recovery的信息,但是如果解密出现问题,还是会重启进入升级,而且升级失败,所以我们要处理的就是写入bcb和解密的先后关系
对于该问题,大致有两种方法
1、失败后不重启 查看代码后,如果修改涉及到的流程较多,代码修改量较大,所以暂时不考虑该方案
2、失败后直接重启,不在recovery报错
二、问题优化
修改代码之前做了几组测试
1、只删除seupBcb代码,重启后会进入recovery,但是相当于按键进入recovery,没有给到需要执行的command
2、只设定重启参数mReason = "userrequested";还是会重启进入reboot正常走升级的流程
根据以上两种测试,如果我们需要判断解密失败后直接重启,以上两个方面都需要考虑到
修改方法一
1、修改./framwork/base/core/java/android/os/RecoverySystem.java
修改clearBcb方法为public,因为我要在shutdown中用到
/**
* Talks to RecoverySystemService via Binder to clear up the BCB.
*
* @hide //加入@hde
*/
public boolean clearBcb() {
try {
return mService.clearBcb();
} catch (RemoteException unused) {
}
return false;
}
2、修改./framwork/base/services/core/java/com/android/server/power/ShutdownThread.java
增加标志位
//by lbb test
private boolean uncrypt_done;
修改uncrypt方法为boolean返回值
//by lbb test
private boolean uncrypt() {
Log.i(TAG, "Calling uncrypt and monitoring the progress...");
//进入方法后赋值为true
uncrypt_done = true;
final RecoverySystem.ProgressListener progressListener =
new RecoverySystem.ProgressListener() {
@Override
public void onProgress(int status) {
if (status >= 0 && status < 100) {
// Scale down to [MOUNT_SERVICE_STOP_PERCENT, 100).
status = (int)(status * (100.0 - MOUNT_SERVICE_STOP_PERCENT) / 100);
status += MOUNT_SERVICE_STOP_PERCENT;
CharSequence msg = mContext.getText(
com.android.internal.R.string.reboot_to_update_package);
sInstance.setRebootProgress(status, msg);
} else if (status == 100) {
CharSequence msg = mContext.getText(
com.android.internal.R.string.reboot_to_update_reboot);
sInstance.setRebootProgress(status, msg);
} else {
// Ignored
}
}
};
final boolean[] done = new boolean[1];
done[0] = false;
Thread t = new Thread() {
@Override
public void run() {
RecoverySystem rs = (RecoverySystem) mContext.getSystemService(
Context.RECOVERY_SERVICE);
String filename = null;
try {
filename = FileUtils.readTextFile(RecoverySystem.UNCRYPT_PACKAGE_FILE, 0, null);
rs.processPackage(mContext, new File(filename), progressListener);
} catch (IOException e) {
//解密失败会抛出异常进入catch方法,这里设定uncry_done为false
uncrypt_done = false;
Log.e(TAG, "Error uncrypting file", e);
//return false;
}
done[0] = true;
}
};
t.start();
Log.i(TAG, "uncrypt_done = " + uncrypt_done);
try {
t.join(MAX_UNCRYPT_WAIT_TIME);
} catch (InterruptedException unused) {
}
if (!done[0]) {
Log.w(TAG, "Timed out waiting for uncrypt.");
final int uncryptTimeoutError = 100;
String timeoutMessage = String.format("uncrypt_time: %d\n" + "uncrypt_error: %d\n",
MAX_UNCRYPT_WAIT_TIME / 1000, uncryptTimeoutError);
try {
FileUtils.stringToFile(RecoverySystem.UNCRYPT_STATUS_FILE, timeoutMessage);
} catch (IOException e) {
uncrypt_done = false;
//return false;
Log.e(TAG, "Failed to write timeout message to uncrypt status", e);
}
}
Log.i(TAG, "uncrypt_done = " + uncrypt_done);
//返回uncrypt_done
return uncrypt_done;
}
修改run方法
/**
* Makes sure we handle the shutdown gracefully.
* Shuts off power regardless of radio state if the allotted time has passed.
*/
public void run() {
......
......
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
// If it's to reboot to install an update and uncrypt hasn't been
// done yet, trigger it now.
//by lbb test
//如果解密成功,继续执行后续的升级流程
if(uncrypt()){
Log.i(TAG, "uncryt succeed");
}else{
//如果解密失败,那么调用clearBcb方法清除misc分区的信息
Log.i(TAG, "uncryt failed,normal reboot");
RecoverySystem rs = (RecoverySystem) mContext.getSystemService(Context.RECOVERY_SERVICE);
try {
rs.clearBcb();
Log.i(TAG, "clearBcb succeed");
//更改mReason为userrequested ,正常reboot的reboot也为该字段
mReason = "userrequested";
}catch (Exception e){
Log.e(TAG, "clearBcb failed");
}
}
}
///M: added for Shutdown Enhancement@{
mShutdownSeqFinish(mContext);
/// @}
shutdownTimingLog.traceEnd(); // SystemServerShutdown
metricEnded(METRIC_SYSTEM_SERVER);
saveMetrics(mReboot, mReason);
// Remaining work will be done by init, including vold shutdown
rebootOrShutdown(mContext, mReboot, mReason);
}
修改方法二
1、修改./framwork/base/core/java/android/os/RecoverySystem.java
修改setupBcb为public
/**
* Talks to RecoverySystemService via Binder to set up the BCB.
*
* @hide
*/
pulic boolean setupBcb(String command) {
try {
return mService.setupBcb(command);
} catch (RemoteException unused) {
}
return false;
}
删除instalpackage中的setupBcb方法
RecoverySystem rs = (RecoverySystem) context.getSystemService(
Context.RECOVERY_SERVICE);
if (!rs.setupBcb(command)) {
throw new IOException("Setup BCB failed");
}
2、修改./framwork/base/services/core/java/com/android/server/power/ShutdownThread.java
uncry_done标志位和uncrypt方法的修改与上述方法相同
修改run方法
/**
* Makes sure we handle the shutdown gracefully.
* Shuts off power regardless of radio state if the allotted time has passed.
*/
public void run() {
......
......
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
// If it's to reboot to install an update and uncrypt hasn't been
// done yet, trigger it now.
//by lbb test
//如果解密成功,继续执行后续的升级流程
if(uncrypt()){
Log.i(TAG, "uncryt succeed");
//如果解密成功,写入bcb信息
RecoverySystem rs = (RecoverySystem) mContext.getSystemService(Context.RECOVERY_SERVICE);
try {
rs.setupBcb();
Log.i(TAG, "setupBcb succeed");
}catch (Exception e){
Log.e(TAG, "setupBcb failed");
}
}else{
//如果解密失败,将reason信息设定为正常restart的值
mReason = "userrequested";
}
}
///M: added for Shutdown Enhancement@{
mShutdownSeqFinish(mContext);
/// @}
shutdownTimingLog.traceEnd(); // SystemServerShutdown
metricEnded(METRIC_SYSTEM_SERVER);
saveMetrics(mReboot, mReason);
// Remaining work will be done by init, including vold shutdown
rebootOrShutdown(mContext, mReboot, mReason);
}
本文探讨了Android设备在升级过程中遇到的解密失败问题,分析了解密流程中可能的中断原因,如线程中断或强制关机。提出了两种解决方案:一是避免解密失败后的重启,但因涉及代码改动较大而暂不考虑;二是直接重启,不在recovery模式中报错,通过调整写入bcb和解密的顺序实现。通过代码修改,确保解密失败时能清除升级信息,避免进入无效的升级流程。
1442

被折叠的 条评论
为什么被折叠?



