原文地址:http://blog.csdn.net/otaku_627/article/details/53899346
点击Settings应用中的恢复出厂设置按钮后流程分析:
先使用grep命令搜索"恢复出厂设置"字符串,找到相应的布局文件:
packages/apps/Settings/res/xml/privacy_settings.xml
- <PreferenceScreen
- android:key="factory_reset"
- android:title="@string/master_clear_title"
- settings:keywords="@string/keywords_factory_data_reset"
- android:fragment="com.android.settings.MasterClear" />
在这个节点下我们可以看到这么一句话:
- android:fragment="com.android.settings.MasterClear"
这句话表示当点击"恢复出厂设置"这个item后,会直接跳转到MasterClear.java这个Fragment子类内:
先来看onCreateView()方法,这个方法是来加载布局文件的:
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- if (!Process.myUserHandle().isOwner()
- || UserManager.get(getActivity()).hasUserRestriction(
- UserManager.DISALLOW_FACTORY_RESET)) {
- return inflater.inflate(R.layout.master_clear_disallowed_screen, null);
- }
-
- mContentView = inflater.inflate(R.layout.master_clear, null);
-
- establishInitialState();
- return mContentView;
- }
判断用户是否具有"恢复出厂设置"的权限,根据判断结果来加载布局;由于分析的是"恢复出厂设置"流程,所有直接默认它加载的是master_clear.xml布局。
接下来再来看establishInitialState()方法,这个方法主要是作为初始化布局控件并未其设置相应的点击事件的作用;
-
-
-
-
-
-
-
-
-
-
-
-
- private void establishInitialState() {
- mInitiateButton = (Button) mContentView.findViewById(R.id.initiate_master_clear);
- mInitiateButton.setOnClickListener(mInitiateListener);
- mExternalStorageContainer = mContentView.findViewById(R.id.erase_external_container);
- mExternalStorage = (CheckBox) mContentView.findViewById(R.id.erase_external);
-
-
-
-
-
-
-
-
- boolean isExtStorageEmulated = false;
- StorageHelpUtil mStorageHelpUtil = new StorageHelpUtil();
- if (mStorageHelpUtil.getSdCardPath(getActivity()) != null) {
- isExtStorageEmulated = true;
- }
- if (isExtStorageEmulated) {
- mExternalStorageContainer.setVisibility(View.VISIBLE);
-
- final View externalOption = mContentView.findViewById(R.id.erase_external_option_text);
- externalOption.setVisibility(View.VISIBLE);
-
- final View externalAlsoErased = mContentView.findViewById(R.id.also_erases_external);
- externalAlsoErased.setVisibility(View.VISIBLE);
-
-
-
- mExternalStorage.setChecked(!isExtStorageEmulated);
- } else {
- mExternalStorageContainer.setVisibility(View.GONE);
- final View externalOption = mContentView.findViewById(R.id.erase_external_option_text);
- externalOption.setVisibility(View.GONE);
- mExternalStorageContainer.setOnClickListener(new View.OnClickListener() {
-
- @Override
- public void onClick(View v) {
- mExternalStorage.toggle();
- }
- });
- }
-
- final UserManager um = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
- loadAccountList(um);
- StringBuffer contentDescription = new StringBuffer();
- View masterClearContainer = mContentView.findViewById(R.id.master_clear_container);
- getContentDescription(masterClearContainer, contentDescription);
- masterClearContainer.setContentDescription(contentDescription);
- }
1、初始化"恢复出厂设置"按钮并未其设置点击事件监听mInitiateListener;
2、判断是否插入SDcard,如果插入则显示是否清空SDcard的提醒消息,实例化选择框CheckBox并设置点击事件;
3、加载用户列表,loadAccountList();
4、实例化提醒信息区域,并显示提醒信息到界面上;
接下来再来看mInitiateListener监听器:
-
-
-
-
-
- private final Button.OnClickListener mInitiateListener = new Button.OnClickListener() {
-
- public void onClick(View v) {
- if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
- Intent intent = new Intent("android.settings.PASSWORD_MANAGER");
- startActivityForResult(intent,PASSWORD_MANAGER);
- }
- }
- };
startActivityForResult()方法进入密码界面,并返回结果,直接来看onActivityResult()方法:
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
-
- if (requestCode != KEYGUARD_REQUEST && requestCode != PASSWORD_MANAGER) {
- return;
- } else if (requestCode == PASSWORD_MANAGER) {
- if (resultCode == Activity.RESULT_OK) {
- validatePassword = data.getExtras().getBoolean("password");
- if (validatePassword) {
- showFinalConfirmation();
- }
- }
- return;
- }
-
-
-
- if (resultCode == Activity.RESULT_OK) {
- showFinalConfirmation();
- } else {
- establishInitialState();
- }
- }
如果密码确认,调用showFinalConfirmation()方法:
- private void showFinalConfirmation() {
- Bundle args = new Bundle();
- args.putBoolean(ERASE_EXTERNAL_EXTRA, mExternalStorage.isChecked());
- ((SettingsActivity) getActivity()).startPreferencePanel(MasterClearConfirm.class.getName(),
- args, R.string.master_clear_confirm_title, null, null, 0);
- }
进入MasterClearConfirm.java内,并传入是否勾选清除sd卡数据的参数;
MasterClearConfirm.java类是用来确认是否开始"恢复出厂设置",在这个类里面我们只需要关心最重要的doMasterClear()方法即可
- private void doMasterClear() {
- Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- intent.putExtra(Intent.EXTRA_REASON, "MasterClearConfirm");
- intent.putExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, mEraseSdCard);
- getActivity().sendBroadcast(intent);
-
- }
这个方法主要是用来发送广播,通知android系统开始"恢复出厂设置",最终的接收方法广播的地方是在
frameworks/base/services/core/java/com/android/server/MasterClearReceiver.java类里面;
onReceiver()方法:
- @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);
- final boolean wipeExternalStorage = intent.getBooleanExtra(
- Intent.EXTRA_WIPE_EXTERNAL_STORAGE, false);
-
- Slog.w(TAG, "!!! FACTORY RESET !!!");
-
- 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);
- }
- }
- };
- if (wipeExternalStorage) {
-
- new WipeAdoptableDisksTask(context, thr).execute();
- } else {
- thr.start();
- }
- }
通过对比发送广播的地方,只需要关心两个参数reason和wipeExternalStorage;
1、wipeExternalStorage为true时,表示需要清除sdcard的数据;开启一个异步任务:
- new WipeAdoptableDisksTask(context, thr).execute();
- private class WipeAdoptableDisksTask extends AsyncTask<Void, Void, Void> {
- private final Thread mChainedTask;
- private final Context mContext;
- private final ProgressDialog mProgressDialog;
-
- public WipeAdoptableDisksTask(Context context, Thread chainedTask) {
- mContext = context;
- mChainedTask = chainedTask;
- mProgressDialog = new ProgressDialog(context);
- }
-
- @Override
- protected void onPreExecute() {
- mProgressDialog.setIndeterminate(true);
- mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
- mProgressDialog.setMessage(mContext.getText(R.string.progress_erasing));
- mProgressDialog.show();
- }
-
- @Override
- protected Void doInBackground(Void... params) {
- Slog.w(TAG, "Wiping adoptable disks");
- StorageManager sm = (StorageManager) mContext.getSystemService(
- Context.STORAGE_SERVICE);
- sm.wipeAdoptableDisks();
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- mProgressDialog.dismiss();
- mChainedTask.start();
- }
-
- }
1)首先执行onPreExecute()方法,此时是在UI Thread内;设置Dialog,提醒用户;
2)执行doInBackground()方法,这个方法一般是用来执行耗时操作;使用StorageManager去清除sdcard内容;
3)最后执行onPostExecute()方法,这个方法是当我们的异步任务执行完之后,就会将结果返回给这个方法;开启一个thr线程,这个线程也是wipeExternalStorage为false需要执行的,后面一起分析。
2、wipeExternalStorage为false时,表示只需要清除用户数据;此时只要需要开启执行thr线程即可;
- 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);
- }
- }
- };
调用RecoverySystem.java的rebootWipeUserData()方法:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 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);
-
-
- 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);
- }
1、查看当前用户是否有权限清除数据;
2、发送有序广播并中断线程,直到有序广播完成;
3、封装命令参数,执行bootCommand()方法;
-
-
-
-
-
- private static void bootCommand(Context context, String... args) throws IOException {
- RECOVERY_DIR.mkdirs();
- COMMAND_FILE.delete();
- LOG_FILE.delete();
-
- FileWriter command = new FileWriter(COMMAND_FILE);
- try {
- for (String arg : args) {
- if (!TextUtils.isEmpty(arg)) {
- command.write(arg);
- command.write("\n");
- }
- }
- } finally {
- command.close();
- }
-
-
- PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- pm.reboot(PowerManager.REBOOT_RECOVERY);
-
- throw new IOException("Reboot failed (no permissions?)");
- }
1、将传入的命令参数写入到"/cache/recovery/command"文件中去;
2、调用PowerManager.java的reboot()方法进行重启操作;
- public void reboot(String reason) {
- try {
- mService.reboot(false, reason, true);
- } catch (RemoteException e) {
- }
- }
aidl调入到PowerManagerService.java的reboot()方法:
-
-
-
-
-
-
-
- @Override
- 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);
- }
- }
首先检查是否有REBOOT和RECOVERY权限,然后调用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);
- }
- }
- }
- };
-
-
- Message msg = Message.obtain(mHandler, runnable);
- msg.setAsynchronous(true);
- mHandler.sendMessage(msg);
-
-
- if (wait) {
- synchronized (runnable) {
- while (true) {
- try {
- runnable.wait();
- } catch (InterruptedException e) {
- }
- }
- }
- }
- }
这个方法最主要的还是Runnable内的run()方法实现,由于之前传进来的shutdown为false,于是继续调用:
- ShutdownThread.reboot(mContext, reason, confirm);
-
-
-
-
-
-
-
-
-
- public static void reboot(final Context context, String reason, boolean confirm) {
- mReboot = true;
- mRebootSafeMode = false;
- mRebootUpdate = false;
- mRebootReason = reason;
- shutdownInner(context, confirm);
- }
继续调用shutdownInner()方法,此时confirm为false;
shutdownInner()这个方法很长,主要的作用是创建弹出框,根据传入参数confirm来判断是否显示需要用户确认关机或者重启的Dialog,然后开线程执行关机或者重启操作。后续的流程分析可以去查看另外一篇文章:
Android6.0 关机shutdown & 重启reboot流程分析
设备重启后,会自动进入recovery mode模式,读取/cache/recovery/command, 內容为"--wipe_data",开始清除data和cache分区,清除成功后,系统重启,然后进入正常开机流程,重新使用system分区的内容完成开机初始化,此过程跟我们第一次烧写软件过程一致。
至此完成恢复出厂设置。
恢复出厂设置总结:
1、在MasterClearConfirm.java中确认开始执行恢复出厂设置操作,并发出"恢复出厂设置"的广播;
2、在MasterClearReceiver.java接收MasterClearConfirm.java发出的广播,根据是否清除sdcard选项来执行相应的操作;
3、调用RecoverySystem.rebootWipeUserData()方法来清除用户数据并重启设备;这个方法执行过程中会发出"android.intent.action.MASTER_CLEAR_NOTIFICATION"广播、写"/cache/recovery/command"文件(内容包含"--wipe_data"),然后重启设备;
4、设备重启后进入recovery mode之后,读取/cache/recovery/command, 內容为"--wipe_data";
5.按照读取的command,进行wipe data清除数据操作;
6.清除成功后,系统重启,然后进入正常开机流程。