Rockchip RK3588 - Rockchip Linux Recovery recovery原始碼分析

大奥特曼打小怪兽發表於2024-10-06

----------------------------------------------------------------------------------------------------------------------------

開發板 :ArmSoM-Sige7開發板
eMMC64GB
LPDDR48GB
螢幕 :15.6英寸HDMI介面螢幕
u-boot2017.09
linux5.10
----------------------------------------------------------------------------------------------------------------------------

在《Rockchip RK3588 - Rockchip Linux Recovery updateEngine原始碼分析》中我們對updateEngine原始碼進行了深入分析,並提到updateEngine 升級命令由兩部分組成;

  • normal系統下的升級:升級recovery分割槽,並修改misc分割槽,重啟系統;
  • recovery系統下的升級:系統重啟之後,會根據misc分割槽存放的欄位來判斷將要引導的系統是normal系統還是recovery系統,這裡會進入到recovery系統,進行剩餘分割槽的升級;

其中normal系統下的升級是透過updateEngine可執行程式完成的;

// 1. 在normal系統,updateEngine升級recovery分割槽;升級完函式就返回了,並不會升級其它分割槽
main(argc, argv)
	MiscUpdate(image_url, partition, save_path)		
		//  對需要執行的升級命令打標記(這裡標記了parameter、recovery升級命令)
		RK_ota_set_partition(0x040000)   
		// 進行parameter、recovery分割槽升級
		RK_ota_start(handle_upgrade_callback, handle_print_callback)
		// 往misc偏移16k位置寫入recovery資訊,這樣系統重啟後會進入recovery系統執行剩餘分割槽的升級
		set_bootloader_message(&msg)
		
	// 2. 觸發系統重啟
	system(" echo b > /proc/sysrq-trigger ")

recovery系統下的升級,是透過recovery可執行程式實現,recovery二進位制bin程式部會根據編譯配置呼叫updateEngine或者rkupdate進行升級,本章的目標就是對recovery原始碼進行分析。

一、recovery目標分析

1.1 目標recovery

定位到<Rockchip Linux SDK>/external/recovery目錄下的Makefile檔案,找到目標recovery;

OBJ = recovery.o \
        default_recovery_ui.o \
        rktools.o \
        roots.o \
        bootloader.o \
        safe_iop.o \
        strlcpy.o \
        strlcat.o \
        rkupdate.o \
        sdboot.o \
        usbboot.o \
        mtdutils/mounts.o \
        mtdutils/mtdutils.o \
        mtdutils/rk29.o \
        minzip/DirUtil.o \
        update_engine/log.o

ifdef RecoveryNoUi  
OBJ += noui.o      # 不走這裡
else
OBJ += ui.o\       # 走這裡  
        minzip/Hash.o \
        minzip/SysUtil.o \
        minzip/Zip.o \
        minui/events.o \
        minui/graphics.o \
        minui/resources.o \
        minui/graphics_drm.o
endif

CFLAGS += -I$(PROJECT_DIR) -I/usr/include -I/usr/include/libdrm/ -lc -DUSE_UPDATEENGINE=ON

ifdef RecoveryNoUi
CFLAGS += -lpthread -lbz2        # 不走這裡
else
CFLAGS += -lz -lpng -ldrm -lpthread -lcurl -lcrypto -lbz2   # 走這裡  
endif

$(PROM): $(OBJ)
        $(CC) -o $(PROM) $(OBJ) $(CFLAGS)

可以看到目標recovery是由若干個.o檔案透過aarch64-buildroot-linux-gnu-gcc編譯器連結生成的可執行檔案。

.o檔案實際上是由.c檔案透過aarch64-buildroot-linux-gnu-gcc編譯器編譯生成的。

# build in buildroot, it need change work directory
recovery_version:
        cd $(PROJECT_DIR)/../../../../../external/recovery && \
        COMMIT_HASH=$$(git rev-parse --verify --short HEAD) && \
        GIT_COMMIT_TIME=$$(git log -1 --format=%cd --date=format:%y%m%d) && \
        GIT_DIRTY=$$(git diff-index --quiet HEAD -- || echo "-dirty") && \
        commit_info=-g$${COMMIT_HASH}-$${GIT_COMMIT_TIME}$${GIT_DIRTY} && \
        cd $(PROJECT_DIR) && \
        echo "#define GIT_COMMIT_INFO $${commit_info}" > recovery_autogenerate.h

%.o: %.cpp
        $(CC) -c $< -o $@ $(CFLAGS)

%.o: %.c recovery_version
        $(CC) -c $< -o $@ $(CFLAGS)

其中:%.o 表示所有以.o結尾的檔案作為目標檔案,%.cpp 表示所有以.c結尾的檔案作為依賴檔案。

程式的入口為update_engine/main.cpp檔案。

1.2 編譯

在《Rockchip RK3588 - Rockchip Linux SDK Buildroot檔案系統構建》中介紹過buildroot編譯命令;

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make -j8

或者使用如下命令單獨編譯recovery軟體包:

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make recovery-dirclean
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make recovery

其中recovery編譯日誌如下:

>>> recovery develop Syncing from source dir /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/../external/recovery
rsync -au --chmod=u=rwX,go=rX  --exclude .svn --exclude .git --exclude .hg --exclude .bzr --exclude CVS /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/../external/recovery/ /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/recovery-develop
>>> recovery develop Configuring
>>> recovery develop Building
PATH="/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin" /usr/bin/make  -C /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/recovery-develop CC="/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-gcc" CFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -I. -fPIC -lpthread -lcurl -lssl -lcrypto -lbz2 -lpng -ldrm -lz -lm -I/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/aarch64-buildroot-linux-gnu/sysroot/usr/include/libdrm -DUSE_UPDATEENGINE=ON -DSUCCESSFUL_BOOT=ON"
make[1]: 進入目錄“/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/recovery-develop”
cd /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/recovery-develop/../../../../../external/recovery && \
COMMIT_HASH=$(git rev-parse --verify --short HEAD) && \
GIT_COMMIT_TIME=$(git log -1 --format=%cd --date=format:%y%m%d) && \
GIT_DIRTY=$(git diff-index --quiet HEAD -- || echo "-dirty") && \
commit_info=-g${COMMIT_HASH}-${GIT_COMMIT_TIME}${GIT_DIRTY} && \
cd /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/recovery-develop && \
echo "#define GIT_COMMIT_INFO ${commit_info}" > recovery_autogenerate.h
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-gcc -c recovery.c -o recovery.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -I. -fPIC -lpthread -lcurl -lssl -lcrypto -lbz2 -lpng -ldrm -lz -lm -I/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/aarch64-buildroot-linux-gnu/sysroot/usr/include/libdrm -DUSE_UPDATEENGINE=ON -DSUCCESSFUL_BOOT=ON
......
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-gcc -o updateEngine mtdutils/mounts.o mtdutils/mtdutils.o mtdutils/rk29.o update_engine/rkbootloader.o update_engine/download.o update_engine/flash_image.o update_engine/log.o update_engine/main.o update_engine/md5sum.o update_engine/rkimage.o update_engine/rktools.o update_engine/rkboot.o update_engine/crc.o update_engine/update.o update_engine/do_patch.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -I. -fPIC -lpthread -lcurl -lssl -lcrypto -lbz2 -lpng -ldrm -lz -lm -I/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/aarch64-buildroot-linux-gnu/sysroot/usr/include/libdrm -DUSE_UPDATEENGINE=ON -DSUCCESSFUL_BOOT=ON
make[1]: 離開目錄“/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/recovery-develop”
>>> recovery develop Installing to target
/usr/bin/install -D -m 755 /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/recovery-develop/recovery /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/target/usr/bin/
mkdir -p /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/target/res/images
cp /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/recovery-develop/res/images/* /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/target/res/images/
/usr/bin/install -D -m 755 /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/recovery-develop/updateEngine /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/target/usr/bin/
/usr/bin/install -D -m 755 package/rockchip/recovery//S40recovery /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/target/etc/init.d/S40recovery

二、recovery原始碼分析

recovery程式的入口為recovery.c檔案。recovery.c程式碼比較長,如下所示:

點開檢視詳情
int
main(int argc, char **argv)
{
    bool bSDBoot    = false;
    bool bUDiskBoot = false;
    const char *sdupdate_package = NULL;
    const char *usbupdate_package = NULL;
    int previous_runs = 0;
    const char *send_intent = NULL;
    const char *update_package = NULL;
    const char *encrypted_fs_mode = NULL;
    int wipe_data = 0;
    int wipe_all = 0;
    int pcba_test = 0;  // add for pcba test
    int toggle_secure_fs = 0;
    int arg;
    bool isrkdebug = false;
    int log_level = LOG_DEBUG;
    encrypted_fs_info encrypted_fs_data;
    struct timeval start_time, end_time;
    long long elapsed_time;

    gettimeofday(&start_time, NULL);
    
    get_args(&argc, &argv);
    strcpy(systemFlag, "false");
    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 = 1;
            break;
        case 'a':
            wipe_all = 1;
            break;
        case 'e':
            encrypted_fs_mode = optarg;
            toggle_secure_fs = 1;
            break;
        case 't':
            ui_show_text(1);
            break;
        case 'f':
            pcba_test = 1;
            break;  // add for pcba test
        case 'r':
            isrkdebug = true;
            break;
        case 'i':
            gr_set_rotate(atoi(optarg));
            break;
        case '?':
            LOGE("Invalid command argument\n");
            continue;
        }
    }
    
    time_t start = time(NULL);
    if ((access("/.rkdebug", F_OK) != 0) && (isrkdebug != true)) {
        // If these fail, there's not really anywhere to complain...
        if (freopen(TEMPORARY_LOG_FILE, "a", stdout) == NULL) {
            LOGW("freopen stdout error");
        }
        setbuf(stdout, NULL);
        if (freopen(TEMPORARY_LOG_FILE, "a", stderr) == NULL) {
            LOGE("freopen stderr error");
        }
        setbuf(stderr, NULL);
    }
    
    printf("\n");
    printf("*********************************************************\n");
    printf("            ROCKCHIP recovery system                     \n");
    printf("*********************************************************\n");
    printf("**** version : %s ****\n", recovery_version);
    
    LOGI("Starting recovery on %s\n", ctime(&start));
    while (access(coldboot_done, F_OK) != 0) {
        LOGI("coldboot not done, wait...\n");
        sleep(1);
    }

#ifndef RecoveryNoUi
    LOGI("Recovery System have UI defined.\n");
#endif

    ui_init();
    ui_set_background(BACKGROUND_ICON_INSTALLING);
    load_volume_table();
    setFlashPoint();
    
    bSDBoot = is_boot_from_SD();
    bUDiskBoot = is_boot_from_udisk();
    
    if (bSDBoot || bUDiskBoot) {
        char imageFile[64] = {0};
        if (bSDBoot) {
            if (is_sdcard_update()) {
                strlcpy(imageFile, EX_SDCARD_ROOT, sizeof(imageFile));
                strlcat(imageFile, "/sdupdate.img", sizeof(imageFile));
                if (access(imageFile, F_OK) == 0) {
                    sdupdate_package = strdup(imageFile);
                    bSDBootUpdate = true;
                    ui_show_text(1);
                    LOGI("sdupdate_package = %s\n", sdupdate_package);
                }
            }
        }
    
        if (bUDiskBoot) {
            if (is_udisk_update()) {
                strlcpy(imageFile, EX_UDISK_ROOT, sizeof(imageFile));
                strlcat(imageFile, "/sdupdate.img", sizeof(imageFile));
                if (access(imageFile, F_OK) == 0) {
                    usbupdate_package = strdup(imageFile);
                    bUdiskUpdate = true;
                    ui_show_text(1);
                    LOGI("usbupdate_package = %s\n", usbupdate_package);
                }
            }
        }
    }
    
    device_recovery_start();
    
    LOGI("Command:");
    for (arg = 0; arg < argc; arg++) {
        printf(" \"%s\"", argv[arg]);
    }
    printf("\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);
            LOGI("(replacing path \"%s\" with \"%s\")\n",
                 update_package, modified_path);
            update_package = modified_path;
        }
    }
    printf("\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("/userdata")) {
                ui_print("Data wipe failed.\n");
                status = INSTALL_ERROR;
#if 0
            } else if (erase_volume("/cache")) {
                ui_print("Cache wipe failed.\n");
                status = INSTALL_ERROR;
#endif
            } 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) {
        int i, ret = 0;
        const char* binary = "/usr/bin/rkupdate";

        rockchip_partition_check();
    
        for (i = 0; i < 5; i++) {
            if (!ensure_path_mounted(update_package)) {
                LOGI("mounted %s Success.\n", update_package);
                break;
            }
            LOGW("mounted %s Failed. retry %d\n", update_package, i + 1);
            sleep(1);
        }
        if (i != 5) {
            LOGI(">>>rkflash will update from %s\n", update_package);
#ifdef USE_RKUPDATE
            status = do_rk_update(binary, update_package);
#endif
#ifdef USE_UPDATEENGINE
            const char* updateEnginebin = "/usr/bin/updateEngine";
            status = do_rk_updateEngine(updateEnginebin, update_package);
#endif
            if (status == INSTALL_SUCCESS) {
                strcpy(systemFlag, update_package);
                /* update success, delete update.img. */
                if (access(update_package, F_OK) == 0)
                    remove(update_package);
                ui_print("update.img images success!\n");
            } else {
                ui_print("update.img images failed!\n");
            }
        } else {
            LOGE("mounted %s Failed.\n", update_package);
            ui_print("mounted %s Failed.\n", update_package);
        }

        if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n");
        ui_print("update.img Installation done.\n");
        //ui_show_text(0);
    } else if (sdupdate_package != NULL) {
        rockchip_partition_check();
    
        // update image from sdcard
#ifdef USE_RKUPDATE
        const char* binary = "/usr/bin/rkupdate";
        LOGI(">>>sdboot update will update from %s\n", sdupdate_package);
        status = do_rk_update(binary, sdupdate_package);
#endif

#ifdef USE_UPDATEENGINE
#undef FACTORY_FIRMWARE_IMAGE
#undef CMD4RECOVERY_FILENAME
#define FACTORY_FIRMWARE_IMAGE "/mnt/sdcard/out_image.img"
#define CMD4RECOVERY_FILENAME "/mnt/sdcard/cmd4recovery"
        if ((access(FACTORY_FIRMWARE_IMAGE, F_OK)) && access(CMD4RECOVERY_FILENAME, F_OK)) {
            int tmp_fd = creat(CMD4RECOVERY_FILENAME, 0777);
            if (tmp_fd < 0) {
                LOGE("creat %s error.\n", CMD4RECOVERY_FILENAME);
                status = INSTALL_ERROR;
            } else {
                close(tmp_fd);
                const char* updateEnginebin = "/usr/bin/updateEngine";
                status = do_rk_updateEngine(updateEnginebin, sdupdate_package);
            }
        }

        if (isMtdDevice()) {
            LOGI("start flash write to /dev/mtd0.\n");
            size_t total_size;
            size_t erase_size;
            mtd_scan_partitions();
            const MtdPartition *part = mtd_find_partition_by_name("rk-nand");
            if ( part == NULL ) {
                part = mtd_find_partition_by_name("spi-nand0");
            }
            if (part == NULL || mtd_partition_info(part, &total_size, &erase_size, NULL)) {
                if ((!access(FACTORY_FIRMWARE_IMAGE, F_OK)) && mtd_find_partition_by_name("sfc_nor") != NULL) {
                    LOGI("Info: start flash out_image.img to spi nor.\n");
                    system("flashcp -v " FACTORY_FIRMWARE_IMAGE " /dev/mtd0");
                } else
                    LOGE("Error: Can't find rk-nand or spi-nand0.\n");
            } else {
                system("flash_erase /dev/mtd0 0x0 0");
                system("sh "CMD4RECOVERY_FILENAME);
            }
        } else {
            LOGI("Start to dd data to emmc partition.\n");
            system("sh "CMD4RECOVERY_FILENAME);
            LOGI("sdcard upgrade done\n");
        }

#endif

        if (status == INSTALL_SUCCESS) {
            LOGI("update.img Installation success.\n");
            ui_print("update.img Installation success.\n");
            //ui_show_text(0);
        }
    
    } else if (usbupdate_package != NULL) {
        rockchip_partition_check();
        // update image from udisk
#ifdef USE_RKUPDATE
        const char* binary = "/usr/bin/rkupdate";
        LOGI(">>>sdboot update will update from %s\n", usbupdate_package);
        status = do_rk_update(binary, usbupdate_package);
#endif

#ifdef USE_UPDATEENGINE
#undef FACTORY_FIRMWARE_IMAGE
#undef CMD4RECOVERY_FILENAME
#define FACTORY_FIRMWARE_IMAGE "/mnt/usb_storage/out_image.img"
#define CMD4RECOVERY_FILENAME "/mnt/usb_storage/cmd4recovery"
        if ((access(FACTORY_FIRMWARE_IMAGE, F_OK)) && access(CMD4RECOVERY_FILENAME, F_OK)) {
            int tmp_fd = creat(CMD4RECOVERY_FILENAME, 0777);
            if (tmp_fd < 0) {
                LOGE("creat %s error.\n", CMD4RECOVERY_FILENAME);
                status = INSTALL_ERROR;
            } else {
                close(tmp_fd);
                const char* updateEnginebin = "/usr/bin/updateEngine";
                status = do_rk_updateEngine(updateEnginebin, usbupdate_package);
            }
        }

        if (isMtdDevice()) {
            LOGI("start flash write to /dev/mtd0.\n");
            size_t total_size;
            size_t erase_size;
            mtd_scan_partitions();
            const MtdPartition *part = mtd_find_partition_by_name("rk-nand");
            if ( part == NULL ) {
                part = mtd_find_partition_by_name("spi-nand0");
            }
            if (part == NULL || mtd_partition_info(part, &total_size, &erase_size, NULL)) {
                if ((!access(FACTORY_FIRMWARE_IMAGE, F_OK)) && mtd_find_partition_by_name("sfc_nor") != NULL) {
                    LOGI("Info: start flash out_image.img to spi nor.\n");
                    system("flashcp -v " FACTORY_FIRMWARE_IMAGE " /dev/mtd0");
                } else
                    LOGE("Error: Can't find rk-nand or spi-nand0.\n");
            } else {
                system("flash_erase /dev/mtd0 0x0 0");
                system("sh "CMD4RECOVERY_FILENAME);
            }
        } else {
            LOGI("Start to dd data to emmc partition.\n");
            system("sh "CMD4RECOVERY_FILENAME);
            LOGI("usb upgrade done\n");
        }
#endif

        if (status == INSTALL_SUCCESS) {
            LOGI("update.img Installation success.\n");
            ui_print("update.img Installation success.\n");
            //ui_show_text(0);
        }
    } else if (wipe_data) {
        if (device_wipe_data()) status = INSTALL_ERROR;
        if (erase_volume("/userdata")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n");
    } else if (wipe_all) {
        if (device_wipe_data()) status = INSTALL_ERROR;
        if (erase_volume("/userdata")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) {
            ui_print("Data wipe failed.\n");
            LOGE("userdata wipe failed.\n");
        } else {
            ui_print("Data wipe done.\n");
            LOGI("userdata wipe done.\n");
        }
    
        //ui_show_text(0);
    } else if (pcba_test) {
        //pcba test todo...
        printf("------------------ pcba test start -------------\n");
        exit(EXIT_SUCCESS); //exit recovery bin directly, not start pcba here, in rkLanuch.sh
        return 0;
    } else {
        if (argc == 1) { // No command specified
            if (!bSDBootUpdate && !bUdiskUpdate && ui_text_visible())
                prompt_and_wait();
            finish_recovery(NULL);
            reboot(RB_AUTOBOOT);
            return 0;
        }
        status = INSTALL_ERROR;  // No command specified
    }
    
    if (status != INSTALL_SUCCESS) ui_set_background(BACKGROUND_ICON_ERROR);
    if (status != INSTALL_SUCCESS) {
        LOGE("\n Install fail! \n");
        if (!bSDBootUpdate && !bUdiskUpdate && ui_text_visible())
            prompt_and_wait();
    }
    
    if (sdupdate_package != NULL && bSDBootUpdate) {
        if (status == INSTALL_SUCCESS) {
            char *SDDdevice =
                strdup(get_mounted_device_from_path(EX_SDCARD_ROOT));
    
            ensure_ex_path_unmounted(EX_SDCARD_ROOT);
            /* Updating is finished here, we must print this message
             * in console, it shows user a specific message that
             * updating is completely, remove SD CARD and reboot */
            fflush(stdout);
            freopen("/dev/console", "w", stdout);
            LOGI("\nPlease remove SD CARD!!!, wait for reboot.\n");
            ui_print("Please remove SD CARD!!!, wait for reboot.");
    
            while (access(SDDdevice, F_OK) == 0) { sleep(1); }
            free(SDDdevice);
        }
    } else if (usbupdate_package && bUdiskUpdate) {
        if (status == INSTALL_SUCCESS) {
            char *udiskDev = strdup(get_mounted_device_from_path(EX_SDCARD_ROOT));
            ensure_path_unmounted(EX_UDISK_ROOT);
            /* Updating is finished here, we must print this message
             * in console, it shows user a specific message that
             * updating is completely, remove U-disk and reboot */
            fflush(stdout);
            freopen("/dev/console", "w", stdout);
            LOGI("\nPlease remove U DISK!!!, wait for reboot.\n");
            ui_print("Please remove U DISK!!!, wait for reboot.");
    
            while (access(udiskDev, F_OK) == 0) { sleep(1); }
            free(udiskDev);
        }
    }
    
    // Otherwise, get ready to boot the main system...
    finish_recovery(send_intent);
    gettimeofday(&end_time, NULL);
    
    elapsed_time = (end_time.tv_sec - start_time.tv_sec) * 1000LL +
                   (end_time.tv_usec - start_time.tv_usec) / 1000LL;
    LOGI("recovery usage time:%lld ms\n", elapsed_time);
    ui_print("Rebooting...\n");
    LOGI("Reboot...\n");
    ui_show_text(0);
    fflush(stdout);
    sync();
    reboot(RB_AUTOBOOT);
    return EXIT_SUCCESS;
}

參考文章:

[1] Rockchip RK3588 - Rockchip Linux Recovery updateEngine原始碼分析

[2] Rockchip RK3588 - Rockchip Linux Recovery updateEngine測試

相關文章