Merge "Reboot and retry on I/O errors" into nyc-dev
This commit is contained in:
commit
d345de66ef
5 changed files with 118 additions and 11 deletions
|
@ -144,6 +144,7 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) {
|
||||||
close(pipefd[1]);
|
close(pipefd[1]);
|
||||||
|
|
||||||
*wipe_cache = false;
|
*wipe_cache = false;
|
||||||
|
bool retry_update = false;
|
||||||
|
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
FILE* from_child = fdopen(pipefd[0], "r");
|
FILE* from_child = fdopen(pipefd[0], "r");
|
||||||
|
@ -180,6 +181,8 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) {
|
||||||
// to be able to reboot during installation (useful for
|
// to be able to reboot during installation (useful for
|
||||||
// debugging packages that don't exit).
|
// debugging packages that don't exit).
|
||||||
ui->SetEnableReboot(true);
|
ui->SetEnableReboot(true);
|
||||||
|
} else if (strcmp(command, "retry_update") == 0) {
|
||||||
|
retry_update = true;
|
||||||
} else {
|
} else {
|
||||||
LOGE("unknown command [%s]\n", command);
|
LOGE("unknown command [%s]\n", command);
|
||||||
}
|
}
|
||||||
|
@ -188,6 +191,9 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) {
|
||||||
|
|
||||||
int status;
|
int status;
|
||||||
waitpid(pid, &status, 0);
|
waitpid(pid, &status, 0);
|
||||||
|
if (retry_update) {
|
||||||
|
return INSTALL_RETRY;
|
||||||
|
}
|
||||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||||
LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status));
|
LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status));
|
||||||
return INSTALL_ERROR;
|
return INSTALL_ERROR;
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE, INSTALL_SKIPPED };
|
enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE, INSTALL_SKIPPED,
|
||||||
|
INSTALL_RETRY };
|
||||||
// Install the package specified by root_path. If INSTALL_SUCCESS is
|
// Install the package specified by root_path. If INSTALL_SUCCESS is
|
||||||
// returned and *wipe_cache is true on exit, caller should wipe the
|
// returned and *wipe_cache is true on exit, caller should wipe the
|
||||||
// cache partition.
|
// cache partition.
|
||||||
|
|
|
@ -38,6 +38,8 @@ static std::string FaultFileName =
|
||||||
#endif // defined (TARGET_READ_FAULT)
|
#endif // defined (TARGET_READ_FAULT)
|
||||||
#endif // defined (TARGET_INJECT_FAULTS)
|
#endif // defined (TARGET_INJECT_FAULTS)
|
||||||
|
|
||||||
|
bool have_eio_error = false;
|
||||||
|
|
||||||
int ota_open(const char* path, int oflags) {
|
int ota_open(const char* path, int oflags) {
|
||||||
#if defined (TARGET_INJECT_FAULTS)
|
#if defined (TARGET_INJECT_FAULTS)
|
||||||
// Let the caller handle errors; we do not care if open succeeds or fails
|
// Let the caller handle errors; we do not care if open succeeds or fails
|
||||||
|
@ -90,12 +92,22 @@ size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream) {
|
||||||
&& FilenameCache[(intptr_t)stream] == FaultFileName) {
|
&& FilenameCache[(intptr_t)stream] == FaultFileName) {
|
||||||
FaultFileName = "";
|
FaultFileName = "";
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
|
have_eio_error = true;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return fread(ptr, size, nitems, stream);
|
size_t status = fread(ptr, size, nitems, stream);
|
||||||
|
// If I/O error occurs, set the retry-update flag.
|
||||||
|
if (status != nitems && errno == EIO) {
|
||||||
|
have_eio_error = true;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return fread(ptr, size, nitems, stream);
|
size_t status = fread(ptr, size, nitems, stream);
|
||||||
|
if (status != nitems && errno == EIO) {
|
||||||
|
have_eio_error = true;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,12 +117,21 @@ ssize_t ota_read(int fd, void* buf, size_t nbyte) {
|
||||||
&& FilenameCache[fd] == FaultFileName) {
|
&& FilenameCache[fd] == FaultFileName) {
|
||||||
FaultFileName = "";
|
FaultFileName = "";
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
|
have_eio_error = true;
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
return read(fd, buf, nbyte);
|
ssize_t status = read(fd, buf, nbyte);
|
||||||
|
if (status == -1 && errno == EIO) {
|
||||||
|
have_eio_error = true;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return read(fd, buf, nbyte);
|
ssize_t status = read(fd, buf, nbyte);
|
||||||
|
if (status == -1 && errno == EIO) {
|
||||||
|
have_eio_error = true;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,12 +141,21 @@ size_t ota_fwrite(const void* ptr, size_t size, size_t count, FILE* stream) {
|
||||||
&& FilenameCache[(intptr_t)stream] == FaultFileName) {
|
&& FilenameCache[(intptr_t)stream] == FaultFileName) {
|
||||||
FaultFileName = "";
|
FaultFileName = "";
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
|
have_eio_error = true;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return fwrite(ptr, size, count, stream);
|
size_t status = fwrite(ptr, size, count, stream);
|
||||||
|
if (status != count && errno == EIO) {
|
||||||
|
have_eio_error = true;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return fwrite(ptr, size, count, stream);
|
size_t status = fwrite(ptr, size, count, stream);
|
||||||
|
if (status != count && errno == EIO) {
|
||||||
|
have_eio_error = true;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,12 +165,21 @@ ssize_t ota_write(int fd, const void* buf, size_t nbyte) {
|
||||||
&& FilenameCache[fd] == FaultFileName) {
|
&& FilenameCache[fd] == FaultFileName) {
|
||||||
FaultFileName = "";
|
FaultFileName = "";
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
|
have_eio_error = true;
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
return write(fd, buf, nbyte);
|
ssize_t status = write(fd, buf, nbyte);
|
||||||
|
if (status == -1 && errno == EIO) {
|
||||||
|
have_eio_error = true;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return write(fd, buf, nbyte);
|
ssize_t status = write(fd, buf, nbyte);
|
||||||
|
if (status == -1 && errno == EIO) {
|
||||||
|
have_eio_error = true;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,10 +190,19 @@ int ota_fsync(int fd) {
|
||||||
FaultFileName = "";
|
FaultFileName = "";
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
return -1;
|
||||||
|
have_eio_error = true;
|
||||||
} else {
|
} else {
|
||||||
return fsync(fd);
|
int status = fsync(fd);
|
||||||
|
if (status == -1 && errno == EIO) {
|
||||||
|
have_eio_error = true;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return fsync(fd);
|
int status = fsync(fd);
|
||||||
|
if (status == -1 && errno == EIO) {
|
||||||
|
have_eio_error = true;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
45
recovery.cpp
45
recovery.cpp
|
@ -36,6 +36,7 @@
|
||||||
|
|
||||||
#include <adb.h>
|
#include <adb.h>
|
||||||
#include <android-base/file.h>
|
#include <android-base/file.h>
|
||||||
|
#include <android-base/parseint.h>
|
||||||
#include <android-base/stringprintf.h>
|
#include <android-base/stringprintf.h>
|
||||||
#include <cutils/android_reboot.h>
|
#include <cutils/android_reboot.h>
|
||||||
#include <cutils/properties.h>
|
#include <cutils/properties.h>
|
||||||
|
@ -60,6 +61,7 @@ struct selabel_handle *sehandle;
|
||||||
static const struct option OPTIONS[] = {
|
static const struct option OPTIONS[] = {
|
||||||
{ "send_intent", required_argument, NULL, 'i' },
|
{ "send_intent", required_argument, NULL, 'i' },
|
||||||
{ "update_package", required_argument, NULL, 'u' },
|
{ "update_package", required_argument, NULL, 'u' },
|
||||||
|
{ "retry_count", required_argument, NULL, 'n' },
|
||||||
{ "wipe_data", no_argument, NULL, 'w' },
|
{ "wipe_data", no_argument, NULL, 'w' },
|
||||||
{ "wipe_cache", no_argument, NULL, 'c' },
|
{ "wipe_cache", no_argument, NULL, 'c' },
|
||||||
{ "show_text", no_argument, NULL, 't' },
|
{ "show_text", no_argument, NULL, 't' },
|
||||||
|
@ -89,6 +91,7 @@ static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
|
||||||
static const char *LAST_KMSG_FILE = "/cache/recovery/last_kmsg";
|
static const char *LAST_KMSG_FILE = "/cache/recovery/last_kmsg";
|
||||||
static const char *LAST_LOG_FILE = "/cache/recovery/last_log";
|
static const char *LAST_LOG_FILE = "/cache/recovery/last_log";
|
||||||
static const int KEEP_LOG_COUNT = 10;
|
static const int KEEP_LOG_COUNT = 10;
|
||||||
|
static const int EIO_RETRY_COUNT = 2;
|
||||||
static const int BATTERY_READ_TIMEOUT_IN_SEC = 10;
|
static const int BATTERY_READ_TIMEOUT_IN_SEC = 10;
|
||||||
// GmsCore enters recovery mode to install package when having enough battery
|
// GmsCore enters recovery mode to install package when having enough battery
|
||||||
// percentage. Normally, the threshold is 40% without charger and 20% with charger.
|
// percentage. Normally, the threshold is 40% without charger and 20% with charger.
|
||||||
|
@ -1162,6 +1165,29 @@ static bool is_battery_ok() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_retry_bootloader_message(int retry_count, int argc, char** argv) {
|
||||||
|
struct bootloader_message boot {};
|
||||||
|
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
|
||||||
|
strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
|
||||||
|
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
if (strstr(argv[i], "retry_count") == nullptr) {
|
||||||
|
strlcat(boot.recovery, argv[i], sizeof(boot.recovery));
|
||||||
|
strlcat(boot.recovery, "\n", sizeof(boot.recovery));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize counter to 1 if it's not in BCB, otherwise increment it by 1.
|
||||||
|
if (retry_count == 0) {
|
||||||
|
strlcat(boot.recovery, "--retry_count=1\n", sizeof(boot.recovery));
|
||||||
|
} else {
|
||||||
|
char buffer[20];
|
||||||
|
snprintf(buffer, sizeof(buffer), "--retry_count=%d\n", retry_count+1);
|
||||||
|
strlcat(boot.recovery, buffer, sizeof(boot.recovery));
|
||||||
|
}
|
||||||
|
set_bootloader_message(&boot);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
// If this binary is started with the single argument "--adbd",
|
// If this binary is started with the single argument "--adbd",
|
||||||
// instead of being the normal recovery binary, it turns into kind
|
// instead of being the normal recovery binary, it turns into kind
|
||||||
|
@ -1197,11 +1223,13 @@ int main(int argc, char **argv) {
|
||||||
bool sideload_auto_reboot = false;
|
bool sideload_auto_reboot = false;
|
||||||
bool just_exit = false;
|
bool just_exit = false;
|
||||||
bool shutdown_after = false;
|
bool shutdown_after = false;
|
||||||
|
int retry_count = 0;
|
||||||
|
|
||||||
int arg;
|
int arg;
|
||||||
while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
|
while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
|
||||||
switch (arg) {
|
switch (arg) {
|
||||||
case 'i': send_intent = optarg; break;
|
case 'i': send_intent = optarg; break;
|
||||||
|
case 'n': android::base::ParseInt(optarg, &retry_count, 0); break;
|
||||||
case 'u': update_package = optarg; break;
|
case 'u': update_package = optarg; break;
|
||||||
case 'w': should_wipe_data = true; break;
|
case 'w': should_wipe_data = true; break;
|
||||||
case 'c': should_wipe_cache = true; break;
|
case 'c': should_wipe_cache = true; break;
|
||||||
|
@ -1306,7 +1334,24 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
if (status != INSTALL_SUCCESS) {
|
if (status != INSTALL_SUCCESS) {
|
||||||
ui->Print("Installation aborted.\n");
|
ui->Print("Installation aborted.\n");
|
||||||
|
// When I/O error happens, reboot and retry installation EIO_RETRY_COUNT
|
||||||
|
// times before we abandon this OTA update.
|
||||||
|
if (status == INSTALL_RETRY && retry_count < EIO_RETRY_COUNT) {
|
||||||
|
copy_logs();
|
||||||
|
set_retry_bootloader_message(retry_count, argc, argv);
|
||||||
|
// Print retry count on screen.
|
||||||
|
ui->Print("Retry attempt %d\n", retry_count);
|
||||||
|
|
||||||
|
// Reboot and retry the update
|
||||||
|
int ret = property_set(ANDROID_RB_PROPERTY, "reboot,recovery");
|
||||||
|
if (ret < 0) {
|
||||||
|
ui->Print("Reboot failed\n");
|
||||||
|
} else {
|
||||||
|
while (true) {
|
||||||
|
pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// If this is an eng or userdebug build, then automatically
|
// If this is an eng or userdebug build, then automatically
|
||||||
// turn the text display on if the script fails so the error
|
// turn the text display on if the script fails so the error
|
||||||
// message is visible.
|
// message is visible.
|
||||||
|
|
|
@ -35,6 +35,8 @@
|
||||||
// (Note it's "updateR-script", not the older "update-script".)
|
// (Note it's "updateR-script", not the older "update-script".)
|
||||||
#define SCRIPT_NAME "META-INF/com/google/android/updater-script"
|
#define SCRIPT_NAME "META-INF/com/google/android/updater-script"
|
||||||
|
|
||||||
|
extern bool have_eio_error;
|
||||||
|
|
||||||
struct selabel_handle *sehandle;
|
struct selabel_handle *sehandle;
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
@ -139,6 +141,11 @@ int main(int argc, char** argv) {
|
||||||
state.errmsg = NULL;
|
state.errmsg = NULL;
|
||||||
|
|
||||||
char* result = Evaluate(&state, root);
|
char* result = Evaluate(&state, root);
|
||||||
|
|
||||||
|
if (have_eio_error) {
|
||||||
|
fprintf(cmd_pipe, "retry_update\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
if (state.errmsg == NULL) {
|
if (state.errmsg == NULL) {
|
||||||
printf("script aborted (no error message)\n");
|
printf("script aborted (no error message)\n");
|
||||||
|
|
Loading…
Reference in a new issue