今天跟了一下Android7.0的恢复出厂设置的流程,记录如下:
首先是在设置里面点击“ERASE EVERYTHING”按钮,
那就从这里入手,先搜索这个
ERASE EVERYTHING字符串
吧:
grep -ri "ERASE EVERYTHING" ../../packages/apps/Settings/
packages/apps/Settings/res/values-en-rGB/strings.xml: "Erase everything"
packages/apps/Settings/res/values-en-rIN/strings.xml: "Erase everything"
packages/apps/Settings/res/values-en-rAU/strings.xml: "Erase everything"
packages/apps/Settings/res/values/strings.xml: Erase everything
再搜索
master_clear_final_button_text,除了大量的各种语言的字符串的定义,还有下面这个:
packages/apps/Settings/res/layout/master_clear_confirm.xml: android:text="@string/master_clear_final_button_text"
那就查看master_clear_confirm.xml文件,找到button的id为execute_master_clear:
android/ packages/apps/Settings/res/layout/master_clear_confirm.xml
32 execute_master_clear"
33 android:layout_gravity="center_horizontal"
34 android:layout_marginTop="40dip"
35 android:layout_width="wrap_content"
36 android:layout_height="wrap_content"
37 android:text="@string/master_clear_final_button_text"
38 android:gravity="center" />
根据id再搜索,找到java源文件:
android/ packages/apps/Settings/src/com/android/settings/MasterClearConfirm.java
128 private void establishFinalConfirmationState() {
129 mContentView.findViewById(R.id.execute_master_clear)
130 .setOnClickListener(mFinalClickListener );
131 }
再来看看该button的事件监听器mFinalClickListener的实现:
60 private Button.OnClickListener mFinalClickListener = new Button.OnClickListener() {
61
62 public void onClick(View v) {
63 if (Utils.isMonkeyRunning()) {
64 return;
65 }
66
67 final PersistentDataBlockManager pdbManager = (PersistentDataBlockManager)
68 getActivity().getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
69
70 if (pdbManager != null && !pdbManager.getOemUnlockEnabled() &&
71 Utils.isDeviceProvisioned(getActivity())) {
72 new AsyncTask() {
73 int mOldOrientation;
74 ProgressDialog mProgressDialog;
75
76 @Override
77 protected Void doInBackground(Void... params) {
78 pdbManager.wipe();
79 return null;
80 }
81
82 @Override
83 protected void onPostExecute(Void aVoid) {
84 mProgressDialog.hide();
85 if (getActivity() != null) {
86 getActivity().setRequestedOrientation(mOldOrientation);
87 doMasterClear ();
88 }
89 }
90
91 @Override
92 protected void onPreExecute() {
93 mProgressDialog = getProgressDialog();
94 mProgressDialog.show();
95 mOldOrientation = getActivity().getRequestedOrientation();
96 getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
97 }
98 }.execute();
99 } else {
100 doMasterClear ();
101 }
102 }
再来看看doMasterClear的实现,主要就是
发送包含
ACTION_MASTER_CLEAR的intent出去
116 private void doMasterClear() {
117 Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR );
118 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
119 intent.putExtra(Intent.EXTRA_REASON, "MasterClearConfirm");
120 intent.putExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, mEraseSdCard);
121 getActivity().sendBroadcast(intent);
122 // Intent handling is asynchronous -- assume it will happen soon.
123 }
这个ACTION_MASTER_CLEAR的定义是在这里:
android/
frameworks/base/
core/java/android/content/Intent.java
3173 /** {@hide} */
3174 public static final String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR ";
那android.intent.action.MASTER_CLEAR的接收是在哪里呢,在这里:
android/ frameworks/base/core/res/AndroidManifest.xml
3111
3113
3115
3116 android.intent.action.MASTER_CLEAR" />
3117
3118
3119
3120
3121
3122
原来是MasterClearReceiver去处理这个消息,那就看看它的处理:
android/ frameworks/base /services/core/java/com/android/server/MasterClearReceiver.java
54 Slog.w(TAG, "!!! FACTORY RESET !!!");
55 // The reboot call is blocking, so we need to do it on another thread.
56 Thread thr = new Thread("Reboot") {
57 @Override
58 public void run() {
59 try {
61 RecoverySystem.rebootWipeUserData (context, shutdown, reason);
62 Log.wtf(TAG, "Still running after master clear?!");
63 } catch (IOException e) {
64 Slog.e(TAG, "Can't perform master clear/factory reset", e);
65 } catch (SecurityException e) {
66 Slog.e(TAG, "Can't perform master clear/factory reset", e);
67 }
68 }
69 };
后面的流程就到了
RecoverySystem中:
android/frameworks/base/core/java/android/os/RecoverySystem.java
606 public static void rebootWipeUserData(Context context, boolean shutdown, String reason)
607 throws IOException {
608 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
609 if (um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {
610 throw new SecurityException("Wiping data is not allowed for this user.");
611 }
612 final ConditionVariable condition = new ConditionVariable();
613
614 Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
615 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
616 context.sendOrderedBroadcastAsUser(intent, UserHandle.SYSTEM,
617 android.Manifest.permission.MASTER_CLEAR,
618 new BroadcastReceiver() {
619 @Override
620 public void onReceive(Context context, Intent intent) {
621 condition.open();
622 }
623 }, null, 0, null, null);
624
625 // Block until the ordered broadcast has completed.
626 condition.block();
627
628 String shutdownArg = null;
629 if (shutdown) {
630 shutdownArg = "--shutdown_after";
631 }
632
633 String reasonArg = null;
634 if (!TextUtils.isEmpty(reason)) {
635 reasonArg = "--reason=" + sanitizeArg(reason);
636 }
637
638 final String localeArg = "--locale=" + Locale.getDefault().toString();
639 bootCommand (context, shutdownArg, "--wipe_data", reasonArg, localeArg);
640 }
还是在RecoverySystem.java中, 最后再来看看bootCommand的实现:
666 private static void bootCommand(Context context, String... args) throws IOException {
667 synchronized (sRequestLock) {
669 LOG_FILE.delete();
670
671 StringBuilder command = new StringBuilder();
672 for (String arg : args) {
673 if (!TextUtils.isEmpty(arg)) {
674 command.append(arg);
675 command.append("\n");
676 }
677 }
678
679 // Write the command into BCB (bootloader control block).
680 RecoverySystem rs = (RecoverySystem) context.getSystemService(
681 Context.RECOVERY_SERVICE);
682 rs.setupBcb(command.toString());
700
701 // Having set up the BCB, go ahead and reboot.
702 PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
703 pm.reboot (PowerManager.REBOOT_RECOVERY);
704
705 throw new IOException("Reboot failed (no permissions?)");
706 }
707 }
这里的的pm.reboot()实现了重启机器的功能,当然,重启之后首先会擦除数据,经过一系列处理完成后,最后又重启回到Android系统,这时候就是刚出厂时的系统了,用户自己安装的APK都会被擦除掉。
其实可以在这里的reboot之前做一些定制化的修改,比如写文件置标志等,重启后,可以按照自己的Recovery逻辑进行处理等。