summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDoug Zongker <dougz@android.com>2010-01-20 16:34:10 -0800
committerDoug Zongker <dougz@android.com>2010-01-21 12:50:04 -0800
commit687bc12ccfbda26ad134b27d09d1d70a2b8705a6 (patch)
tree83d313c1cb3e9a3a6795faeceb832cfd1f423870
parent883b4c8be5f50cde679cdfa589d7ade83c0253b7 (diff)
downloadbootable_recovery-687bc12ccfbda26ad134b27d09d1d70a2b8705a6.zip
bootable_recovery-687bc12ccfbda26ad134b27d09d1d70a2b8705a6.tar.gz
bootable_recovery-687bc12ccfbda26ad134b27d09d1d70a2b8705a6.tar.bz2
save the recovery log from before HTC firmware updates
When doing a firmware (radio or hboot) update on HTC devices, save the recovery log in block 1 of the cache partition, before the firmware image and the UI bitmaps. When we boot back into recovery after the firmware update to reformat the cache partition, copy that log out of cache before reformatting it and dump it into the current invocation's log. The practical upshot of all this is that we can see the log output from radio and hboot updates. Change-Id: Ie0e89566754c88f4bed6a90d8a0aa04047b01a27
-rw-r--r--bootloader.c101
-rw-r--r--bootloader.h9
-rw-r--r--firmware.c6
-rw-r--r--firmware.h3
-rw-r--r--recovery.c4
5 files changed, 117 insertions, 6 deletions
diff --git a/bootloader.c b/bootloader.c
index bc79bee..61b24e9 100644
--- a/bootloader.c
+++ b/bootloader.c
@@ -155,10 +155,14 @@ struct update_header {
unsigned fail_bitmap_length;
};
+#define LOG_MAGIC "LOGmagic"
+#define LOG_MAGIC_SIZE 8
+
int write_update_for_bootloader(
const char *update, int update_length,
int bitmap_width, int bitmap_height, int bitmap_bpp,
- const char *busy_bitmap, const char *fail_bitmap) {
+ const char *busy_bitmap, const char *fail_bitmap,
+ const char *log_filename) {
if (ensure_root_path_unmounted(CACHE_NAME)) {
LOGE("Can't unmount %s\n", CACHE_NAME);
return -1;
@@ -198,6 +202,21 @@ int write_update_for_bootloader(
header.version = UPDATE_VERSION;
header.size = header_size;
+ if (log_filename != NULL) {
+ // Write 1 byte into the following block, then fill to the end
+ // in order to reserve that block. We'll use the block to
+ // send a copy of the log through to the next invocation of
+ // recovery. We write the log as late as possible in order to
+ // capture any messages emitted by this function.
+ mtd_erase_blocks(write, 0);
+ if (mtd_write_data(write, (char*) &header, 1) != 1) {
+ LOGE("Can't write log block to %s\n(%s)\n",
+ CACHE_NAME, strerror(errno));
+ mtd_write_close(write);
+ return -1;
+ }
+ }
+
off_t image_start_pos = mtd_erase_blocks(write, 0);
header.image_length = update_length;
if ((int) header.image_offset == -1 ||
@@ -256,6 +275,37 @@ int write_update_for_bootloader(
return -1;
}
+ if (log_filename != NULL) {
+ size_t erase_size;
+ if (mtd_partition_info(part, NULL, &erase_size, NULL) != 0) {
+ LOGE("Error reading block size\n(%s)\n", strerror(errno));
+ mtd_write_close(write);
+ return -1;
+ }
+ mtd_erase_blocks(write, 0);
+
+ if (erase_size > 0) {
+ char* log = malloc(erase_size);
+ FILE* f = fopen(log_filename, "rb");
+ // The fseek() may fail if it tries to go before the
+ // beginning of the log, but that's okay because we want
+ // to be positioned at the start anyway.
+ fseek(f, -(erase_size-sizeof(size_t)-LOG_MAGIC_SIZE), SEEK_END);
+ memcpy(log, LOG_MAGIC, LOG_MAGIC_SIZE);
+ size_t read = fread(log+sizeof(size_t)+LOG_MAGIC_SIZE,
+ 1, erase_size-sizeof(size_t)-LOG_MAGIC_SIZE, f);
+ LOGI("read %d bytes from log\n", (int)read);
+ *(size_t *)(log + LOG_MAGIC_SIZE) = read;
+ fclose(f);
+ if (mtd_write_data(write, log, erase_size) != erase_size) {
+ LOGE("failed to store log in cache partition\n(%s)\n",
+ strerror(errno));
+ mtd_write_close(write);
+ }
+ free(log);
+ }
+ }
+
if (mtd_erase_blocks(write, 0) != image_start_pos) {
LOGE("Misalignment rewriting %s\n(%s)\n", CACHE_NAME, strerror(errno));
mtd_write_close(write);
@@ -269,3 +319,52 @@ int write_update_for_bootloader(
return 0;
}
+
+void recover_firmware_update_log() {
+ printf("recovering log from before firmware update\n");
+
+ const MtdPartition *part = get_root_mtd_partition(CACHE_NAME);
+ if (part == NULL) {
+ LOGE("Can't find %s\n", CACHE_NAME);
+ return;
+ }
+
+ MtdReadContext* read = mtd_read_partition(part);
+
+ size_t erase_size;
+ if (mtd_partition_info(part, NULL, &erase_size, NULL) != 0) {
+ LOGE("Error reading block size\n(%s)\n", strerror(errno));
+ mtd_read_close(read);
+ return;
+ }
+
+ char* buffer = malloc(erase_size);
+ if (mtd_read_data(read, buffer, erase_size) != erase_size) {
+ LOGE("Error reading header block\n(%s)\n", strerror(errno));
+ mtd_read_close(read);
+ free(buffer);
+ return;
+ }
+ if (mtd_read_data(read, buffer, erase_size) != erase_size) {
+ LOGE("Error reading log block\n(%s)\n", strerror(errno));
+ mtd_read_close(read);
+ free(buffer);
+ return;
+ }
+ mtd_read_close(read);
+
+ if (memcmp(buffer, LOG_MAGIC, LOG_MAGIC_SIZE) != 0) {
+ LOGE("No log from before firmware install\n");
+ free(buffer);
+ return;
+ }
+
+ size_t log_size = *(size_t *)(buffer + LOG_MAGIC_SIZE);
+ LOGI("header has %d bytes of log\n", (int)log_size);
+
+ printf("\n###\n### START RECOVERED LOG\n###\n\n");
+ fwrite(buffer + sizeof(size_t) + LOG_MAGIC_SIZE, 1, log_size, stdout);
+ printf("\n\n###\n### END RECOVERED LOG\n###\n\n");
+
+ free(buffer);
+}
diff --git a/bootloader.h b/bootloader.h
index 3d4302f..fec6409 100644
--- a/bootloader.h
+++ b/bootloader.h
@@ -54,6 +54,13 @@ int set_bootloader_message(const struct bootloader_message *in);
int write_update_for_bootloader(
const char *update, int update_len,
int bitmap_width, int bitmap_height, int bitmap_bpp,
- const char *busy_bitmap, const char *error_bitmap);
+ const char *busy_bitmap, const char *error_bitmap,
+ const char *log_filename);
+
+/* Look for a log stored in the cache partition in the block after the
+ * firmware update header. If we can read such a log, copy it to
+ * stdout (ie, the current log).
+ */
+void recover_firmware_update_log();
#endif
diff --git a/firmware.c b/firmware.c
index e2e4fe6..6739c1e 100644
--- a/firmware.c
+++ b/firmware.c
@@ -76,7 +76,8 @@ int firmware_update_pending() {
* It is recovery's responsibility to clean up the mess afterwards.
*/
-int maybe_install_firmware_update(const char *send_intent) {
+int maybe_install_firmware_update(const char *send_intent,
+ const char *log_filename) {
if (update_data == NULL || update_length == 0) return 0;
/* We destroy the cache partition to pass the update image to the
@@ -104,7 +105,7 @@ int maybe_install_firmware_update(const char *send_intent) {
ui_print("Writing %s image...\n", update_type);
if (write_update_for_bootloader(
update_data, update_length,
- width, height, bpp, busy_image, fail_image)) {
+ width, height, bpp, busy_image, fail_image, log_filename)) {
LOGE("Can't write %s image\n(%s)\n", update_type, strerror(errno));
format_root_device("CACHE:"); // Attempt to clean cache up, at least.
return -1;
@@ -118,6 +119,7 @@ int maybe_install_firmware_update(const char *send_intent) {
* wipe the cache and reboot into the system.)
*/
snprintf(boot.command, sizeof(boot.command), "update-%s", update_type);
+ strlcat(boot.recovery, "--recover_log\n", sizeof(boot.recovery));
if (set_bootloader_message(&boot)) {
format_root_device("CACHE:");
return -1;
diff --git a/firmware.h b/firmware.h
index aeb8f97..04507bb 100644
--- a/firmware.h
+++ b/firmware.h
@@ -30,6 +30,7 @@ int firmware_update_pending();
* Returns 0 if no radio image was defined, nonzero on error,
* doesn't return at all on success...
*/
-int maybe_install_firmware_update(const char *send_intent);
+int maybe_install_firmware_update(const char *send_intent,
+ const char *log_filename);
#endif
diff --git a/recovery.c b/recovery.c
index 58c84ef..1a88560 100644
--- a/recovery.c
+++ b/recovery.c
@@ -46,6 +46,7 @@ static const struct option OPTIONS[] = {
{ "wipe_cache", no_argument, NULL, 'c' },
// TODO{oam}: implement improved command line passing key, egnot to review.
{ "set_encrypted_filesystem", required_argument, NULL, 'e' },
+ { "recover_log", no_argument, NULL, 'g' },
{ NULL, 0, NULL, 0 },
};
@@ -491,6 +492,7 @@ main(int argc, char **argv) {
case 'w': wipe_data = wipe_cache = 1; break;
case 'c': wipe_cache = 1; break;
case 'e': efs_mode = optarg; toggle_efs = 1; break;
+ case 'g': recover_firmware_update_log(); break;
case '?':
LOGE("Invalid command argument\n");
continue;
@@ -562,7 +564,7 @@ main(int argc, char **argv) {
if (status != INSTALL_SUCCESS || ui_text_visible()) prompt_and_wait();
// If there is a radio image pending, reboot now to install it.
- maybe_install_firmware_update(send_intent);
+ maybe_install_firmware_update(send_intent, TEMPORARY_LOG_FILE);
// Otherwise, get ready to boot the main system...
finish_recovery(send_intent);