最近在学习Android系统源码,这一节主要是了解恢复出厂设置。实现恢复出厂一般是通过发广播操作,如下:

//恢复出厂设置
Intent recovery = new Intent("android.intent.action.MASTER_CLEAR");
recovery.setPackage("android");
sendBroadcast(recovery);清单文件需要加:1 android:shareUserId = "android.uid.system"  //表明系统应用2 <uses-permission android:name="android.permission.MASTER_CLEAR" />

它的主要流程如下:

1 点击按钮,系统发送恢复出厂设置广播
2 系统MasterClearReceiver接收广播,并进行android层的相关处理最后重启
3 在/cache/recovery/command文件中写入命令字段
4 重启系统,进入Recovery模式
5 根据/cache/recovery/command中的命令字段清楚用户数据
6 重新启动系统,恢复出厂完成

简单来看一下源码:

/frameworks/base/services/core/java/com/android/server/MasterClearReceiver.javapublic class MasterClearReceiver extends BroadcastReceiver {private static final String TAG = "MasterClear";private boolean mWipeExternalStorage;private boolean mWipeEsims;@Overridepublic void onReceive(final Context context, final Intent intent) {...final String factoryResetPackage = context.getString(com.android.internal.R.string.config_factoryResetPackage);if (Intent.ACTION_FACTORY_RESET.equals(intent.getAction())&& !TextUtils.isEmpty(factoryResetPackage)) {intent.setPackage(factoryResetPackage).setComponent(null);context.sendBroadcastAsUser(intent, UserHandle.SYSTEM);return;}final boolean shutdown = intent.getBooleanExtra("shutdown", false);final String reason = intent.getStringExtra(Intent.EXTRA_REASON);mWipeExternalStorage = intent.getBooleanExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, false);mWipeEsims = intent.getBooleanExtra(Intent.EXTRA_WIPE_ESIMS, false);final boolean forceWipe = intent.getBooleanExtra(Intent.EXTRA_FORCE_MASTER_CLEAR, false)|| intent.getBooleanExtra(Intent.EXTRA_FORCE_FACTORY_RESET, false);Slog.w(TAG, "!!! FACTORY RESET !!!");// The reboot call is blocking, so we need to do it on another thread.Thread thr = new Thread("Reboot") {@Overridepublic void run() {try {RecoverySystem.rebootWipeUserData(context, shutdown, reason, forceWipe, mWipeEsims);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 (mWipeExternalStorage) {// thr will be started at the end of this task.new WipeDataTask(context, thr).execute();} else {thr.start();}}private class WipeDataTask extends AsyncTask<Void, Void, Void> {private final Thread mChainedTask;private final Context mContext;private final ProgressDialog mProgressDialog;public WipeDataTask(Context context, Thread chainedTask) {mContext = context;mChainedTask = chainedTask;mProgressDialog = new ProgressDialog(context);}@Overrideprotected void onPreExecute() {mProgressDialog.setIndeterminate(true);mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);mProgressDialog.setMessage(mContext.getText(R.string.progress_erasing));mProgressDialog.show();}@Overrideprotected Void doInBackground(Void... params) {Slog.w(TAG, "Wiping adoptable disks");if (mWipeExternalStorage) {StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);sm.wipeAdoptableDisks();}return null;}@Overrideprotected void onPostExecute(Void result) {mProgressDialog.dismiss();mChainedTask.start();}}
}
<receiver android:name="com.android.server.MasterClearReceiver"android:permission="android.permission.MASTER_CLEAR"><intent-filterandroid:priority="100" ><!-- For Checkin, Settings, etc.: action=FACTORY_RESET --><action android:name="android.intent.action.FACTORY_RESET" /><!-- As above until all the references to the deprecated MASTER_CLEAR get updated toFACTORY_RESET. --><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>
 /frameworks/base/core/java/android/os/RecoverySystem.javapublic class RecoverySystem {private final IRecoverySystem mService;public RecoverySystem(IRecoverySystem service) {mService = service;}public static void rebootWipeUserData(Context context, boolean shutdown, String reason,boolean force, boolean wipeEuicc) throws IOException {UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);if (!force && 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| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);context.sendOrderedBroadcastAsUser(intent, UserHandle.SYSTEM,android.Manifest.permission.MASTER_CLEAR,new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {condition.open();}}, null, 0, null, null);// Block until the ordered broadcast has completed.condition.block();EuiccManager euiccManager = context.getSystemService(EuiccManager.class);if (wipeEuicc) {wipeEuiccData(context, PACKAGE_NAME_EUICC_DATA_MANAGEMENT_CALLBACK);} else {removeEuiccInvisibleSubs(context, euiccManager);}String shutdownArg = null;if (shutdown) {shutdownArg = "--shutdown_after";}String reasonArg = null;if (!TextUtils.isEmpty(reason)) {String timeStamp = DateFormat.format("yyyy-MM-ddTHH:mm:ssZ", System.currentTimeMillis()).toString();reasonArg = "--reason=" + sanitizeArg(reason + "," + timeStamp);}final String localeArg = "--locale=" + Locale.getDefault().toLanguageTag() ;bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);}
 private static void bootCommand(Context context, String... args) throws IOException {//删除日志信息 LOG_FILE.delete();StringBuilder command = new StringBuilder();for (String arg : args) {if (!TextUtils.isEmpty(arg)) {command.append(arg);command.append("\n");}}// Write the command into BCB (bootloader control block) and boot from// there. Will not return unless failed.// 将命令写到bootloader control block RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);rs.rebootRecoveryWithCommand(command.toString());throw new IOException("Reboot failed (no permissions?)");}// 通过Binder与RecoverySystemService对话以设置BCBprivate void rebootRecoveryWithCommand(String command) {try {mService.rebootRecoveryWithCommand(command);} catch (RemoteException ignored) {}}

来看一下服务端:

/frameworks/base/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java@Override // Binder callpublic void rebootRecoveryWithCommand(String command) {if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");synchronized (sRequestLock) {if (!setupOrClearBcb(true, command)) {return;}// 设置完CBC,调用电源管理重启系统,进入恢复模式PowerManager pm = mInjector.getPowerManager();pm.reboot(PowerManager.REBOOT_RECOVERY);}}private boolean setupOrClearBcb(boolean isSetup, String command) {mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);final boolean available = checkAndWaitForUncryptService();if (!available) {Slog.e(TAG, "uncrypt service is unavailable.");return false;}if (isSetup) {mInjector.systemPropertiesSet("ctl.start", "setup-bcb");} else {mInjector.systemPropertiesSet("ctl.start", "clear-bcb");}// Connect to the uncrypt service socket.UncryptSocket socket = mInjector.connectService();if (socket == null) {Slog.e(TAG, "Failed to connect to uncrypt socket");return false;}try {// Send the BCB commands if it's to setup BCB.if (isSetup) {socket.sendCommand(command);}// Read the status from the socket.int status = socket.getPercentageUncrypted();// Ack receipt of the status code. uncrypt waits for the ack so// the socket won't be destroyed before we receive the code.socket.sendAck();if (status == 100) {Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear")+ " bcb successfully finished.");} else {// Error in /system/bin/uncrypt.Slog.e(TAG, "uncrypt failed with status: " + status);return false;}} catch (IOException e) {Slog.e(TAG, "IOException when communicating with uncrypt:", e);return false;} finally {socket.close();}return true;}    
/frameworks/base/core/java/android/os/PowerManager.java
public final class PowerManager {@UnsupportedAppUsagefinal IPowerManager mService;/*** {@hide}*/public PowerManager(Context context, IPowerManager service, IThermalService thermalService,Handler handler) {mContext = context;mService = service;mThermalService = thermalService;mHandler = handler;}public void reboot(@Nullable String reason) {if (REBOOT_USERSPACE.equals(reason) && !isRebootingUserspaceSupported()) {throw new UnsupportedOperationException("Attempted userspace reboot on a device that doesn't support it");}try {mService.reboot(false, reason, true);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}
}
/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java/*** 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 callpublic void reboot(boolean confirm, @Nullable String reason, boolean wait) {mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);if (PowerManager.REBOOT_RECOVERY.equals(reason)|| PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);}final long ident = Binder.clearCallingIdentity();try {shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);} finally {Binder.restoreCallingIdentity(ident);}}private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,@Nullable final String reason, boolean wait) {if (PowerManager.REBOOT_USERSPACE.equals(reason)) {if (!PowerManager.isRebootingUserspaceSupportedImpl()) {throw new UnsupportedOperationException("Attempted userspace reboot on a device that doesn't support it");}UserspaceRebootLogger.noteUserspaceRebootWasRequested();}if (mHandler == null || !mSystemReady) {if (RescueParty.isAttemptingFactoryReset()) {// If we're stuck in a really low-level reboot loop, and a// rescue party is trying to prompt the user for a factory data// reset, we must GET TO DA CHOPPA!PowerManagerService.lowLevelReboot(reason);} else {throw new IllegalStateException("Too early to call shutdown() or reboot()");}}Runnable runnable = new Runnable() {@Overridepublic void run() {synchronized (this) {if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {ShutdownThread.rebootSafeMode(getUiContext(), confirm);} else if (haltMode == HALT_MODE_REBOOT) {ShutdownThread.reboot(getUiContext(), reason, confirm);} else {ShutdownThread.shutdown(getUiContext(), reason, confirm);}}}};// ShutdownThread must run on a looper capable of displaying the UI.Message msg = Message.obtain(UiThread.getHandler(), runnable);msg.setAsynchronous(true);UiThread.getHandler().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) {}}}}}
/frameworks/base/services/core/java/com/android/server/power/ShutdownThread.javaprivate static final ShutdownThread sInstance = new ShutdownThread();public static void rebootSafeMode(final Context context, boolean confirm) {UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);if (um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {return;}mReboot = true;mRebootSafeMode = true;mRebootHasProgressBar = false;mReason = null;shutdownInner(context, confirm);}public static void reboot(final Context context, String reason, boolean confirm) {mReboot = true;mRebootSafeMode = false;mRebootHasProgressBar = false;mReason = reason;shutdownInner(context, confirm);}public static void shutdown(final Context context, String reason, boolean confirm) {mReboot = false;mRebootSafeMode = false;mReason = reason;shutdownInner(context, confirm);}private static void shutdownInner(final Context context, boolean confirm) {// ShutdownThread is called from many places, so best to verify here that the context passed// in is themed.context.assertRuntimeOverlayThemable();// ensure that only one thread is trying to power down.// any additional calls are just returnedsynchronized (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);}}
/frameworks/base/core/java/android/os/storage/StorageManager.javaprivate final IStorageManager mStorageManager;@UnsupportedAppUsagepublic StorageManager(Context context, Looper looper) throws ServiceNotFoundException {mContext = context;mResolver = context.getContentResolver();mLooper = looper;mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getServiceOrThrow("mount"));mAppOps = mContext.getSystemService(AppOpsManager.class);}/** {@hide} */public void wipeAdoptableDisks() {// We only wipe devices in "adoptable" locations, which are in a// long-term stable slot/location on the device, where apps have a// reasonable chance of storing sensitive data. (Apps need to go through// SAF to write to transient volumes.)final List<DiskInfo> disks = getDisks();for (DiskInfo disk : disks) {final String diskId = disk.getId();if (disk.isAdoptable()) {Slog.d(TAG, "Found adoptable " + diskId + "; wiping");try {// TODO: switch to explicit wipe command when we have it,// for now rely on the fact that vfat format does a wipemStorageManager.partitionPublic(diskId);} catch (Exception e) {Slog.w(TAG, "Failed to wipe " + diskId + ", but soldiering onward", e);}} else {Slog.d(TAG, "Ignorning non-adoptable disk " + disk.getId());}}}/** {@hide} */@UnsupportedAppUsagepublic void partitionPublic(String diskId) {try {mStorageManager.partitionPublic(diskId);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}

Android源码笔记--恢复出厂设置相关推荐

  1. android 9.0 添加自定义恢复出厂设置标识

    说明 android 恢复出厂设置的处理逻辑是RecoverySystem.java中的rebootWipeUserData,源码在recovery.cpp中的main中,前面有想过在recovery ...

  2. Android最新版,恢复出厂设置

    文章目录 前言 1.原生设置源码路径: 2.源码解释 3.APP的调用 前言 Android12下,如何恢复出厂设置 1.原生设置源码路径: 系统源码/package/apps/Settings/sr ...

  3. Android 10.0创建恢复出厂设置不被清除的文件夹节点

    在系统开发中,希望保存一些数据 在恢复出厂设置以后也不会被清理掉,这样就希望创建的节点不在被清理的范围内 而recovery主要会清理 /data/ 和 /cache 分区的数据 卸载安装的app A ...

  4. 恢复出厂设置android手机号码,手机怎么恢复出厂设置 安卓手机恢复出厂设置方法汇总...

    最近接连有不少身边的朋友遇到一些比较奇怪的智能手机问题,比如最开始有朋友无意间设置了图案锁屏保护密码,但之后却不记得自设置的图案密码,导致连续五次解锁失败,手机直接成为了锁定状态,需要注册的谷歌账号密 ...

  5. 恢复出厂设置android手机号码,安卓手机恢复出厂设置会怎么样?

    安卓手机恢复出厂设置会怎么样?事实上,用户若是主动将安卓手机恢复出厂设置,未备份的手机号码(在手机里面的,SIM卡中的电话号码不影响).短信.应用.设置等数据就会被直接删除. 安卓手机恢复出厂设置会怎 ...

  6. 华为手机怎样恢复Android,华为手机怎么恢复出厂设置 华为恢复出厂设置的两种方法...

    当我们的华为手机出现一些系统错乱或感染病毒或因个人原因想让我们的手机恢复出厂设置,让手机全变得一干二净,跟我们刚买来时的状态一样,我们该去哪里操作呢,下面,让小编带大家一起了解下这方面的知识. 华为恢 ...

  7. 三星android在哪里,三星手机恢复出厂设置功能在哪里?三星手机恢复出厂设置方法图解...

    最近有网友"花莫愁"问小编,我的三星手机卡死了,想恢复出厂设置,请问三星手机怎么恢复出厂设置呢?对于类似问题,以前也有不少朋友问到过此问题.其实三星手机恢复出厂设置比较简单,只要找 ...

  8. Android客制化------恢复出厂设置但保留文件

    很久没有记录了,持之以恒做一件事,需要一定的毅力呐! 最近遇到了一个需求,要求恢复出厂设置保留内置sd卡下某个目录的文件.思来想去,从驱动那边备份校准信号文件得到了一些思路.因为带通话设置的装置需要进 ...

  9. Android客制化-恢复出厂设置但保留文件

    很久没有记录了,持之以恒做一件事,需要一定的毅力呐!  最近遇到了一个需求,要求恢复出厂设置保留内置sd卡下某个目录的文件.思来想去,从驱动那边备份校准信号文件得到了一些思路.因为带通话设置的装置需要 ...

最新文章

  1. 如何在HTML页面中插入百度地图
  2. JDK9新特性实战:简化流关闭新姿势。
  3. su user oracle does not exist,Linux下oracle用户无法su切换的异常【终极解决方案_生产环境亲测有效】...
  4. 字符串池化,减少了三分之一的内存占用
  5. Blazor——Asp.net core的新前端框架
  6. 骁龙660是32位还是64位_微软公布v2004最低处理器要求,放弃32位系统,你的CPU还能支持吗?...
  7. 计算机片段教学优秀教案,精彩教学片段100例—导入篇(1)
  8. HTTP的长连接和短连接通俗解释以及应用场景
  9. junit测试给定默认的jvm参数
  10. Java原生-实现SHA256算法【工具类】
  11. Mac -- 插入移动硬盘后没有显示
  12. html5辨别音高,音理知识基础:音高和时值
  13. linux中如何开启vnc服务端口,Linux下vnc配置及启动
  14. 币圈炒币如何避免被额韭菜?
  15. C#转Java心路历程
  16. 单片机--串口通信---11
  17. WebStorm英文版汉化
  18. ubuntu14.04编译安装strongswan
  19. MDN-CSS-排版社区大学首页
  20. 优步北京B组奖励政策

热门文章

  1. linux显示iphone屏幕,关于 iphone 文字显示
  2. UE4/UE5 虚幻引擎,设置Mouse Cursor鼠标光标样式
  3. android获取qq消息列表,获取所有qq好友、全部群所有成员部分信息,并保存列表至电子表格文件以备份信息的爬虫...
  4. Unity Hub登录无响应
  5. springCloud-40 restTemplate 整合sentinel 实现熔断
  6. 过去几十年来计算机应用经历了几个阶段,计算机应用阶段训练题.doc
  7. 深入java虚拟机 class类文件结构
  8. endorsed java_关于java:在jdk1.6中使用Endorsed目录的确切方法是什么
  9. 面向亿万级用户的QQ一般做什么?——兴趣部落的Web同构直出分享
  10. [学习]19 如何高效工作和学习