Merge "recovery: Clean up try_update_binary() in install.cpp." am: 095675a3eb
am: 1bbd9c68af
Change-Id: Ia502cd3e40fb02ed01e3e91fd0892f952083b1fa
This commit is contained in:
+159
-138
@@ -14,6 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "install.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -32,6 +34,7 @@
|
|||||||
|
|
||||||
#include <android-base/file.h>
|
#include <android-base/file.h>
|
||||||
#include <android-base/logging.h>
|
#include <android-base/logging.h>
|
||||||
|
#include <android-base/parsedouble.h>
|
||||||
#include <android-base/parseint.h>
|
#include <android-base/parseint.h>
|
||||||
#include <android-base/stringprintf.h>
|
#include <android-base/stringprintf.h>
|
||||||
#include <android-base/strings.h>
|
#include <android-base/strings.h>
|
||||||
@@ -40,7 +43,6 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "error_code.h"
|
#include "error_code.h"
|
||||||
#include "install.h"
|
|
||||||
#include "minui/minui.h"
|
#include "minui/minui.h"
|
||||||
#include "otautil/SysUtil.h"
|
#include "otautil/SysUtil.h"
|
||||||
#include "roots.h"
|
#include "roots.h"
|
||||||
@@ -55,10 +57,10 @@ static constexpr const char* METADATA_PATH = "META-INF/com/android/metadata";
|
|||||||
static constexpr const char* UNCRYPT_STATUS = "/cache/recovery/uncrypt_status";
|
static constexpr const char* UNCRYPT_STATUS = "/cache/recovery/uncrypt_status";
|
||||||
|
|
||||||
// Default allocation of progress bar segments to operations
|
// Default allocation of progress bar segments to operations
|
||||||
static const int VERIFICATION_PROGRESS_TIME = 60;
|
static constexpr int VERIFICATION_PROGRESS_TIME = 60;
|
||||||
static const float VERIFICATION_PROGRESS_FRACTION = 0.25;
|
static constexpr float VERIFICATION_PROGRESS_FRACTION = 0.25;
|
||||||
static const float DEFAULT_FILES_PROGRESS_FRACTION = 0.4;
|
static constexpr float DEFAULT_FILES_PROGRESS_FRACTION = 0.4;
|
||||||
static const float DEFAULT_IMAGE_PROGRESS_FRACTION = 0.1;
|
static constexpr float DEFAULT_IMAGE_PROGRESS_FRACTION = 0.1;
|
||||||
|
|
||||||
// This function parses and returns the build.version.incremental
|
// This function parses and returns the build.version.incremental
|
||||||
static int parse_build_number(const std::string& str) {
|
static int parse_build_number(const std::string& str) {
|
||||||
@@ -299,149 +301,168 @@ update_binary_command(const char* path, ZipArchiveHandle zip, int retry_count,
|
|||||||
#endif // !AB_OTA_UPDATER
|
#endif // !AB_OTA_UPDATER
|
||||||
|
|
||||||
// If the package contains an update binary, extract it and run it.
|
// If the package contains an update binary, extract it and run it.
|
||||||
static int
|
static int try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_cache,
|
||||||
try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_cache,
|
std::vector<std::string>& log_buffer, int retry_count) {
|
||||||
std::vector<std::string>& log_buffer, int retry_count)
|
read_source_target_build(zip, log_buffer);
|
||||||
{
|
|
||||||
read_source_target_build(zip, log_buffer);
|
|
||||||
|
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
pipe(pipefd);
|
pipe(pipefd);
|
||||||
|
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
int ret = update_binary_command(path, zip, retry_count, pipefd[1], &args);
|
int ret = update_binary_command(path, zip, retry_count, pipefd[1], &args);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
close(pipefd[0]);
|
close(pipefd[0]);
|
||||||
close(pipefd[1]);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
//
|
|
||||||
// ui_print <string>
|
|
||||||
// display <string> on the screen.
|
|
||||||
//
|
|
||||||
// wipe_cache
|
|
||||||
// a wipe of cache will be performed following a successful
|
|
||||||
// installation.
|
|
||||||
//
|
|
||||||
// clear_display
|
|
||||||
// turn off the text display.
|
|
||||||
//
|
|
||||||
// enable_reboot
|
|
||||||
// packages can explicitly request that they want the user
|
|
||||||
// to be able to reboot during installation (useful for
|
|
||||||
// debugging packages that don't exit).
|
|
||||||
//
|
|
||||||
// - the name of the package zip file.
|
|
||||||
//
|
|
||||||
// - an optional argument "retry" if this update is a retry of a failed
|
|
||||||
// update attempt.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Convert the vector to a NULL-terminated char* array suitable for execv.
|
|
||||||
const char* chr_args[args.size() + 1];
|
|
||||||
chr_args[args.size()] = NULL;
|
|
||||||
for (size_t i = 0; i < args.size(); i++) {
|
|
||||||
chr_args[i] = args[i].c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
pid_t pid = fork();
|
|
||||||
|
|
||||||
if (pid == -1) {
|
|
||||||
close(pipefd[0]);
|
|
||||||
close(pipefd[1]);
|
|
||||||
PLOG(ERROR) << "Failed to fork update binary";
|
|
||||||
return INSTALL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pid == 0) {
|
|
||||||
umask(022);
|
|
||||||
close(pipefd[0]);
|
|
||||||
execv(chr_args[0], const_cast<char**>(chr_args));
|
|
||||||
fprintf(stdout, "E:Can't run %s (%s)\n", chr_args[0], strerror(errno));
|
|
||||||
_exit(-1);
|
|
||||||
}
|
|
||||||
close(pipefd[1]);
|
close(pipefd[1]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
*wipe_cache = false;
|
// When executing the update binary contained in the package, the
|
||||||
bool retry_update = false;
|
// 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.
|
||||||
|
//
|
||||||
|
// ui_print <string>
|
||||||
|
// display <string> on the screen.
|
||||||
|
//
|
||||||
|
// wipe_cache
|
||||||
|
// a wipe of cache will be performed following a successful
|
||||||
|
// installation.
|
||||||
|
//
|
||||||
|
// clear_display
|
||||||
|
// turn off the text display.
|
||||||
|
//
|
||||||
|
// enable_reboot
|
||||||
|
// packages can explicitly request that they want the user
|
||||||
|
// to be able to reboot during installation (useful for
|
||||||
|
// debugging packages that don't exit).
|
||||||
|
//
|
||||||
|
// retry_update
|
||||||
|
// updater encounters some issue during the update. It requests
|
||||||
|
// a reboot to retry the same package automatically.
|
||||||
|
//
|
||||||
|
// log <string>
|
||||||
|
// updater requests logging the string (e.g. cause of the
|
||||||
|
// failure).
|
||||||
|
//
|
||||||
|
// - the name of the package zip file.
|
||||||
|
//
|
||||||
|
// - an optional argument "retry" if this update is a retry of a failed
|
||||||
|
// update attempt.
|
||||||
|
//
|
||||||
|
|
||||||
char buffer[1024];
|
// Convert the vector to a NULL-terminated char* array suitable for execv.
|
||||||
FILE* from_child = fdopen(pipefd[0], "r");
|
const char* chr_args[args.size() + 1];
|
||||||
while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
|
chr_args[args.size()] = nullptr;
|
||||||
char* command = strtok(buffer, " \n");
|
for (size_t i = 0; i < args.size(); i++) {
|
||||||
if (command == NULL) {
|
chr_args[i] = args[i].c_str();
|
||||||
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);
|
pid_t pid = fork();
|
||||||
int seconds = strtol(seconds_s, NULL, 10);
|
|
||||||
|
|
||||||
ui->ShowProgress(fraction * (1-VERIFICATION_PROGRESS_FRACTION), seconds);
|
if (pid == -1) {
|
||||||
} else if (strcmp(command, "set_progress") == 0) {
|
close(pipefd[0]);
|
||||||
char* fraction_s = strtok(NULL, " \n");
|
close(pipefd[1]);
|
||||||
float fraction = strtof(fraction_s, NULL);
|
PLOG(ERROR) << "Failed to fork update binary";
|
||||||
ui->SetProgress(fraction);
|
return INSTALL_ERROR;
|
||||||
} else if (strcmp(command, "ui_print") == 0) {
|
}
|
||||||
char* str = strtok(NULL, "\n");
|
|
||||||
if (str) {
|
if (pid == 0) {
|
||||||
ui->PrintOnScreenOnly("%s", str);
|
umask(022);
|
||||||
} else {
|
close(pipefd[0]);
|
||||||
ui->PrintOnScreenOnly("\n");
|
execv(chr_args[0], const_cast<char**>(chr_args));
|
||||||
}
|
PLOG(ERROR) << "Can't run " << chr_args[0];
|
||||||
fflush(stdout);
|
_exit(-1);
|
||||||
} else if (strcmp(command, "wipe_cache") == 0) {
|
}
|
||||||
*wipe_cache = true;
|
close(pipefd[1]);
|
||||||
} else if (strcmp(command, "clear_display") == 0) {
|
|
||||||
ui->SetBackground(RecoveryUI::NONE);
|
*wipe_cache = false;
|
||||||
} else if (strcmp(command, "enable_reboot") == 0) {
|
bool retry_update = false;
|
||||||
// packages can explicitly request that they want the user
|
|
||||||
// to be able to reboot during installation (useful for
|
char buffer[1024];
|
||||||
// debugging packages that don't exit).
|
FILE* from_child = fdopen(pipefd[0], "r");
|
||||||
ui->SetEnableReboot(true);
|
while (fgets(buffer, sizeof(buffer), from_child) != nullptr) {
|
||||||
} else if (strcmp(command, "retry_update") == 0) {
|
std::string line(buffer);
|
||||||
retry_update = true;
|
size_t space = line.find_first_of(" \n");
|
||||||
} else if (strcmp(command, "log") == 0) {
|
std::string command(line.substr(0, space));
|
||||||
// Save the logging request from updater and write to
|
if (command.empty()) continue;
|
||||||
// last_install later.
|
|
||||||
log_buffer.push_back(std::string(strtok(NULL, "\n")));
|
// Get rid of the leading and trailing space and/or newline.
|
||||||
} else {
|
std::string args = space == std::string::npos ? "" : android::base::Trim(line.substr(space));
|
||||||
LOG(ERROR) << "unknown command [" << command << "]";
|
|
||||||
}
|
if (command == "progress") {
|
||||||
|
std::vector<std::string> tokens = android::base::Split(args, " ");
|
||||||
|
double fraction;
|
||||||
|
int seconds;
|
||||||
|
if (tokens.size() == 2 && android::base::ParseDouble(tokens[0].c_str(), &fraction) &&
|
||||||
|
android::base::ParseInt(tokens[1], &seconds)) {
|
||||||
|
ui->ShowProgress(fraction * (1 - VERIFICATION_PROGRESS_FRACTION), seconds);
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "invalid \"progress\" parameters: " << line;
|
||||||
|
}
|
||||||
|
} else if (command == "set_progress") {
|
||||||
|
std::vector<std::string> tokens = android::base::Split(args, " ");
|
||||||
|
double fraction;
|
||||||
|
if (tokens.size() == 1 && android::base::ParseDouble(tokens[0].c_str(), &fraction)) {
|
||||||
|
ui->SetProgress(fraction);
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "invalid \"set_progress\" parameters: " << line;
|
||||||
|
}
|
||||||
|
} else if (command == "ui_print") {
|
||||||
|
if (!args.empty()) {
|
||||||
|
ui->PrintOnScreenOnly("%s", args.c_str());
|
||||||
|
} else {
|
||||||
|
ui->PrintOnScreenOnly("\n");
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
} else if (command == "wipe_cache") {
|
||||||
|
*wipe_cache = true;
|
||||||
|
} else if (command == "clear_display") {
|
||||||
|
ui->SetBackground(RecoveryUI::NONE);
|
||||||
|
} else if (command == "enable_reboot") {
|
||||||
|
// packages can explicitly request that they want the user
|
||||||
|
// to be able to reboot during installation (useful for
|
||||||
|
// debugging packages that don't exit).
|
||||||
|
ui->SetEnableReboot(true);
|
||||||
|
} else if (command == "retry_update") {
|
||||||
|
retry_update = true;
|
||||||
|
} else if (command == "log") {
|
||||||
|
if (!args.empty()) {
|
||||||
|
// Save the logging request from updater and write to last_install later.
|
||||||
|
log_buffer.push_back(args);
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "invalid \"log\" parameters: " << line;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "unknown command [" << command << "]";
|
||||||
}
|
}
|
||||||
fclose(from_child);
|
}
|
||||||
|
fclose(from_child);
|
||||||
|
|
||||||
int status;
|
int status;
|
||||||
waitpid(pid, &status, 0);
|
waitpid(pid, &status, 0);
|
||||||
if (retry_update) {
|
if (retry_update) {
|
||||||
return INSTALL_RETRY;
|
return INSTALL_RETRY;
|
||||||
}
|
}
|
||||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||||
LOG(ERROR) << "Error in " << path << " (Status " << WEXITSTATUS(status) << ")";
|
LOG(ERROR) << "Error in " << path << " (Status " << WEXITSTATUS(status) << ")";
|
||||||
return INSTALL_ERROR;
|
return INSTALL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return INSTALL_SUCCESS;
|
return INSTALL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|||||||
Reference in New Issue
Block a user