概要
本文描述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)
待补充