// If the package contains an update binary, extract it and run it. static int try_update_binary(const char *path, ZipArchive *zip) { const ZipEntry* binary_entry = mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME); if (binary_entry == NULL) { return INSTALL_CORRUPT; } char* binary = "/tmp/update_binary"; unlink(binary); int fd = creat(binary, 0755); if (fd < 0) { LOGE("Can't make %s\n", binary); return 1; } bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd); close(fd); 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.) // // 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(stderr, "E:Can't run %s (%s)\n", binary, strerror(errno)); _exit(-1); } close(pipefd[1]); char* firmware_type = NULL; char* firmware_filename = NULL; char buffer[81]; FILE* from_child = fdopen(pipefd[0], "r"); while (fgets(buffer, sizeof(buffer), from_child) != NULL) { LOGI("read: %s", buffer); 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, "firmware") == 0) { char* type = strtok(NULL, " \n"); char* filename = strtok(NULL, " \n"); if (type != NULL && filename != NULL) { if (firmware_type != NULL) { LOGE("ignoring attempt to do multiple firmware updates"); } else { firmware_type = strdup(type); firmware_filename = strdup(filename); } } } else if (strcmp(command, "ui_print") == 0) { char* str = strtok(NULL, "\n"); if (str) { printf(str); } else { printf("\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; } if (firmware_type != NULL) { return handle_firmware_update(firmware_type, firmware_filename, zip); } else { return INSTALL_SUCCESS; } }
// If the package contains an update binary, extract it and run it. static int try_update_binary(const char *path, ZipArchive *zip) { int custom_binary = 0; const ZipEntry* or_script_entry = mzFindZipEntry(zip, ASSUMED_OR_UPDATE_SCRIPT_NAME); if (or_script_entry != NULL) { ui_print("使用shell脚本...\n"); return handle_or_update(path, zip); } const ZipEntry* binary_entry = mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME); if (binary_entry == NULL) ui_print("使用默认的updater...\n"); else custom_binary = 1; char* binary = "/tmp/update_binary"; unlink(binary); if (custom_binary) { int fd = creat(binary, 0755); if (fd < 0) { LOGE("无法制作%s\n", binary); return 1; } bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd); close(fd); if (!ok) { LOGE("无法复制%s\n", ASSUMED_UPDATE_BINARY_NAME); return 1; } } else binary = DEFAULT_UPDATE_BINARY_NAME; ui_show_indeterminate_progress(); 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.) // // ui_print <string> // display <string> on the screen. // // stasis // quit the gui // - 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(stderr, "E:无法运行%s (%s)\n", binary, strerror(errno)); _exit(-1); } close(pipefd[1]); char* firmware_type = NULL; char* firmware_filename = NULL; char buffer[1024]; FILE* from_child = fdopen(pipefd[0], "r"); ui_set_progress(0.0); 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, 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, "firmware") == 0) { char* type = strtok(NULL, " \n"); char* filename = strtok(NULL, " \n"); if (type != NULL && filename != NULL) { if (firmware_type != NULL) LOGE("忽略试图进行多个固件更新"); else { firmware_type = strdup(type); firmware_filename = strdup(filename); } } } else if (strcmp(command, "ui_print") == 0) { char* str = strtok(NULL, "\n"); if (str) ui_print(str); else ui_print("\n"); } else LOGE("未知命令[%s]\n", command); } fclose(from_child); int status; waitpid(pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { LOGE("错误!代码%s\n(Status %d)\n", path, WEXITSTATUS(status)); return INSTALL_ERROR; } if (firmware_type != NULL) return handle_firmware_update(firmware_type, firmware_filename, zip); else return INSTALL_SUCCESS; }