Recovery模式的命令行参数

概要


本文描述Android应用层要进入recovery模式时,需要设定参数的方式、以及参数的格式。


应用层的调用场景

有如下的场景需要让手机重启进入recovery模式:

  • 系统升级;
  • 恢复出厂设置


RecoverySystem.java

// \frameworks\base\core\java\android\os\RecoverySystem.java
 * fails, or if the reboot itself fails.
 */
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 +
        "\n--locale=" + Locale.getDefault().toString();
    bootCommand(context, arg);
}

/**
 * Reboots the device and wipes the user data partition.  This is
 * sometimes called a "factory reset", which is something of a
 * misnomer because the system partition is not restored to its
 * factory state.
 * Requires the {@link android.Manifest.permission#REBOOT} permission.
 *
 * @param context  the Context to use
 *
 * @throws IOException  if writing the recovery command file
 * fails, or if the reboot itself fails.
 */
public static void rebootWipeUserData(Context context) throws IOException {
    final ConditionVariable condition = new ConditionVariable();

    Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
    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);

    // Block until the ordered broadcast has completed.
    condition.block();

    bootCommand(context, "--wipe_data\n--locale=" + Locale.getDefault().toString());
}

/**
 * Reboot into the recovery system to wipe the /cache partition.
 * @throws IOException if something goes wrong.
 */
public static void rebootWipeCache(Context context) throws IOException {
    bootCommand(context, "--wipe_cache\n--locale=" + Locale.getDefault().toString());
}

/**
 * Reboot into the recovery system with the supplied argument.
 * @param arg to pass to the recovery utility.
 * @throws IOException if something goes wrong.
 */
private static void bootCommand(Context context, String arg) throws IOException {
    RECOVERY_DIR.mkdirs();  // In case we need it
    COMMAND_FILE.delete();  // In case it'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?)");
}

这里包括了:

  • installPackage:系统升级,比如FOTA、组合按键进入recovery,等等
  • rebootWipeUserData:重启用于擦除用户数据(恢复出厂设置);
  • rebootWipeCache:擦除cache分区

所有这些都通过COMMAND_FILE(/cache/recovery/command)文件来给recovery传递命令行参数。


command文件的格式

如同上面代码所描述的,command文件中,每个参数占用一行;每个参数本身采用--parName=parValue的格式。如:

--wipe_data
--locale=en

因为Android底层是Linux,所以换行使用的是\n,而不是\r\n。——参考上面的java代码。当然,recovery为了提高可靠性,增加了容错处理。下面是recovery.cpp中的处理过程:

// \bootable\recovery\recovery.cpp

// --- if that doesn't work, try the command file
if (*argc <= 1) {
    FILE *fp = fopen_path(COMMAND_FILE, "r");
    if (fp != NULL) {
        char *token;
        char *argv0 = (*argv)[0];
        *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
        (*argv)[0] = argv0;  // use the same program name

        char buf[MAX_ARG_LENGTH];
        for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
            if (!fgets(buf, sizeof(buf), fp)) break;
            token = strtok(buf, "\r\n");
            if (token != NULL) {
                (*argv)[*argc] = strdup(token);  // Strip newline.
            } else {
                --*argc;
            }
        }

        check_and_fclose(fp, COMMAND_FILE);
        LOGI("Got arguments from %s\n", COMMAND_FILE);
    }
}

recovery支持的命令行参数

recovery支持的参数由recovery.cpp中的OPTIONS来定义:

static const struct option OPTIONS[] = {
  { "send_intent", required_argument, NULL, 's' },
  { "update_package", required_argument, NULL, 'u' },
  { "wipe_data", no_argument, NULL, 'w' },
  { "wipe_cache", no_argument, NULL, 'c' },
  { "show_text", no_argument, NULL, 't' },
  { "just_exit", no_argument, NULL, 'x' },
  { "locale", required_argument, NULL, 'l' },
  { NULL, 0, NULL, 0 },
};

事实上,各个厂商可以根据需求而进行扩展,只要recovery和上层应用保持一致即可。——在Recovery模式下的文本显示一文中讲到了locale的注意事项,如前面Java代码给出的,传入的是Locale.toString(),而不是Locale.getLanguage()。


BCB (Bootloader Control Block)

待补充

接下来分析应用层如何进入recovery模式的,包括ShutdownThread.java、android_reboot.c等的分析。



你可能感兴趣的:(Android)