现在的位置: 首页 > 综合 > 正文

FSL Android Recovery Mode

2013年10月04日 ⁄ 综合 ⁄ 共 19335字 ⁄ 字号 评论关闭

FSL i.Mx53的Android Recovery Mode已经在i.MX_Android_R10.3_User_Guide.html这个文件中有介绍,引用如下:

4.5.6 Software Update and Wipe Partition using Recovery Mode

It is possible to format the /data and /cache partitions or update software based on a update script
using recovery mode as follows:

  • Prepare for all android source code that assumed to be saved in ~/myandroid directory. 

  • Prepare for ADB over USB. make sure that ADB over USB is ok. USB cable is connected. Refer toADB over USB section for more information.

  • Connect the UART to the PC and open a terminal to check for printed messages

  • Enter the recovery by manual

       for imx51_BBG board:
      
setenv bootargs_android_recovery 'setenv bootargs ${bootargs} init=/init root=/dev/mmcblk0p4 rootfs=ext4 di1_primary'
       setenv bootcmd_android_recovery 'run bootargs_android_recovery;mmc read 0 ${loadaddr} 0x800 0x2000;bootm'
       run bootcmd_android_recovery

       For imx53_SMD board:
       
setenv bootargs_android_recovery 'setenv bootargs ${bootargs} init=/init root=/dev/mmcblk0p4 rootfs=ext4'
       setenv bootcmd_android_recovery 'run bootargs_android_recovery;mmc read

1 ${loadaddr} 0x800 0x2000;bootm'
       run bootcmd_android_recovery

  • When system had complete to bootup,  You will see this screen:

  • You can press"MENU" "HOME" or "F1"(by USB keyboard, for developer)" going to thetext menu
    like this:

  • Select the required option using the direction keys on the keypad or keyboard.

    • Apply sdcard:update.zip, you may update the software from update.zip as shown in the following example:

      • Copy this directory from android source code myandroid/bootable/recovery/etc to a tempepory directory, such as ~/recovery. 

      • cd ~/recovery and remove init.rc from this directory. 

      • Edit ./META-INF/com/google/android/updater-script according to the required commands. for example, in order to format /system partition and use update.zip to update system partition, copy whole the entire content directory
        to system partition, all commands are found in ~/myandroid/bootable/recovery/update/install.c

      • You must notice, when your signing the zip package, it will lose ALL of the permission information, you need to set the right permission in the script. You can find the example in ./META-INF/com/google/android/update-script

      • Copy update-binary, Copy out/target/product/YOU_PRODUCT/system/bin/updater to ~/reocvery/META-INFO/com/google/android/update-binary

      • Create a directory called systemand copy some files you would like to update to ./system.

      • Create a directory calledres
        to save the public key of your system.

        fsl@fsl-desktop:~/recovery$ mkdir res
        fsl@fsl-desktop:~/recovery$ ~/myandroid/out/host/linux-x86/framework/dumpkey.jar ~/myandroid/build/target/product/security/testkey.x509.pem > res/keys

      • Create a package called recovery.zip using the zip command

fsl@fsl-desktop:~/recovery$zip recovery.zip -r ./META-INF ./system ./res

      • recovery.zip is located in the current directory. Then create a digital signature for recovery.zip package as follows.

fsl@fsl-desktop:~/recovery$ cd ~/myandroid

fsl@fsl-desktop:~/myandroid$ make signapk

fsl@fsl-desktop:~/myandroid$ cd ~/recovery

fsl@fsl-desktop:~/recovery$ java -jar ~/myandroid/out/host/linux-x86/framework/signapk.jar -w ~/myandroid/build/target/product/security/testkey.x509.pem ~/myandroid/build/target/product/security/testkey.pk8
recovery.zip recovery_signed.zip

      • recovery_signed.zip is located in the current directory. Copy it to the SD card using ADB

fsl@fsl-desktop:~/recovery$ adb push recovery_signed.zip /sdcard/update.zip

      • update.zip is completed and the system is updated based on the commands in the update-script. Check for error messages on the LCD. 

    • Wipe data/factory reset. /data and /cache partitions are formatted.

    • Wipe cache partition. /cache partition is formatted. 

        

  • Reboot the system. 

  • About system upgrade method:
            You upgrade mode can be change per your needs, which is written in your update-script, you should change the script, it's very fixable, here is the flow:   
    • copy file and dirs from package to devices(you can use this method upgrade a few of files/dirs.), below is rough step in script.

      • format the /system partition if needed (option)

      • mount /system partition

      • package_extract_dir command to extract system dir in updater.zip to /system/

      • change the permissions, since signapk will clean up permission of files, you need set the permission by your self, you can refer the update-script, but maybe you need add some permission if needed.

      • umount /system partition.

    • use fake_dd command in update-script to dd whole system.img from update.zip to device (New)

      • use fake_dd command to dd system.img file in your update.zip to your mmc block device.

      • (This is much less script needs to write)

  • About Kernel/uramdisk/U-boot upgrade:

       
You can use this function to upgrade your kernel and u-boot, this also need change the update-script.

    • For Nand devices: you can use the write_raw_image() command upgrade your boot.img, like other android system.

    • For SD/eMMC devices: you need use fake_dd command to dd your image to your device(written in update-script.), eg:

          

      ui_print("extract kernel image...");

      package_extract_file("files/uImage", "/tmp/uImage");

      # Write uImage to 1M position.

      ui_print("writting kernel image");

      simple_dd("/tmp/uImage", "/dev/block/mmcblk0", 1048576);


      ui_print("extract uramdisk image...");

      package_extract_file("files/uramdisk.img", "/tmp/uramdisk.img");

      # Write uImage to 1M position.

      ui_print("writting uramdisk image");

      simple_dd("/tmp/uramdisk", "/dev/block/mmcblk0", 6291456);

      show_progress(0.1, 5);


      For uboot upgrade for eMMC storage, since u-boot maybe stored in the "boot partition" of eMMC, you need do some sys file operation before dd, eg:

    •     

      # Write u-boot to 1K position.

      # u-boot binary should be a no padding uboot!

      # For eMMC(iNand) device, needs to unlock boot partition.

      ui_print("writting u-boot...");

      sysfs_file_write("class/mmc_host/mmc0/mmc0:0001/boot_config", "1");

      package_extract_file("files/u-boot-no-padding.bin", "/tmp/u-boot-no-padding.bin");

      simple_dd("/tmp/u-boot-no-padding.bin", "/dev/block/mmcblk0", 1024);

      sysfs_file_write("class/mmc_host/mmc0/mmc0:0001/boot_config", "8");

      show_progress(0.1, 5);

           You can find the detail example in source code:  bootable\recovery\etc\META-INF\com\google\android\update-script

           Please choose them per your needs.

 

根据以上说明,流程分析如下:

1、uboot设置进入recovery

开机启动boot->start_armboot->check_recovery_mode->setup_recovery_env进行设置启动参数如下:

       setenv bootargs_android_recovery 'setenv bootargs ${bootargs} init=/init root=/dev/mmcblk0p4 rootfs=ext4'
       setenv bootcmd_android_recovery 'run bootargs_android_recovery;mmc read

1
${loadaddr} 0x800 0x2000;bootm'

       run bootcmd_android_recovery

此时 root=/dev/mmcblk0p4,启动boot和kernel后,会进入recovery模式。

 

2、recovery模式

  系统进入recovery模式启动(参考recovery\recovery.c),运行如下代码:

int
main(int argc, char **argv) {
    time_t start = time(NULL);

    // If these fail, there's not really anywhere to complain...
    freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL);
    freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);
    printf("Harvey Starting recovery on %s", ctime(&start));
    printf("Harvey Starting recovery on %s", ctime(&start));

    ui_init();
    ui_set_background(BACKGROUND_ICON_INSTALLING);
    load_volume_table();
    get_args(&argc, &argv);       

    int previous_runs = 0;
    const char *send_intent = NULL;
    const char *update_package = NULL;
    const char *encrypted_fs_mode = NULL;
    int wipe_data = 0, wipe_cache = 0;
    int toggle_secure_fs = 0;
    encrypted_fs_info encrypted_fs_data;

    int arg;
    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();

    LOGI("Command:");
    for (arg = 0; arg < argc; arg++) {
        LOGI(" \"%s\"", argv[arg]);
    }
    LOGI("\n");

    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);
            fprintf("(replacing path \"%s\" with \"%s\")\n",
                   update_package, modified_path);
            update_package = modified_path;
        }

	LOGI("update from :[%s]\n",update_package);
 	ui_print("install package from[%s]\n",update_package);
     }
    LOGI("\n");


    property_list(print_property, NULL);
    LOGI("\n");

    int status = INSTALL_SUCCESS;

    if (toggle_secure_fs) {
        if (strcmp(encrypted_fs_mode,"on") == 0) {
            encrypted_fs_data.mode = MODE_ENCRYPTED_FS_ENABLED;
            ui_print("Enabling Encrypted FS.\n");
        } else if (strcmp(encrypted_fs_mode,"off") == 0) {
            encrypted_fs_data.mode = MODE_ENCRYPTED_FS_DISABLED;
            ui_print("Disabling Encrypted FS.\n");
        } else {
            ui_print("Error: invalid Encrypted FS setting.\n");
            status = INSTALL_ERROR;
        }

        // Recovery strategy: if the data partition is damaged, disable encrypted file systems.
        // This preventsthe device recycling endlessly in recovery mode.
        if ((encrypted_fs_data.mode == MODE_ENCRYPTED_FS_ENABLED) &&
                (read_encrypted_fs_info(&encrypted_fs_data))) {
            ui_print("Encrypted FS change aborted, resetting to disabled state.\n");
            encrypted_fs_data.mode = MODE_ENCRYPTED_FS_DISABLED;
        }

        if (status != INSTALL_ERROR) {
            if (erase_volume("/data")) {
                ui_print("Data wipe failed.\n");
                status = INSTALL_ERROR;
            } else if (erase_volume("/cache")) {
                ui_print("Cache wipe failed.\n");
                status = INSTALL_ERROR;
            } else if ((encrypted_fs_data.mode == MODE_ENCRYPTED_FS_ENABLED) &&
                      (restore_encrypted_fs_info(&encrypted_fs_data))) {
                ui_print("Encrypted FS change aborted.\n");
                status = INSTALL_ERROR;
            } else {
                ui_print("Successfully updated Encrypted FS.\n");
                status = INSTALL_SUCCESS;
            }   
        }
    } else if (update_package != NULL)     
    {
		//erase_volume("/data");
		erase_volume("/cache");
		//erase_volume("/system"); 
        status = install_package(update_package);  
        if (status != INSTALL_SUCCESS) 
			ui_print("Installation aborted.\n");
    } 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;
}

 

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' },
  { "set_encrypted_filesystems", required_argument, NULL, 'e' },
  { "show_text", no_argument, NULL, 't' },
  { NULL, 0, NULL, 0 },
};

        进入系统后,首先是画一个基本的UI底图,通过get_args(跟踪其是对/cache/recovery/command这个文件的解析,具体的写操作后续介绍)和OPTIONS获得启动参数。通过OPTIONS可以看出来,参数为send_intent、update_package、wipe_data、wipe_cache、set_encrypted_filesystems、show_text几种。

 

3、update package

update package即为系统升级,将调用到install_package(update_package)。

 

int
install_package(const char *path)
{
    ui_set_background(BACKGROUND_ICON_INSTALLING);
    ui_print("Finding update package...\n");
    ui_show_indeterminate_progress();
    LOGI("Update location: %s\n", path);

    if (ensure_path_mounted(path) != 0) {
        LOGE("Can't mount %s\n", path);
        return INSTALL_CORRUPT;
    }

    ui_print("Opening update package...\n");

    int numKeys;
    RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);
    if (loadedKeys == NULL) {
        LOGE("Failed to load keys\n");
        return INSTALL_CORRUPT;
    }
    LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);

    // Give verification half the progress bar...
    ui_print("Verifying update package...\n");
    ui_show_progress(
            VERIFICATION_PROGRESS_FRACTION,
            VERIFICATION_PROGRESS_TIME);

    int err;
    err = verify_file(path, loadedKeys, numKeys);
    free(loadedKeys);
    LOGI("verify_file returned %d\n", err);
    if (err != VERIFY_SUCCESS) {
        LOGE("signature verification failed\n");
        return INSTALL_CORRUPT;
    }

    /* Try to open the package.
     */
    ZipArchive zip;
    err = mzOpenZipArchive(path, &zip);
    if (err != 0) {
        LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad");
        return INSTALL_CORRUPT;
    }

    /* Verify and install the contents of the package.
     */
    ui_print("Installing update...\n");
    return try_update_binary(path, &zip);
}

 

这里主要完成文件的key钥匙校验,其文件位于/res/keys,校验成功之后,调用try_update_binary(path, &zip)。

  
static int
try_update_binary(const char *path, ZipArchive *zip) {
    const ZipEntry* binary_entry =
            mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
    if (binary_entry == NULL) {
        mzCloseZipArchive(zip);
        return INSTALL_CORRUPT;
    }

    char* binary = "/tmp/update_binary";
    unlink(binary);
    int fd = creat(binary, 0755);
    if (fd < 0) {
        mzCloseZipArchive(zip);
        LOGE("Can't make %s\n", binary);
        return 1;
    }
    bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
    close(fd);
    mzCloseZipArchive(zip);

    if (!ok) {
        LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);
        return 1;
    }

    int pipefd[2];
    pipe(pipefd);

    // When executing the update binary contained in the package, the
    // arguments passed are:
    //
    //   - the version number for this interface
    //
    //   - an fd to which the program can write in order to update the
    //     progress bar.  The program can write single-line commands:
    //
    //        progress <frac> <secs>
    //            fill up the next <frac> part of of the progress bar
    //            over <secs> seconds.  If <secs> is zero, use
    //            set_progress commands to manually control the
    //            progress of this segment of the bar
    //
    //        set_progress <frac>
    //            <frac> should be between 0.0 and 1.0; sets the
    //            progress bar within the segment defined by the most
    //            recent progress command.
    //
    //        firmware <"hboot"|"radio"> <filename>
    //            arrange to install the contents of <filename> in the
    //            given partition on reboot.
    //
    //            (API v2: <filename> may start with "PACKAGE:" to
    //            indicate taking a file from the OTA package.)
    //
    //            (API v3: this command no longer exists.)
    //
    //        ui_print <string>
    //            display <string> on the screen.
    //
    //   - the name of the package zip file.
    //

    char** args = malloc(sizeof(char*) * 5);
    args[0] = binary;
    args[1] = EXPAND(RECOVERY_API_VERSION);   // defined in Android.mk
    args[2] = malloc(10);
    sprintf(args[2], "%d", pipefd[1]);
    args[3] = (char*)path;
    args[4] = NULL;

    pid_t pid = fork();
    if (pid == 0) {
        close(pipefd[0]);
        execv(binary, args);
        fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno));
        _exit(-1);
    }
    close(pipefd[1]);

    char buffer[1024];
    FILE* from_child = fdopen(pipefd[0], "r");
    while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
        char* command = strtok(buffer, " \n");
        if (command == NULL) {
            continue;
        } else if (strcmp(command, "progress") == 0) {
            char* fraction_s = strtok(NULL, " \n");
            char* seconds_s = strtok(NULL, " \n");

            float fraction = strtof(fraction_s, NULL);
            int seconds = strtol(seconds_s, NULL, 10);

            ui_show_progress(fraction * (1-VERIFICATION_PROGRESS_FRACTION),
                             seconds);
        } else if (strcmp(command, "set_progress") == 0) {
            char* fraction_s = strtok(NULL, " \n");
            float fraction = strtof(fraction_s, NULL);
            ui_set_progress(fraction);
        } else if (strcmp(command, "ui_print") == 0) {
            char* str = strtok(NULL, "\n");
            if (str) {
                ui_print("%s", str);
            } else {
                ui_print("\n");
            }
        } else {
            LOGE("unknown command [%s]\n", command);
        }
    }
    fclose(from_child);

    int status;
    waitpid(pid, &status, 0);
    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
        LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status));
        return INSTALL_ERROR;
    }

    return INSTALL_SUCCESS;
}

        首先查找update-binary文件,并execv这个文件,这个文件源代码是bootable\recovery\updater\updater.c。

4、updater 及updater-script

        updater将完成对updater-script的解析,其源码如下:

int main(int argc, char** argv) {
    // Various things log information to stdout or stderr more or less
    // at random.  The log file makes more sense if buffering is
    // turned off so things appear in the right order.
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);

    if (argc != 4) {
        fprintf(stderr, "unexpected number of arguments (%d)\n", argc);
        return 1;
    }

    char* version = argv[1];
    if ((version[0] != '1' && version[0] != '2' && version[0] != '3') ||
        version[1] != '\0') {
        // We support version 1, 2, or 3.
        fprintf(stderr, "wrong updater binary API; expected 1, 2, or 3; "
                        "got %s\n",
                argv[1]);
        return 2;
    }

    // Set up the pipe for sending commands back to the parent process.

    int fd = atoi(argv[2]);
    FILE* cmd_pipe = fdopen(fd, "wb");
    setlinebuf(cmd_pipe);

    // Extract the script from the package.

    char* package_data = argv[3];
    ZipArchive za;
    int err;
    err = mzOpenZipArchive(package_data, &za);
    if (err != 0) {
        fprintf(stderr, "failed to open package %s: %s\n",
                package_data, strerror(err));
        return 3;
    }

    const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME);
    if (script_entry == NULL) {
        fprintf(stderr, "failed to find %s in %s\n", SCRIPT_NAME, package_data);
        return 4;
    }

    char* script = malloc(script_entry->uncompLen+1);
    if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) {
        fprintf(stderr, "failed to read script from package\n");
        return 5;
    }
    script[script_entry->uncompLen] = '\0';

    // Configure edify's functions.

    RegisterBuiltins();
    RegisterInstallFunctions();
    RegisterDeviceExtensions();
    FinishRegistration();

    // Parse the script.

    Expr* root;
    int error_count = 0;
    yy_scan_string(script);
    int error = yyparse(&root, &error_count);
    if (error != 0 || error_count > 0) {
        fprintf(stderr, "%d parse errors\n", error_count);
        return 6;
    }

    // Evaluate the parsed script.

    UpdaterInfo updater_info;
    updater_info.cmd_pipe = cmd_pipe;
    updater_info.package_zip = &za;
    updater_info.version = atoi(version);

    State state;
    state.cookie = &updater_info;
    state.script = script;
    state.errmsg = NULL;

    char* result = Evaluate(&state, root);
    if (result == NULL) {
        if (state.errmsg == NULL) {
            fprintf(stderr, "script aborted (no error message)\n");
            fprintf(cmd_pipe, "ui_print script aborted (no error message)\n");
        } else {
            fprintf(stderr, "script aborted: %s\n", state.errmsg);
            char* line = strtok(state.errmsg, "\n");
            while (line) {
                fprintf(cmd_pipe, "ui_print %s\n", line);
                line = strtok(NULL, "\n");
            }
            fprintf(cmd_pipe, "ui_print\n");
        }
        free(state.errmsg);
        return 7;
    } else {
        fprintf(stderr, "script result was [%s]\n", result);
        free(result);
    }

    if (updater_info.package_zip) {
        mzCloseZipArchive(updater_info.package_zip);
    }
    free(script);

    return 0;
}

argv[3]为package的路径,通过其查找"META-INF/com/google/android/updater-script"这个文件,并根据script进行系统的升级操作。

updater-script可以参考fsl文档的介绍 来写了。

根据文档来看,系统采用的SD/eMMC devices,因此要使用fake_dd这个命令来更新系统文件,需要注意的是,对于uboot来说,使用的是u-boot-no-padding.bin这个没有填充的bin,如不是,请参考编译文档介绍,进行生成;另外请注意script里升级system时的选择,请根据自己生成的升级文件进行选择

# You can use two way to update your system which using ext4 system.
# 1. dd hole system.img to your mmcblk0p2 partition.
# 2. format system/ ;copy files under system dir in update.zip; change the premissions.
#   [ This operation may cause recovery script very complex, if you are just update few files, please choose this operation    

 

5、升级界面

升级界面可以参考Settings->Privacy->Factory data reset这个界面来编写,不同的是在frameworks\base\services\java\com\android\server\MasterClearReceiver.java中,修改成升级需要的command。

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();
    }

 

    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");
    }

 

    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?)");
    }

通过上述代码可知,此处便是往COMMAND_FILE(/cache/recovery/command) 写--wipe_data 这个命令,对照recovery模式中的OPTIONS,便可清楚。

那么,对应于update,只要烧写命令--update_package+文件路径即可。

抱歉!评论已关闭.