Android recovery

关于android的recovery网上有各种版本的定义,这里我总结一下:所谓recovery是android下加入的一种特殊工作模式,有点类似于windows下的gost,系统进入到这种模式下时,可以在这里通过按键选择相应的操作菜单实现相应的功能,比如android系统和数据区的快速格式化(wipe);系统和用户数据的备份和恢复;通过sd卡刷新的rom等等。典型的recovery界面如下:

Recovery的源代码在bootable/recovery这个目录下面,主要来看看recovery.c这个文件中的main函数:

Int main(int argc, char **argv) {
       .
       .
       .
    ui_init();
    ui_set_background(BACKGROUND_ICON_INSTALLING);
    load_volume_table();
       .
       .
       .
    while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
        switch (arg) {
        case 'p': previous_runs = atoi(optarg); break;
        case 's': send_intent = optarg; break;
        case 'u': update_package = optarg; break;
        case 'w': wipe_data = wipe_cache = 1; break;
        case 'c': wipe_cache = 1; break;
        case 'e': encrypted_fs_mode = optarg; toggle_secure_fs = 1; break;
        case 't': ui_show_text(1); break;
        case '?':
            LOGE("Invalid command argument\n");
            continue;
        }
    }
    device_recovery_start();
       .
       .
       .
    if (update_package)
       {
        // For backwards compatibility on the cache partition only, if
        // we're given an old 'root' path "CACHE:foo", change it to
        // "/cache/foo".
        if (strncmp(update_package, "CACHE:", 6) == 0)
              {
            int len = strlen(update_package) + 10;
            char* modified_path = malloc(len);
            strlcpy(modified_path, "/cache/", len);
            strlcat(modified_path, update_package+6, len);
            printf("(replacing path \"%s\" with \"%s\")\n",
                   update_package, modified_path);
            update_package = modified_path;
        }
              //for update from "/mnt/sdcard/update.zip",but at recovery system is "/sdcard" so change it to "/sdcard"
              //ui_print("before:[%s]\n",update_package);
        if (strncmp(update_package, "/mnt", 4) == 0)
        {
        //jump the "/mnt"
                     update_package +=4;
              }
              ui_print("install package from[%s]\n",update_package);
     }
    printf("\n");
    property_list(print_property, NULL);
    printf("\n");
    int status = INSTALL_SUCCESS;
       .
       .
       .
// Recovery strategy: if the data partition is damaged, disable encrypted file systems.
        // This preventsthe device recycling endlessly in recovery mode.
       .
       .
       .
    if (update_package != NULL)
    {
        status = install_package(update_package);
        if (status != INSTALL_SUCCESS)
                     ui_print("Installation aborted.\n");
              else
              {
                     erase_volume("/data");
                     erase_volume("/cache");
              }
    } else if (wipe_data) {
        if (device_wipe_data()) status = INSTALL_ERROR;
        if (erase_volume("/data")) status = INSTALL_ERROR;
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n");
    } else if (wipe_cache) {
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui_print("Cache wipe failed.\n");
    } else {
        status = INSTALL_ERROR;  // No command specified
    }
    if (status != INSTALL_SUCCESS) ui_set_background(BACKGROUND_ICON_ERROR);
       //Xandy modify for view the install infomation
    //if (status != INSTALL_SUCCESS || ui_text_visible())
    if(status != INSTALL_SUCCESS)
       {
        prompt_and_wait();
    }
    // Otherwise, get ready to boot the main system...
    finish_recovery(send_intent);
    ui_print("Rebooting...\n");
    sync();
    reboot(RB_AUTOBOOT);
    return EXIT_SUCCESS;
}

在这里首先完成recovery模式轻量级的UI系统初始化,设置背景图片,然后对输入的参数格式化,最后根据输入的参数进行相应的操作,如:安装新的ROM、格式化(wipe)data及cache分区等等;值得注意的是刷新ROM的时候,要制作相应的update.zip的安装包,这个在最后一章节讲述,这里遇到的一个问题是在recovery模式下sd卡的挂载点为/sdcard而不是android系统下的/mnt/sdcard,所以我在这里通过:

//for update from "/mnt/sdcard/update.zip",but at recovery system is "/sdcard" so change it to "/sdcard"
              //ui_print("before:[%s]\n",update_package);
        if (strncmp(update_package, "/mnt", 4) == 0)
        {
        //jump the "/mnt"
                     update_package +=4;
              }

这样的操作跳过了上层传过来的/mnt这四个字符。另外一个值得一提的是,传入这里的这些参数都是从/cache/recovery/command这个文件中提取。具体对command文件的解析过程这里不再讲述,可能通过查看recovery.c这个文件中的get_args函数。

       那么command这个文件是在什么情况下创建的呢?下面我们就来看看吧!

恢复出厂设置和固件升级

在android的系统设备中进入“隐私权->恢复出厂设置->重置手机”将为进入到恢复出厂设置的状态,这时将会清除data、cache分区中的所有用户数据,使得系统重启后和刚刷机时一样了。另外为了方便操作我们还可在“隐私权->固件升级->刷新ROM”这里加入了固件升级这一项。

在讲述这些内容之前,我们有必要来看看/cache/recovery/command这个文件相应的一些recovery命令,这些命令都由android系统写入。所有的命令如下:

*      --send_intent=anystring ―― write the text out to recovery.intent
*      --update_package=root:path —— verify install an OTA package file
*      --wipe_data —— erase user data (and cache), then reboot
*      --wipe_cache —— wipe cache (but not user data), then reboot

恢复出厂设置

在frameworks/base/services/java/com/android/server/masterClearReceiver.java

这个文件中有如下代码:

public class MasterClearReceiver extends BroadcastReceiver {
    private static final String TAG = "MasterClear";
    @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;
            }
        }
        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 {
                    if (intent.hasExtra("enableEFS")) {
                        RecoverySystem.rebootToggleEFS(context, intent.getBooleanExtra("enableEFS", false));
                    } else {
                        RecoverySystem.rebootWipeUserData(context);
                    }
                    Log.wtf(TAG, "Still running after master clear?!");
                } catch (IOException e) {
                    Slog.e(TAG, "Can't perform master clear/factory reset", e);
                }
            }
        };
        thr.start();
    }
}
当app中操作了“恢复出厂设置”这一项时,将发出广播,这个广播将在这里被监听,然后进入到恢复出厂设置状态,我们来看看rebootWipeUserData这个方法的代码:
public static void rebootWipeUserData(Context context) throws IOException {
        final ConditionVariable condition = new ConditionVariable();
        Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
        context.sendOrderedBroadcast(intent, android.Manifest.permission.MASTER_CLEAR,
                new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        condition.open();
                    }
                }, null, 0, null, null);
        // Block until the ordered broadcast has completed.
        condition.block();
        bootCommand(context, "--wipe_data");
    }

我们可以看到在这里参入了“--wipe_data”这个参数,并把这条命令写入到command这个文件中去了,在进入recovery模式的时候解析到这条命令时就会清除data和cache中的数据了。

再来看看bootCommand这个方法里的代码:

private static void bootCommand(Context context, String arg) throws IOException {
        RECOVERY_DIR.mkdirs();  // In case we need it
        COMMAND_FILE.delete();  // In case it'

固件升级的流程和恢复出厂设置差不多,不同之处是入command这个文件中写入的命令不一样,下面是恢复出厂设置时的写命令的代码:

public static void installPackage(Context context, File packageFile)
      throws IOException {
      String filename = packageFile.getCanonicalPath();
      Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
      String arg = "--update_package=" + filename;
      bootCommand(context, arg);
  }

       这里的packageFile是由上层app传入的,内容如下:

File packageFile = new File("/sdcard/update.zip");
RecoverySystem.installPackage(context, packageFile);

       这样当系统重启进入到recovery模式时将会自动查找sdcard的根目录下是否有update.zip这个文件,如果有将会进入到update状态,否则会提示无法找到update.zip!

s not writable LOG_FILE.delete(); FileWriter command = new FileWriter(COMMAND_FILE); try { command.write(arg); command.write("\n"); } finally { command.close(); } // Having written the command file, go ahead and reboot PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); pm.reboot("recovery"); throw new IOException("Reboot failed (no permissions?)"); }
其中COMMAND_FILE这个成员的定义如下:
/** Used to communicate with recovery.  See bootable/recovery/recovery.c. */
private static File RECOVERY_DIR = new File("/cache/recovery");
private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");

       至此恢复出厂设置的命令就写入了recovery cmd file中去了,通过pm.reboot(“recovery”);重启系统,系统就自动进入到recovery模式自动清除用户数据后再重启系统。

固件升级

固件升级的流程和恢复出厂设置差不多,不同之处是入command这个文件中写入的命令不一样,下面是恢复出厂设置时的写命令的代码:

public static void installPackage(Context context, File packageFile)
      throws IOException {
      String filename = packageFile.getCanonicalPath();
      Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
      String arg = "--update_package=" + filename;
      bootCommand(context, arg);
  }

       这里的packageFile是由上层app传入的,内容如下:

File packageFile = new File("/sdcard/update.zip");
RecoverySystem.installPackage(context, packageFile);

       这样当系统重启进入到recovery模式时将会自动查找sdcard的根目录下是否有update.zip这个文件,如果有将会进入到update状态,否则会提示无法找到update.zip!


作者:Xandy


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值