Android恢复出厂设置保存文件标志位到 persist 分区

Android 恢复出厂设置基本流程

(1)遥控器/按键板后门键触发,或者应用里面从系统设置里面恢复出厂选项也可触发; // 后面以系统设置的应用触发为例
(2)选择恢复出厂设置之后,就会发送广播“android.intent.action.MASTER_CLEAR” ;// framework/base/core/res/AndroidManifest.xml
(3)MasterClearReceiver 捕获广播 ,并进行android 层的相关处理最后重启 ;
(4)往 /cache/recovery/command 文件中写入命令字段;
(5)重启系统;

recovery 进入方式

(1) 通过读取 /cache 分区中文件 /cache/recovery/command 内容进入 
(2)通过按键操作进入 (G1 通过同时按 HOME 和 挂断键) 
          以上两种方式进入都需要 blob的支持

进入recovery 的条件

(1) blob 必须能从 recovery 分区中装载内核和文件系统 
2 )flash 必须有 cache 分区 和 recovery 分区 
3 )必须编译提供 recovery.img 烧录到 recovery 分区


Android 的处理流程

广播接收
framework/base/core/res/AndroidManifest.xml
[html]  view plain  copy
  1. <receiver android:name="com.android.server.MasterClearReceiver"  
  2.     android:permission="android.permission.MASTER_CLEAR">  
  3.     <intent-filter  
  4.             android:priority="100" >  
  5.         <!-- For Checkin, Settings, etc.: action=MASTER_CLEAR -->  
  6.         <action android:name="android.intent.action.MASTER_CLEAR" />  
  7.   
  8.         <!-- MCS always uses REMOTE_INTENT: category=MASTER_CLEAR -->  
  9.         <action android:name="com.google.android.c2dm.intent.RECEIVE" />  
  10.         <category android:name="android.intent.category.MASTER_CLEAR" />  
  11.     </intent-filter>  
  12. </receiver>  
MasterClearReceiver接收广播android.intent.action.MASTER_CLEAR,创建一个县城作一下处理
[java]  view plain  copy
  1. Thread thr = new Thread("Reboot") {  
  2.     @Override  
  3.     public void run() {  
  4.         try {  
  5.             RecoverySystem.rebootWipeUserData(context, shutdown, reason);  
  6.             Log.wtf(TAG, "Still running after master clear?!");  
  7.         } catch (IOException e) {  
  8.             Slog.e(TAG, "Can't perform master clear/factory reset", e);  
  9.         } catch (SecurityException e) {  
  10.             Slog.e(TAG, "Can't perform master clear/factory reset", e);  
  11.         }  
  12.     }  
  13. };  
  14. thr.start();  
RecoverySystem 来重启,启动擦除用户数据的操作
[java]  view plain  copy
  1. /** 
  2.  * Reboots the device and wipes the user data and cache 
  3.  * partitions.  This is sometimes called a "factory reset", which 
  4.  * is something of a misnomer because the system partition is not 
  5.  * restored to its factory state.  Requires the 
  6.  * {@link android.Manifest.permission#REBOOT} permission. 
  7.  * 
  8.  * @param context   the Context to use 
  9.  * @param shutdown  if true, the device will be powered down after 
  10.  *                  the wipe completes, rather than being rebooted 
  11.  *                  back to the regular system. 
  12.  * 
  13.  * @throws IOException  if writing the recovery command file 
  14.  * fails, or if the reboot itself fails. 
  15.  * @throws SecurityException if the current user is not allowed to wipe data. 
  16.  * 
  17.  * @hide 
  18.  */  
  19. public static void rebootWipeUserData(Context context, boolean shutdown, String reason)  
  20.         throws IOException {  
  21.     UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);  
  22.     if (um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {  
  23.         throw new SecurityException("Wiping data is not allowed for this user.");  
  24.     }  
  25.     final ConditionVariable condition = new ConditionVariable();  
  26.   
  27.     Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");  
  28.     intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);  
  29.     context.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,  
  30.             android.Manifest.permission.MASTER_CLEAR,  
  31.             new BroadcastReceiver() {  
  32.                 @Override  
  33.                 public void onReceive(Context context, Intent intent) {  
  34.                     condition.open();  
  35.                 }  
  36.             }, null0nullnull);  
  37.   
  38.     // Block until the ordered broadcast has completed.  
  39.     condition.block();  
  40.   
  41.     String shutdownArg = null;  
  42.     if (shutdown) {  
  43.         shutdownArg = "--shutdown_after";  
  44.     }  
  45.   
  46.     String reasonArg = null;  
  47.     if (!TextUtils.isEmpty(reason)) {  
  48.         reasonArg = "--reason=" + sanitizeArg(reason);  
  49.     }  
  50.   
  51.     final String localeArg = "--locale=" + Locale.getDefault().toString();  
  52.     bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);  
  53. }  
我们可以注意到在启动bootCommand传递命令时,封装参数 --wipe_data , --locale , 这些命令我们可以在查看recovery log ( /cache/recovery/*.log )信息时看到
“Command: "/sbin/recovery" "--wipe_data" "--locale=zh_CN"  ,其实这应该也就是bootCommand 执行的命令
[java]  view plain  copy
  1. /** 
  2.  * Reboot into the recovery system with the supplied argument. 
  3.  * @param args to pass to the recovery utility. 
  4.  * @throws IOException if something goes wrong. 
  5.  */  
  6. private static void bootCommand(Context context, String... args) throws IOException {  
  7.     RECOVERY_DIR.mkdirs();  // In case we need it  
  8.     COMMAND_FILE.delete();  // In case it's not writable  
  9.     LOG_FILE.delete();  
  10.   
  11.     FileWriter command = new FileWriter(COMMAND_FILE);  
  12.     try {  
  13.         for (String arg : args) {  
  14.             if (!TextUtils.isEmpty(arg)) {  
  15.                 // MStar Android Patch Begin  
  16.                 String cmd = arg;  
  17.                 String label = null;  
  18.                 String uuid = null;  
  19.                 if (cmd.startsWith("--update_package")) {  
  20.                     cmd = arg.substring(1723);  
  21.                     if (cmd.equals("/cache")) {  
  22.                         command.write("--uuid=mstar-cache");  
  23.                         command.write("\n");  
  24.                         command.write("--label=mstar-cache");  
  25.                         command.write("\n");  
  26.                     } else {  
  27.                         cmd = arg.substring(1728);  
  28.                         if (cmd.equals("/mnt/usb/sd")) {  
  29.                             cmd = arg.substring(1730);  
  30.                             uuid = "--uuid=" + getVolumeUUID(cmd).toString();  
  31.                             label = "--label=" + getVolumeLabel(cmd).toString();  
  32.                             command.write(uuid);  
  33.                             command.write("\n");  
  34.                             command.write(label);  
  35.                             command.write("\n");  
  36.                         } else {  
  37.                             if (cmd.equals("/mnt/sdcard")) {  
  38.                                 uuid = "--uuid=" + getVolumeUUID(cmd).toString();  
  39.                                 label = "--label=" + getVolumeLabel(cmd).toString();  
  40.                                 command.write(uuid);  
  41.                                 command.write("\n");  
  42.                                 command.write(label);  
  43.                                 command.write("\n");  
  44.                             } else {  
  45.                                 cmd = arg.substring(1732);  
  46.                                 if (cmd.equals("/mnt/usb/mmcblk")) {  
  47.                                     cmd = arg.substring(1735);  
  48.                                     uuid = "--uuid=" + getVolumeUUID(cmd).toString();  
  49.                                     label = "--label=" + getVolumeLabel(cmd).toString();  
  50.                                     command.write(uuid);  
  51.                                     command.write("\n");  
  52.                                     command.write(label);  
  53.                                     command.write("\n");  
  54.                                 }  
  55.                             }  
  56.                         }  
  57.                     }  
  58.                 }  
  59.                 // MStar Android Patch End  
  60.                 command.write(arg);  
  61.                 command.write("\n");  
  62.             }  
  63.         }  
  64.     } finally {  
  65.         command.close();  
  66.     }  
  67.   
  68.     // Having written the command file, go ahead and reboot  
  69.     PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);  
  70.     pm.reboot(PowerManager.REBOOT_RECOVERY);  
  71.   
  72.     throw new IOException("Reboot failed (no permissions?)");  
  73. }  
从以上代码分析,bootCommand 主要工作就是重启进入recovery,此处可以看到COMMAND_FILE 就是文件 “ /cache/recovery/command " , 将上面封装的参数信息
写入改文件,待重启之后读取该文件时进入recovery模式,另外我们看到写完文件之后,调用PowerManager 来reboot,注意参数PowerManager.REBOOT_RECOVERY
[java]  view plain  copy
  1. // Having written the command file, go ahead and reboot  
  2. PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);  
  3. pm.reboot(PowerManager.REBOOT_RECOVERY);  
  4.   
  5. /** 
  6.  * Reboot the device.  Will not return if the reboot is successful. 
  7.  * <p> 
  8.  * Requires the {@link android.Manifest.permission#REBOOT} permission. 
  9.  * </p> 
  10.  * 
  11.  * @param reason code to pass to the kernel (e.g., "recovery") to 
  12.  *               request special boot modes, or null. 
  13.  */  
  14. public void reboot(String reason) {  
  15.     try {  
  16.         mService.reboot(false, reason, true);  
  17.     } catch (RemoteException e) {  
  18.     }  
  19. }  
最后又进入PowerManagerService 的reboot函数
[java]  view plain  copy
  1. /** 
  2.  * Reboots the device. 
  3.  * 
  4.  * @param confirm If true, shows a reboot confirmation dialog. 
  5.  * @param reason The reason for the reboot, or null if none. 
  6.  * @param wait If true, this call waits for the reboot to complete and does not return. 
  7.  */  
  8. @Override // Binder call  
  9. public void reboot(boolean confirm, String reason, boolean wait) {  
  10.     mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);  
  11.     if (PowerManager.REBOOT_RECOVERY.equals(reason)) {  
  12.         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);  
  13.     }  
  14.   
  15.     final long ident = Binder.clearCallingIdentity();  
  16.     try {  
  17.         shutdownOrRebootInternal(false, confirm, reason, wait);  
  18.     } finally {  
  19.         Binder.restoreCallingIdentity(ident);  
  20.     }  
  21. }  
接着进入shutdownOrRebootInternal
[java]  view plain  copy
  1. private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm,  
  2.         final String reason, boolean wait) {  
  3.     if (mHandler == null || !mSystemReady) {  
  4.         throw new IllegalStateException("Too early to call shutdown() or reboot()");  
  5.     }  
  6.   
  7.     Runnable runnable = new Runnable() {  
  8.         @Override  
  9.         public void run() {  
  10.             synchronized (this) {  
  11.                 if (shutdown) {  
  12.                     ShutdownThread.shutdown(mContext, confirm);  
  13.                 } else {  
  14.                     ShutdownThread.reboot(mContext, reason, confirm);  
  15.                 }  
  16.             }  
  17.         }  
  18.     };  
  19.   
  20.     // ShutdownThread must run on a looper capable of displaying the UI.  
  21.     Message msg = Message.obtain(mHandler, runnable);  
  22.     msg.setAsynchronous(true);  
  23.     mHandler.sendMessage(msg);  
  24.   
  25.     // PowerManager.reboot() is documented not to return so just wait for the inevitable.  
  26.     if (wait) {  
  27.         synchronized (runnable) {  
  28.             while (true) {  
  29.                 try {  
  30.                     runnable.wait();  
  31.                 } catch (InterruptedException e) {  
  32.                 }  
  33.             }  
  34.         }  
  35.     }  
  36. }  
ShutdownThread来负责重启动作
[java]  view plain  copy
  1. /** 
  2.  * Request a clean shutdown, waiting for subsystems to clean up their 
  3.  * state etc.  Must be called from a Looper thread in which its UI 
  4.  * is shown. 
  5.  * 
  6.  * @param context Context used to display the shutdown progress dialog. 
  7.  * @param reason code to pass to the kernel (e.g. "recovery"), or null. 
  8.  * @param confirm true if user confirmation is needed before shutting down. 
  9.  */  
  10. public static void reboot(final Context context, String reason, boolean confirm) {  
  11.     mReboot = true;  
  12.     mRebootSafeMode = false;  
  13.     mRebootReason = reason;  
  14.     shutdownInner(context, confirm);  
  15. }  
  16.   
  17. static void shutdownInner(final Context context, boolean confirm) {  
  18.     // ensure that only one thread is trying to power down.  
  19.     // any additional calls are just returned  
  20.     synchronized (sIsStartedGuard) {  
  21.         if (sIsStarted) {  
  22.             Log.d(TAG, "Request to shutdown already running, returning.");  
  23.             return;  
  24.         }  
  25.     }  
  26.   
  27.     final int longPressBehavior = context.getResources().getInteger(  
  28.                     com.android.internal.R.integer.config_longPressOnPowerBehavior);  
  29.     final int resourceId = mRebootSafeMode  
  30.             ? com.android.internal.R.string.reboot_safemode_confirm  
  31.             : (longPressBehavior == 2  
  32.                     ? com.android.internal.R.string.shutdown_confirm_question  
  33.                     : com.android.internal.R.string.shutdown_confirm);  
  34.   
  35.     Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);  
  36.   
  37.     if (confirm) {  
  38.         final CloseDialogReceiver closer = new CloseDialogReceiver(context);  
  39.         if (sConfirmDialog != null) {  
  40.             sConfirmDialog.dismiss();  
  41.         }  
  42.         sConfirmDialog = new AlertDialog.Builder(context)  
  43.                 .setTitle(mRebootSafeMode  
  44.                         ? com.android.internal.R.string.reboot_safemode_title  
  45.                         : com.android.internal.R.string.power_off)  
  46.                 .setMessage(resourceId)  
  47.                 .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {  
  48.                     public void onClick(DialogInterface dialog, int which) {  
  49.                         beginShutdownSequence(context);  
  50.                     }  
  51.                 })  
  52.                 .setNegativeButton(com.android.internal.R.string.no, null)  
  53.                 .create();  
  54.         closer.dialog = sConfirmDialog;  
  55.         sConfirmDialog.setOnDismissListener(closer);  
  56.         sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);  
  57.         sConfirmDialog.show();  
  58.     } else {  
  59.         beginShutdownSequence(context);  
  60.     }  
  61. }  
beginShutdownSequence进入主要的关机流程, 接着启动ShutdownThread.run() , 发送光机广播,关闭核心服务,最后进入rebootOrShutdown重启。


recovery进入流程

进入recovery有几种途径:
(1)进入recovery前先写misc分区,重启时发现变化就直接进入recovery模式;
(2)写文件 /cache/recovery/command 文件,重启时进去recovery模式; // 此种模式暂未找到启动recovery的地方,只是在启动recovery后有看到读
                                                                                                                                           // 取/cache/recovery/command 文件数据再做后续操作

MISC分区内容

Bootloader Control Block(BCB) 存放recovery 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可以有以下两个值
“boot-recovery”:表示recovery正在进行或者指示bootloader应该进入recovery mode
“update--hboot/radio”:标志bootloader更新fireware

recovery内容

“recovery\n
<recovery command>\n
<recovery command>\n”其中 recovery command为CACHE:/recovery/command命令


Recovery Case 

Factory reset(恢复出厂设置)



1. 用户选择“恢复出厂设置”
2. 设置系统将“--wipe_data”命令写入 /cache/recovery/command
3. 系统重启,并进入recovery模式 (sbin/recovery  or /system/bin/recovery)
4. recovery get_args() 将“boot-recovery”和“--wipe_data”写入BCB
5. erase_root 格式化DATA 分区
6. erase_root 格式化CACHE 分区
7. finish_recovery 擦除BCB分区
8. 重启系统

OTA INSTALL (OTA升级)

1. 升级系统系在OTA包包/cache/some-filename.zip
2. 升级系统写入recovery命令 “--update_package=CACHE:some-filename.zip”
3. 重启系统,进入recovery模式
4. get_args()将“boot-recovery”和“--wipe_packkage=...”写入BCB
5. install_package 做升级
6. finish_recovery() 擦除BCB
7. **如果安装包失败**prompt_and_wait()等待用户操作,选择ALT+S或者ALT+W升级或回复出厂设置
8. main() 里面调用maybe_install_firmware_update()
    1.如果包里含有hboot/radio的fireware则继续,否则返回
    2.将"boot-recovery"和"--wipe_cache"写入BCB
    3.将fireware image写入cache分区
    4.将"update-readio/hboot"和“--wipe_date”写入BCB
    5.重启系统
    6.bootloader自身更新fireware
    7.bootloader将"boot-recovery"写入BCB
    8.erase_root擦除CACHE分区
    9.清除BCB
9. main 调用reboot重启系统




Recovery代码位置:bootable/recovery/ ,主文件recovery.cpp


后续再分析 recovery流程
                  

Android Recovery 模式学习
本文转载自:http://blog.csdn.net/u012724237/article/details/69568846
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值