MasterClearReceiver接收广播android.intent.action.MASTER_CLEAR,创建一个县城作一下处理
Thread thr = new Thread("Reboot") {
@Override
public void run() {
try {
RecoverySystem.rebootWipeUserData(context, shutdown, reason);
Log.wtf(TAG, "Still running after master clear?!");
} catch (IOException e) {
Slog.e(TAG, "Can't perform master clear/factory reset", e);
} catch (SecurityException e) {
Slog.e(TAG, "Can't perform master clear/factory reset", e);
}
}
};
thr.start();
RecoverySystem 来重启,启动擦除用户数据的操作
/**
* Reboots the device and wipes the user data and cache
* partitions. This is sometimes called a "factory reset", which
* is something of a misnomer because the system partition is not
* restored to its factory state. Requires the
* {@link android.Manifest.permission#REBOOT} permission.
*
* @param context the Context to use
* @param shutdown if true, the device will be powered down after
* the wipe completes, rather than being rebooted
* back to the regular system.
*
* @throws IOException if writing the recovery command file
* fails, or if the reboot itself fails.
* @throws SecurityException if the current user is not allowed to wipe data.
*
* @hide
*/
public static void rebootWipeUserData(Context context, boolean shutdown, String reason)
throws IOException {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
if (um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {
throw new SecurityException("Wiping data is not allowed for this user.");
}
final ConditionVariable condition = new ConditionVariable();
Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
context.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
android.Manifest.permission.MASTER_CLEAR,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
condition.open();
}
}, null, 0, null, null);
// Block until the ordered broadcast has completed.
condition.block();
String shutdownArg = null;
if (shutdown) {
shutdownArg = "--shutdown_after";
}
String reasonArg = null;
if (!TextUtils.isEmpty(reason)) {
reasonArg = "--reason=" + sanitizeArg(reason);
}
final String localeArg = "--locale=" + Locale.getDefault().toString();
bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);
}
我们可以注意到在启动bootCommand传递命令时,封装参数 --wipe_data , --locale , 这些命令我们可以在查看recovery log ( /cache/recovery/*.log )信息时看到
/**
* Reboot into the recovery system with the supplied argument.
* @param args to pass to the recovery utility.
* @throws IOException if something goes wrong.
*/
private static void bootCommand(Context context, String... args) throws IOException {
RECOVERY_DIR.mkdirs(); // In case we need it
COMMAND_FILE.delete(); // In case it's not writable
LOG_FILE.delete();
FileWriter command = new FileWriter(COMMAND_FILE);
try {
for (String arg : args) {
if (!TextUtils.isEmpty(arg)) {
// MStar Android Patch Begin
String cmd = arg;
String label = null;
String uuid = null;
if (cmd.startsWith("--update_package")) {
cmd = arg.substring(17, 23);
if (cmd.equals("/cache")) {
command.write("--uuid=mstar-cache");
command.write("\n");
command.write("--label=mstar-cache");
command.write("\n");
} else {
cmd = arg.substring(17, 28);
if (cmd.equals("/mnt/usb/sd")) {
cmd = arg.substring(17, 30);
uuid = "--uuid=" + getVolumeUUID(cmd).toString();
label = "--label=" + getVolumeLabel(cmd).toString();
command.write(uuid);
command.write("\n");
command.write(label);
command.write("\n");
} else {
if (cmd.equals("/mnt/sdcard")) {
uuid = "--uuid=" + getVolumeUUID(cmd).toString();
label = "--label=" + getVolumeLabel(cmd).toString();
command.write(uuid);
command.write("\n");
command.write(label);
command.write("\n");
} else {
cmd = arg.substring(17, 32);
if (cmd.equals("/mnt/usb/mmcblk")) {
cmd = arg.substring(17, 35);
uuid = "--uuid=" + getVolumeUUID(cmd).toString();
label = "--label=" + getVolumeLabel(cmd).toString();
command.write(uuid);
command.write("\n");
command.write(label);
command.write("\n");
}
}
}
}
}
// MStar Android Patch End
command.write(arg);
command.write("\n");
}
}
} finally {
command.close();
}
// Having written the command file, go ahead and reboot
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
pm.reboot(PowerManager.REBOOT_RECOVERY);
throw new IOException("Reboot failed (no permissions?)");
}
从以上代码分析,bootCommand 主要工作就是重启进入recovery,此处可以看到COMMAND_FILE 就是文件 “ /cache/recovery/command " , 将上面封装的参数信息
// Having written the command file, go ahead and reboot
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
pm.reboot(PowerManager.REBOOT_RECOVERY);
/**
* Reboot the device. Will not return if the reboot is successful.
*
* Requires the {@link android.Manifest.permission#REBOOT} permission.
*
*
* @param reason code to pass to the kernel (e.g., "recovery") to
* request special boot modes, or null.
*/
public void reboot(String reason) {
try {
mService.reboot(false, reason, true);
} catch (RemoteException e) {
}
}
最后又进入PowerManagerService 的reboot函数
/**
* Reboots the device.
*
* @param confirm If true, shows a reboot confirmation dialog.
* @param reason The reason for the reboot, or null if none.
* @param wait If true, this call waits for the reboot to complete and does not return.
*/
@Override // Binder call
public void reboot(boolean confirm, String reason, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
if (PowerManager.REBOOT_RECOVERY.equals(reason)) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
}
final long ident = Binder.clearCallingIdentity();
try {
shutdownOrRebootInternal(false, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
接着进入shutdownOrRebootInternal
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) {
}
}
}
}
}
ShutdownThread来负责重启动作
/**
* Request a clean shutdown, waiting for subsystems to clean up their
* state etc. Must be called from a Looper thread in which its UI
* is shown.
*
* @param context Context used to display the shutdown progress dialog.
* @param reason code to pass to the kernel (e.g. "recovery"), or null.
* @param confirm true if user confirmation is needed before shutting down.
*/
public static void reboot(final Context context, String reason, boolean confirm) {
mReboot = true;
mRebootSafeMode = false;
mRebootReason = reason;
shutdownInner(context, confirm);
}
static void shutdownInner(final Context context, boolean confirm) {
// ensure that only one thread is trying to power down.
// any additional calls are just returned
synchronized (sIsStartedGuard) {
if (sIsStarted) {
Log.d(TAG, "Request to shutdown already running, returning.");
return;
}
}
final int longPressBehavior = context.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnPowerBehavior);
final int resourceId = mRebootSafeMode
? com.android.internal.R.string.reboot_safemode_confirm
: (longPressBehavior == 2
? com.android.internal.R.string.shutdown_confirm_question
: com.android.internal.R.string.shutdown_confirm);
Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
if (confirm) {
final CloseDialogReceiver closer = new CloseDialogReceiver(context);
if (sConfirmDialog != null) {
sConfirmDialog.dismiss();
}
sConfirmDialog = new AlertDialog.Builder(context)
.setTitle(mRebootSafeMode
? com.android.internal.R.string.reboot_safemode_title
: com.android.internal.R.string.power_off)
.setMessage(resourceId)
.setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
beginShutdownSequence(context);
}
})
.setNegativeButton(com.android.internal.R.string.no, null)
.create();
closer.dialog = sConfirmDialog;
sConfirmDialog.setOnDismissListener(closer);
sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
sConfirmDialog.show();
} else {
beginShutdownSequence(context);
}
}
beginShutdownSequence进入主要的关机流程, 接着启动ShutdownThread.run() , 发送光机广播,关闭核心服务,最后进入rebootOrShutdown重启。