From d0181b8fcdac761afec252151a8bfda116916e96 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Wed, 19 Oct 2011 10:51:12 -0700 Subject: [PATCH] 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 --- install.c | 23 ++++++++++--------- install.h | 6 ++++- recovery.c | 58 +++++++++++++++++++++++++++++++++++------------ updater/install.c | 10 ++++++++ 4 files changed, 71 insertions(+), 26 deletions(-) diff --git a/install.c b/install.c index 707cda43..9d7595e1 100644 --- a/install.c +++ b/install.c @@ -36,11 +36,9 @@ #define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary" #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. 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 = mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME); if (binary_entry == NULL) { @@ -54,7 +52,7 @@ try_update_binary(const char *path, ZipArchive *zip) { if (fd < 0) { mzCloseZipArchive(zip); LOGE("Can't make %s\n", binary); - return 1; + return INSTALL_ERROR; } bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd); close(fd); @@ -62,7 +60,7 @@ try_update_binary(const char *path, ZipArchive *zip) { if (!ok) { LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME); - return 1; + return INSTALL_ERROR; } int pipefd[2]; @@ -119,6 +117,8 @@ try_update_binary(const char *path, ZipArchive *zip) { } close(pipefd[1]); + *wipe_cache = 0; + char buffer[1024]; FILE* from_child = fdopen(pipefd[0], "r"); while (fgets(buffer, sizeof(buffer), from_child) != NULL) { @@ -145,6 +145,8 @@ try_update_binary(const char *path, ZipArchive *zip) { } else { ui_print("\n"); } + } else if (strcmp(command, "wipe_cache") == 0) { + *wipe_cache = 1; } else { LOGE("unknown command [%s]\n", command); } @@ -236,7 +238,7 @@ exit: } static int -really_install_package(const char *path) +really_install_package(const char *path, int* wipe_cache) { ui_set_background(BACKGROUND_ICON_INSTALLING); ui_print("Finding update package...\n"); @@ -285,25 +287,24 @@ really_install_package(const char *path) /* Verify and install the contents of the package. */ ui_print("Installing update...\n"); - return try_update_binary(path, &zip); + return try_update_binary(path, &zip, wipe_cache); } 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) { fputs(path, install_log); fputc('\n', install_log); } else { 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) { fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log); fputc('\n', install_log); fclose(install_log); - chmod(LAST_INSTALL_FILE, 0644); } return result; } diff --git a/install.h b/install.h index a7ebc090..5ebe1604 100644 --- a/install.h +++ b/install.h @@ -20,6 +20,10 @@ #include "common.h" 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_ diff --git a/recovery.c b/recovery.c index 1e3eb5af..06d64980 100644 --- a/recovery.c +++ b/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 *LOG_FILE = "/cache/recovery/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 *SDCARD_ROOT = "/sdcard"; 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"; extern UIParameters ui_parameters; // from ui.c @@ -223,15 +225,13 @@ set_sdcard_update_bootloader_message() { static long tmplog_offset = 0; 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"); if (log == NULL) { LOGE("Can't open %s\n", destination); } else { - FILE *tmplog = fopen(TEMPORARY_LOG_FILE, "r"); - if (tmplog == NULL) { - LOGE("Can't open %s\n", TEMPORARY_LOG_FILE); - } else { + FILE *tmplog = fopen(source, "r"); + if (tmplog != NULL) { if (append) { fseek(tmplog, tmplog_offset, SEEK_SET); // Since last write } @@ -240,7 +240,7 @@ copy_log_file(const char* destination, int append) { if (append) { tmplog_offset = ftell(tmplog); } - check_and_fclose(tmplog, TEMPORARY_LOG_FILE); + check_and_fclose(tmplog, source); } 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_log_file(LOG_FILE, true); - copy_log_file(LAST_LOG_FILE, false); + copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true); + 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_INSTALL_FILE, 0644); // Reset to mormal system boot so recovery won't cycle indefinitely. struct bootloader_message boot; @@ -280,6 +284,7 @@ finish_recovery(const char *send_intent) { LOGW("Can't unlink %s\n", COMMAND_FILE); } + ensure_path_unmounted(CACHE_ROOT); sync(); // For good measure. } @@ -289,6 +294,8 @@ erase_volume(const char *volume) { ui_show_indeterminate_progress(); ui_print("Formatting %s...\n", volume); + ensure_path_unmounted(volume); + if (strcmp(volume, "/cache") == 0) { // 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 @@ -469,7 +476,8 @@ static int compare_string(const void* a, const void* b) { } 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); 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, item, PATH_MAX); 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; } else { // 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); } if (copy) { - result = install_package(copy); + result = install_package(copy, wipe_cache, TEMPORARY_INSTALL_FILE); free(copy); } else { result = INSTALL_ERROR; @@ -650,6 +658,7 @@ prompt_and_wait() { chosen_item = device_perform_action(chosen_item); int status; + int wipe_cache; switch (chosen_item) { case ITEM_REBOOT: return; @@ -667,7 +676,15 @@ prompt_and_wait() { break; 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 != INSTALL_SUCCESS) { ui_set_background(BACKGROUND_ICON_ERROR); @@ -681,7 +698,15 @@ prompt_and_wait() { break; case ITEM_APPLY_CACHE: // 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 != INSTALL_SUCCESS) { ui_set_background(BACKGROUND_ICON_ERROR); @@ -768,7 +793,12 @@ main(int argc, char **argv) { int status = INSTALL_SUCCESS; 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"); } else if (wipe_data) { if (device_wipe_data()) status = INSTALL_ERROR; diff --git a/updater/install.c b/updater/install.c index 0396bae6..7b4b99b0 100644 --- a/updater/install.c +++ b/updater/install.c @@ -1024,6 +1024,14 @@ Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) { 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[]) { if (argc < 1) { return ErrorAbort(state, "%s() expects at least 1 arg", name); @@ -1198,6 +1206,8 @@ void RegisterInstallFunctions() { RegisterFunction("read_file", ReadFileFn); RegisterFunction("sha1_check", Sha1CheckFn); + RegisterFunction("wipe_cache", WipeCacheFn); + RegisterFunction("ui_print", UIPrintFn); RegisterFunction("run_program", RunProgramFn);