(一)、 在进行详细流程分析之前,先看一下几个重要概念:
一、Recovery的工作需要整个软件平台的配合,从架构角度看,有三个部分:
1、Main system:用boot.img启动的Linux系统,Android的正常工作模式。
2、Recovery:用recovery.img启动的Linux系统,只要是运行Recovery程序。
3、Bootloader:除了加载、启动系统,还会通过读取flash的MISC分区获取来自Main system和Recovery的消息,并以此觉得做何种操作。
在Recovery的工作流程中,上述三个实体的通信是必不可少的。
二、通信接口
1、BCB(bootloader control block)
Bootloader和Recovery模块以及主系统之间的通信是通过系统的misc分区来完成的,描述misc分区的数据结构是bootloader_message,定义如下:
struct bootloader_message {
char command[32];
char status[32];
char recovery[768];
// The 'recovery' field used to be 1024 bytes. It has only ever
// been used to store the recovery command line, so 768 bytes
// should be plenty. We carve off the last 256 bytes to store the
// stage string (for multistage packages) and possible future
// expansion.
char stage[32];
char reserved[224];
};
command:command字段中存储的是命令,当想要重启进入Recovery模式,或升级radio/bootloader firmware时,会更新这个字段(如果它的值是“boot-recovery”,系统进入Recovery模式;如果它的值是“update-radio”或“update-hboot”,系统进入更新firmware模式,这个更新过程由bootloader完成;如果command中的值为null,则进入主系统,正常启动);当firmware更新完毕,为了启动后进入Recovery做最终的清除,bootloader还会修改它。
status:status字段存储的是更新的结果。update-radio或update-hboot完成后,由Recovery或Bootloader将更新结果写入到这个字段中。
recovery:recovery字段存放的是recovery模块的启动参数。仅被Main system写入,用于向Recovery发送消息,必须以“recovery\n”开头,否则这个字段中的所有内容会被忽略。这一项的内容中“recovery/\n”以后的部分,是/cache/recovery/command支持的命令,可以认为这是在Recovery操作过程中,对命令操作的备份。Recovery也会更新这个域的信息,执行某操作前把该操作命令写到recovery域,并更新command域,操作完成后再清空recovery域及command域,这样在进入Main system之前,就能确保操作被执行。
(二)详细流程分析
一、入口流程分析
1、在MasterClearConfirm.java(/packages/apps/settings/src/com/android/settings/MasterClearConfirm.java)中显示恢复出厂提示和对应button,点击button后调用button的click方法。如果选中了mEraseSdCard(格式化SD卡),则启动ExternalStorageFormatter的服务;否则发送Intent.ACTION_MASTER_CLEAR广播。
private void doMasterClear() {
if (mEraseSdCard) {
Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
intent.putExtra(Intent.EXTRA_REASON, "MasterClearConfirm");
intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
getActivity().startService(intent);
} else {
Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_REASON, "MasterClearConfirm");
getActivity().sendBroadcast(intent);
// Intent handling is asynchronous -- assume it will happen soon.
}
}
2、定位到注册改广播的地方,/frameworks/base/core/res/AndroidMenifest.xml中注册了改广播接收器。
<receiver android:name="com.android.server.MasterClearReceiver"
android:permission="android.permission.MASTER_CLEAR">
<intent-filter
android:priority="100" >
<!-- For Checkin, Settings, etc.: action=MASTER_CLEAR -->
<action android:name="android.intent.action.MASTER_CLEAR" />
<!-- MCS always uses REMOTE_INTENT: category=MASTER_CLEAR -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="android.intent.category.MASTER_CLEAR" />
</intent-filter>
</receiver>
3、对应的在MasterClearReceiver(\frameworks\base\services\core\java\com\android\server)会接受此广播,在onReceive()方法中会调用RecoverySystem.rebootWipeUserData()方法,并传递三个参数:context;shutdown=false;reason=“MasterClearConfirm”。
@Override
public void onReceive(final Context context, final Intent intent) {
if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
if (!"google.com".equals(intent.getStringExtra("from"))) {
Slog.w(TAG, "Ignoring master clear request -- not from trusted server.");
return;
}
}
final boolean shutdown = intent.getBooleanExtra("shutdown", false);
final String reason = intent.getStringExtra(Intent.EXTRA_REASON);//"MasterClearConfirm"
Slog.w(TAG, "!!! FACTORY RESET !!!");
// The reboot call is blocking, so we need to do it on another thread.
Thread thr = new Thread("Reboot") {
@Override
public void run() {
try {
RecoverySystem.rebootWipeUserData(context, shutdown, reason);//shutdown=false;reason="MasterClearConfirm"
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();
}
二、应用层流程分析
设置模块中恢复出厂设置,不管是否删除SD卡,最终都会执行如下两步:
1、 往/cache/recovery/command文件中写入命令字段
2、 重启系统,进入recovery模式
具体可参考framework/base/core/java/android/os/RecoverySystem.java文件,代码片段如下:
/**
* 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.
*重启设备并且擦除用户data和cache分区;难免有些用词不当,因为system分区没有回复到出厂状态。
* @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.
* true,擦除完成后关闭设备;否则重新引导回正常系统;
* @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.
* 如果当前用户不允许擦除数据,抛出SecurityException。
* @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);//发送广播:android.intent.action.MASTER_CLEAR_NOTIFICATION,通知所有接收端处理相关行为
// Block until the ordered broa