allow recovery packages to wipe cache
updater now has a function "wipe_cache();" which causes recovery to wipe the cache partition after the successful installation of the package. Move log copying around a bit so logs and the last_install flag file are copied to cache after it's wiped. Bug: 5314244 Change-Id: Id35a9eb6dcd626c8f3a3a0076074f462ed3d44bd
This commit is contained in:
parent
441031dadc
commit
d0181b8fcd
4 changed files with 71 additions and 26 deletions
23
install.c
23
install.c
|
@ -36,11 +36,9 @@
|
||||||
#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary"
|
#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary"
|
||||||
#define PUBLIC_KEYS_FILE "/res/keys"
|
#define PUBLIC_KEYS_FILE "/res/keys"
|
||||||
|
|
||||||
static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install";
|
|
||||||
|
|
||||||
// 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, ZipArchive *zip) {
|
try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
|
||||||
const ZipEntry* binary_entry =
|
const ZipEntry* binary_entry =
|
||||||
mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
|
mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
|
||||||
if (binary_entry == NULL) {
|
if (binary_entry == NULL) {
|
||||||
|
@ -54,7 +52,7 @@ try_update_binary(const char *path, ZipArchive *zip) {
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
mzCloseZipArchive(zip);
|
mzCloseZipArchive(zip);
|
||||||
LOGE("Can't make %s\n", binary);
|
LOGE("Can't make %s\n", binary);
|
||||||
return 1;
|
return INSTALL_ERROR;
|
||||||
}
|
}
|
||||||
bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
|
bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
@ -62,7 +60,7 @@ try_update_binary(const char *path, ZipArchive *zip) {
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);
|
LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);
|
||||||
return 1;
|
return INSTALL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
|
@ -119,6 +117,8 @@ try_update_binary(const char *path, ZipArchive *zip) {
|
||||||
}
|
}
|
||||||
close(pipefd[1]);
|
close(pipefd[1]);
|
||||||
|
|
||||||
|
*wipe_cache = 0;
|
||||||
|
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
FILE* from_child = fdopen(pipefd[0], "r");
|
FILE* from_child = fdopen(pipefd[0], "r");
|
||||||
while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
|
while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
|
||||||
|
@ -145,6 +145,8 @@ try_update_binary(const char *path, ZipArchive *zip) {
|
||||||
} else {
|
} else {
|
||||||
ui_print("\n");
|
ui_print("\n");
|
||||||
}
|
}
|
||||||
|
} else if (strcmp(command, "wipe_cache") == 0) {
|
||||||
|
*wipe_cache = 1;
|
||||||
} else {
|
} else {
|
||||||
LOGE("unknown command [%s]\n", command);
|
LOGE("unknown command [%s]\n", command);
|
||||||
}
|
}
|
||||||
|
@ -236,7 +238,7 @@ exit:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
really_install_package(const char *path)
|
really_install_package(const char *path, int* wipe_cache)
|
||||||
{
|
{
|
||||||
ui_set_background(BACKGROUND_ICON_INSTALLING);
|
ui_set_background(BACKGROUND_ICON_INSTALLING);
|
||||||
ui_print("Finding update package...\n");
|
ui_print("Finding update package...\n");
|
||||||
|
@ -285,25 +287,24 @@ really_install_package(const char *path)
|
||||||
/* Verify and install the contents of the package.
|
/* Verify and install the contents of the package.
|
||||||
*/
|
*/
|
||||||
ui_print("Installing update...\n");
|
ui_print("Installing update...\n");
|
||||||
return try_update_binary(path, &zip);
|
return try_update_binary(path, &zip, wipe_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
install_package(const char* path)
|
install_package(const char* path, int* wipe_cache, const char* install_file)
|
||||||
{
|
{
|
||||||
FILE* install_log = fopen_path(LAST_INSTALL_FILE, "w");
|
FILE* install_log = fopen_path(install_file, "w");
|
||||||
if (install_log) {
|
if (install_log) {
|
||||||
fputs(path, install_log);
|
fputs(path, install_log);
|
||||||
fputc('\n', install_log);
|
fputc('\n', install_log);
|
||||||
} else {
|
} else {
|
||||||
LOGE("failed to open last_install: %s\n", strerror(errno));
|
LOGE("failed to open last_install: %s\n", strerror(errno));
|
||||||
}
|
}
|
||||||
int result = really_install_package(path);
|
int result = really_install_package(path, wipe_cache);
|
||||||
if (install_log) {
|
if (install_log) {
|
||||||
fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log);
|
fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log);
|
||||||
fputc('\n', install_log);
|
fputc('\n', install_log);
|
||||||
fclose(install_log);
|
fclose(install_log);
|
||||||
chmod(LAST_INSTALL_FILE, 0644);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,10 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT };
|
enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT };
|
||||||
int install_package(const char *root_path);
|
// Install the package specified by root_path. If INSTALL_SUCCESS is
|
||||||
|
// returned and *wipe_cache is true on exit, caller should wipe the
|
||||||
|
// cache partition.
|
||||||
|
int install_package(const char *root_path, int* wipe_cache,
|
||||||
|
const char* install_file);
|
||||||
|
|
||||||
#endif // RECOVERY_INSTALL_H_
|
#endif // RECOVERY_INSTALL_H_
|
||||||
|
|
58
recovery.c
58
recovery.c
|
@ -52,9 +52,11 @@ static const char *COMMAND_FILE = "/cache/recovery/command";
|
||||||
static const char *INTENT_FILE = "/cache/recovery/intent";
|
static const char *INTENT_FILE = "/cache/recovery/intent";
|
||||||
static const char *LOG_FILE = "/cache/recovery/log";
|
static const char *LOG_FILE = "/cache/recovery/log";
|
||||||
static const char *LAST_LOG_FILE = "/cache/recovery/last_log";
|
static const char *LAST_LOG_FILE = "/cache/recovery/last_log";
|
||||||
|
static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install";
|
||||||
static const char *CACHE_ROOT = "/cache";
|
static const char *CACHE_ROOT = "/cache";
|
||||||
static const char *SDCARD_ROOT = "/sdcard";
|
static const char *SDCARD_ROOT = "/sdcard";
|
||||||
static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
|
static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
|
||||||
|
static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
|
||||||
static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
|
static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
|
||||||
|
|
||||||
extern UIParameters ui_parameters; // from ui.c
|
extern UIParameters ui_parameters; // from ui.c
|
||||||
|
@ -223,15 +225,13 @@ set_sdcard_update_bootloader_message() {
|
||||||
static long tmplog_offset = 0;
|
static long tmplog_offset = 0;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
copy_log_file(const char* destination, int append) {
|
copy_log_file(const char* source, const char* destination, int append) {
|
||||||
FILE *log = fopen_path(destination, append ? "a" : "w");
|
FILE *log = fopen_path(destination, append ? "a" : "w");
|
||||||
if (log == NULL) {
|
if (log == NULL) {
|
||||||
LOGE("Can't open %s\n", destination);
|
LOGE("Can't open %s\n", destination);
|
||||||
} else {
|
} else {
|
||||||
FILE *tmplog = fopen(TEMPORARY_LOG_FILE, "r");
|
FILE *tmplog = fopen(source, "r");
|
||||||
if (tmplog == NULL) {
|
if (tmplog != NULL) {
|
||||||
LOGE("Can't open %s\n", TEMPORARY_LOG_FILE);
|
|
||||||
} else {
|
|
||||||
if (append) {
|
if (append) {
|
||||||
fseek(tmplog, tmplog_offset, SEEK_SET); // Since last write
|
fseek(tmplog, tmplog_offset, SEEK_SET); // Since last write
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ copy_log_file(const char* destination, int append) {
|
||||||
if (append) {
|
if (append) {
|
||||||
tmplog_offset = ftell(tmplog);
|
tmplog_offset = ftell(tmplog);
|
||||||
}
|
}
|
||||||
check_and_fclose(tmplog, TEMPORARY_LOG_FILE);
|
check_and_fclose(tmplog, source);
|
||||||
}
|
}
|
||||||
check_and_fclose(log, destination);
|
check_and_fclose(log, destination);
|
||||||
}
|
}
|
||||||
|
@ -265,9 +265,13 @@ finish_recovery(const char *send_intent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy logs to cache so the system can find out what happened.
|
// Copy logs to cache so the system can find out what happened.
|
||||||
copy_log_file(LOG_FILE, true);
|
copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true);
|
||||||
copy_log_file(LAST_LOG_FILE, false);
|
copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false);
|
||||||
|
copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false);
|
||||||
|
chmod(LOG_FILE, 0600);
|
||||||
|
chown(LOG_FILE, 1000, 1000); // system user
|
||||||
chmod(LAST_LOG_FILE, 0640);
|
chmod(LAST_LOG_FILE, 0640);
|
||||||
|
chmod(LAST_INSTALL_FILE, 0644);
|
||||||
|
|
||||||
// Reset to mormal system boot so recovery won't cycle indefinitely.
|
// Reset to mormal system boot so recovery won't cycle indefinitely.
|
||||||
struct bootloader_message boot;
|
struct bootloader_message boot;
|
||||||
|
@ -280,6 +284,7 @@ finish_recovery(const char *send_intent) {
|
||||||
LOGW("Can't unlink %s\n", COMMAND_FILE);
|
LOGW("Can't unlink %s\n", COMMAND_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensure_path_unmounted(CACHE_ROOT);
|
||||||
sync(); // For good measure.
|
sync(); // For good measure.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +294,8 @@ erase_volume(const char *volume) {
|
||||||
ui_show_indeterminate_progress();
|
ui_show_indeterminate_progress();
|
||||||
ui_print("Formatting %s...\n", volume);
|
ui_print("Formatting %s...\n", volume);
|
||||||
|
|
||||||
|
ensure_path_unmounted(volume);
|
||||||
|
|
||||||
if (strcmp(volume, "/cache") == 0) {
|
if (strcmp(volume, "/cache") == 0) {
|
||||||
// Any part of the log we'd copied to cache is now gone.
|
// Any part of the log we'd copied to cache is now gone.
|
||||||
// Reset the pointer so we copy from the beginning of the temp
|
// Reset the pointer so we copy from the beginning of the temp
|
||||||
|
@ -469,7 +476,8 @@ static int compare_string(const void* a, const void* b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
update_directory(const char* path, const char* unmount_when_done) {
|
update_directory(const char* path, const char* unmount_when_done,
|
||||||
|
int* wipe_cache) {
|
||||||
ensure_path_mounted(path);
|
ensure_path_mounted(path);
|
||||||
|
|
||||||
const char* MENU_HEADERS[] = { "Choose a package to install:",
|
const char* MENU_HEADERS[] = { "Choose a package to install:",
|
||||||
|
@ -558,7 +566,7 @@ update_directory(const char* path, const char* unmount_when_done) {
|
||||||
strlcat(new_path, "/", PATH_MAX);
|
strlcat(new_path, "/", PATH_MAX);
|
||||||
strlcat(new_path, item, PATH_MAX);
|
strlcat(new_path, item, PATH_MAX);
|
||||||
new_path[strlen(new_path)-1] = '\0'; // truncate the trailing '/'
|
new_path[strlen(new_path)-1] = '\0'; // truncate the trailing '/'
|
||||||
result = update_directory(new_path, unmount_when_done);
|
result = update_directory(new_path, unmount_when_done, wipe_cache);
|
||||||
if (result >= 0) break;
|
if (result >= 0) break;
|
||||||
} else {
|
} else {
|
||||||
// selected a zip file: attempt to install it, and return
|
// selected a zip file: attempt to install it, and return
|
||||||
|
@ -575,7 +583,7 @@ update_directory(const char* path, const char* unmount_when_done) {
|
||||||
ensure_path_unmounted(unmount_when_done);
|
ensure_path_unmounted(unmount_when_done);
|
||||||
}
|
}
|
||||||
if (copy) {
|
if (copy) {
|
||||||
result = install_package(copy);
|
result = install_package(copy, wipe_cache, TEMPORARY_INSTALL_FILE);
|
||||||
free(copy);
|
free(copy);
|
||||||
} else {
|
} else {
|
||||||
result = INSTALL_ERROR;
|
result = INSTALL_ERROR;
|
||||||
|
@ -650,6 +658,7 @@ prompt_and_wait() {
|
||||||
chosen_item = device_perform_action(chosen_item);
|
chosen_item = device_perform_action(chosen_item);
|
||||||
|
|
||||||
int status;
|
int status;
|
||||||
|
int wipe_cache;
|
||||||
switch (chosen_item) {
|
switch (chosen_item) {
|
||||||
case ITEM_REBOOT:
|
case ITEM_REBOOT:
|
||||||
return;
|
return;
|
||||||
|
@ -667,7 +676,15 @@ prompt_and_wait() {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ITEM_APPLY_SDCARD:
|
case ITEM_APPLY_SDCARD:
|
||||||
status = update_directory(SDCARD_ROOT, SDCARD_ROOT);
|
status = update_directory(SDCARD_ROOT, SDCARD_ROOT, &wipe_cache);
|
||||||
|
if (status == INSTALL_SUCCESS && wipe_cache) {
|
||||||
|
ui_print("\n-- Wiping cache (at package request)...\n");
|
||||||
|
if (erase_volume("/cache")) {
|
||||||
|
ui_print("Cache wipe failed.\n");
|
||||||
|
} else {
|
||||||
|
ui_print("Cache wipe complete.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (status >= 0) {
|
if (status >= 0) {
|
||||||
if (status != INSTALL_SUCCESS) {
|
if (status != INSTALL_SUCCESS) {
|
||||||
ui_set_background(BACKGROUND_ICON_ERROR);
|
ui_set_background(BACKGROUND_ICON_ERROR);
|
||||||
|
@ -681,7 +698,15 @@ prompt_and_wait() {
|
||||||
break;
|
break;
|
||||||
case ITEM_APPLY_CACHE:
|
case ITEM_APPLY_CACHE:
|
||||||
// Don't unmount cache at the end of this.
|
// Don't unmount cache at the end of this.
|
||||||
status = update_directory(CACHE_ROOT, NULL);
|
status = update_directory(CACHE_ROOT, NULL, &wipe_cache);
|
||||||
|
if (status == INSTALL_SUCCESS && wipe_cache) {
|
||||||
|
ui_print("\n-- Wiping cache (at package request)...\n");
|
||||||
|
if (erase_volume("/cache")) {
|
||||||
|
ui_print("Cache wipe failed.\n");
|
||||||
|
} else {
|
||||||
|
ui_print("Cache wipe complete.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (status >= 0) {
|
if (status >= 0) {
|
||||||
if (status != INSTALL_SUCCESS) {
|
if (status != INSTALL_SUCCESS) {
|
||||||
ui_set_background(BACKGROUND_ICON_ERROR);
|
ui_set_background(BACKGROUND_ICON_ERROR);
|
||||||
|
@ -768,7 +793,12 @@ main(int argc, char **argv) {
|
||||||
int status = INSTALL_SUCCESS;
|
int status = INSTALL_SUCCESS;
|
||||||
|
|
||||||
if (update_package != NULL) {
|
if (update_package != NULL) {
|
||||||
status = install_package(update_package);
|
status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE);
|
||||||
|
if (status == INSTALL_SUCCESS && wipe_cache) {
|
||||||
|
if (erase_volume("/cache")) {
|
||||||
|
LOGE("Cache wipe (requested by package) failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n");
|
if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n");
|
||||||
} else if (wipe_data) {
|
} else if (wipe_data) {
|
||||||
if (device_wipe_data()) status = INSTALL_ERROR;
|
if (device_wipe_data()) status = INSTALL_ERROR;
|
||||||
|
|
|
@ -1024,6 +1024,14 @@ Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
return StringValue(buffer);
|
return StringValue(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
|
if (argc != 0) {
|
||||||
|
return ErrorAbort(state, "%s() expects no args, got %d", name, argc);
|
||||||
|
}
|
||||||
|
fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "wipe_cache\n");
|
||||||
|
return StringValue(strdup("t"));
|
||||||
|
}
|
||||||
|
|
||||||
Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
|
Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
return ErrorAbort(state, "%s() expects at least 1 arg", name);
|
return ErrorAbort(state, "%s() expects at least 1 arg", name);
|
||||||
|
@ -1198,6 +1206,8 @@ void RegisterInstallFunctions() {
|
||||||
RegisterFunction("read_file", ReadFileFn);
|
RegisterFunction("read_file", ReadFileFn);
|
||||||
RegisterFunction("sha1_check", Sha1CheckFn);
|
RegisterFunction("sha1_check", Sha1CheckFn);
|
||||||
|
|
||||||
|
RegisterFunction("wipe_cache", WipeCacheFn);
|
||||||
|
|
||||||
RegisterFunction("ui_print", UIPrintFn);
|
RegisterFunction("ui_print", UIPrintFn);
|
||||||
|
|
||||||
RegisterFunction("run_program", RunProgramFn);
|
RegisterFunction("run_program", RunProgramFn);
|
||||||
|
|
Loading…
Reference in a new issue