一、问题来源
二、问题优化
一、问题来源
我们都知道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); }