File file = new File(Environment.getExternalStorageDirectory() + "/dload/update.zip");
if (file == null || !file.exists()) {
showToast(R.string.no_update_file);
return;
}
//参数拼接,该参数最终会写入BCB,也就是说设备重启进入Recovery模式后,Recovery.cpp将会解析该参数,并且根据参数做出操作,它将会被传入到bootcommand(context,arg)函数中去。
String arg = "--update_package=" + filename +
"\n--locale=" + Locale.getDefault().toString();
bootCommand(context, arg);
}
4.下面是对bootCommand进行分析。
private static void bootCommand(Context context, String arg) throws IOException {
RECOVERY_DIR.mkdirs();
// 创建/cache/recovery目录
COMMAND_FILE.delete();
// 删除command文件,进行初始化
LOG_FILE.delete();
//删除log文件,进行初始化
Log.d(TAG,"Preapre to write command: " + arg +"\n");
WriteByFdSync(COMMAND_FILE,arg);
//将参数写入到command文件中
Log.d(TAG,"Success to write command: " + arg +"\n");
Log.d(TAG,"Current build type is: " + Build.TYPE +"\n");
ReadInAndPrint(COMMAND_FILE);
//读取command文件,并打印log
// Having written the command file, go ahead and reboot
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
//从系统服务中获得PowerManager实例
pm.
reboot("recovery");
//重启
Log.d(TAG,"!!! pm.reboot failed !!!\n");
throw new IOException("Reboot failed (no permissions?)");
}
下面的方法调用流程为PowerManager:reboot("recovery")-->PowerManagerService:reboot(reason)
-->PowerManagerService:shtudownOrRebootInternal(false,confirm,reason,wait)
-->PowerManagerService:shutdownOrRebootInternal(...)
-->ShutdownThread:reboot(mContext, reason, confirm);
-->ShutdownThread:run():running()......
@Override // Binder call
public void
reboot(boolean confirm, String reason, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
Slog.i(TAG, "reboot call pid: " + Binder.getCallingPid() + " uid: " + Binder.getCallingUid());
final long ident = Binder.clearCallingIdentity();
try {
shutdownOrRebootInternal(false, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void
shutdownOrRebootInternal(final boolean shutdown, final boolean confirm,
final String reason, boolean wait) {
if (mHandler == null || !mSystemReady) {
throw new IllegalStateException("Too early to call shutdown() or reboot()");
}
Runnable runnable = new Runnable() {
@Override
public void run() {
synchronized (this) {
if (shutdown) {
ShutdownThread.shutdown(mContext, confirm);
} else {
ShutdownThread.reboot(mContext, reason, confirm);
}
}
}
};
// ShutdownThread must run on a looper capable of displaying the UI.
Message msg = Message.obtain(mHandler, runnable);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
// PowerManager.reboot() is documented not to return so just wait for the inevitable.
if (wait) {
synchronized (runnable) {
while (true) {
try {
runnable.wait();
} catch (InterruptedException e) {
}
}
}
}
}
public static void
reboot(final Context context, String reason, boolean confirm) {
mReboot = true;
mRebootSafeMode = false;
mRebootReason = reason;
Log.d(TAG, "reboot");
if (mSpew) {
StackTraceElement[] stack = new Throwable().getStackTrace();
for (StackTraceElement element : stack)
{
Log.d(TAG, " |----" + element.toString());
}
}
shutdownInner(context, confirm);
}
这里在run方法下的,running方法中将重启原因写入系统属性文件中去。
。。。。。。
{
String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
}
。。。。。。
最后,重启设备。