summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk34
-rw-r--r--bootloader.c150
-rw-r--r--bootloader.h9
-rw-r--r--common.h7
-rw-r--r--default_recovery_ui.c4
-rw-r--r--efs_migration.c183
-rw-r--r--efs_migration.h40
-rw-r--r--firmware.c131
-rw-r--r--firmware.h35
-rw-r--r--install.c99
-rw-r--r--minui/resources.c11
-rw-r--r--minzip/Zip.c37
-rw-r--r--minzip/Zip.h7
-rw-r--r--recovery.c98
-rw-r--r--recovery_ui.h3
-rw-r--r--res/images/icon_firmware_error.pngbin8088 -> 0 bytes
-rwxr-xr-xres/images/icon_firmware_install.pngbin12717 -> 0 bytes
-rw-r--r--res/images/indeterminate1.pngbin2249 -> 1919 bytes
-rw-r--r--res/images/indeterminate2.pngbin2251 -> 1912 bytes
-rw-r--r--res/images/indeterminate3.pngbin2254 -> 1917 bytes
-rw-r--r--res/images/indeterminate4.pngbin2249 -> 1912 bytes
-rw-r--r--res/images/indeterminate5.pngbin2246 -> 1902 bytes
-rw-r--r--res/images/indeterminate6.pngbin2262 -> 1914 bytes
-rw-r--r--res/images/progress_bar_empty.pngbin148 -> 0 bytes
-rw-r--r--res/images/progress_bar_empty_left_round.pngbin220 -> 0 bytes
-rw-r--r--res/images/progress_bar_empty_right_round.pngbin211 -> 0 bytes
-rw-r--r--res/images/progress_bar_fill.pngbin117 -> 0 bytes
-rw-r--r--res/images/progress_bar_left_round.pngbin195 -> 0 bytes
-rw-r--r--res/images/progress_bar_right_round.pngbin192 -> 0 bytes
-rw-r--r--res/images/progress_empty.pngbin0 -> 361 bytes
-rw-r--r--res/images/progress_fill.pngbin0 -> 286 bytes
-rw-r--r--testdata/alter-footer.zipbin0 -> 4009 bytes
-rw-r--r--testdata/alter-metadata.zipbin0 -> 4009 bytes
-rw-r--r--testdata/fake-eocd.zipbin0 -> 4313 bytes
-rw-r--r--testdata/jarsigned.zipbin0 -> 2271 bytes
-rw-r--r--testdata/otasigned.zipbin0 -> 4009 bytes
-rw-r--r--testdata/random.zipbin0 -> 1024 bytes
-rw-r--r--testdata/unsigned.zipbin0 -> 376 bytes
-rw-r--r--ui.c55
-rw-r--r--updater/install.c132
-rw-r--r--updater/updater.c9
-rw-r--r--updater/updater.h1
-rw-r--r--verifier.c4
-rw-r--r--verifier_test.c91
-rwxr-xr-xverifier_test.sh94
45 files changed, 666 insertions, 568 deletions
diff --git a/Android.mk b/Android.mk
index deec80ae4..5f7406466 100644
--- a/Android.mk
+++ b/Android.mk
@@ -7,13 +7,13 @@ include $(CLEAR_VARS)
commands_recovery_local_path := $(LOCAL_PATH)
LOCAL_SRC_FILES := \
- recovery.c \
- bootloader.c \
- firmware.c \
- install.c \
- roots.c \
- ui.c \
- verifier.c
+ recovery.c \
+ bootloader.c \
+ install.c \
+ roots.c \
+ ui.c \
+ verifier.c \
+ efs_migration.c
LOCAL_SRC_FILES += test_roots.c
@@ -21,7 +21,7 @@ LOCAL_MODULE := recovery
LOCAL_FORCE_STATIC_EXECUTABLE := true
-RECOVERY_API_VERSION := 2
+RECOVERY_API_VERSION := 3
LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
# This binary is in the recovery ramdisk, which is otherwise a copy of root.
@@ -43,6 +43,22 @@ LOCAL_STATIC_LIBRARIES += libstdc++ libc
include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := verifier_test.c verifier.c
+
+LOCAL_MODULE := verifier_test
+
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_STATIC_LIBRARIES := libmincrypt libcutils libstdc++ libc
+
+include $(BUILD_EXECUTABLE)
+
+
include $(commands_recovery_local_path)/minui/Android.mk
include $(commands_recovery_local_path)/minzip/Android.mk
include $(commands_recovery_local_path)/mtdutils/Android.mk
@@ -52,5 +68,5 @@ include $(commands_recovery_local_path)/updater/Android.mk
commands_recovery_local_path :=
endif # TARGET_ARCH == arm
-endif # !TARGET_SIMULATOR
+endif # !TARGET_SIMULATOR
diff --git a/bootloader.c b/bootloader.c
index bc79bee76..38b5651bf 100644
--- a/bootloader.c
+++ b/bootloader.c
@@ -119,153 +119,3 @@ int set_bootloader_message(const struct bootloader_message *in) {
LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
return 0;
}
-
-/* Update Image
- *
- * - will be stored in the "cache" partition
- * - bad blocks will be ignored, like boot.img and recovery.img
- * - the first block will be the image header (described below)
- * - the size is in BYTES, inclusive of the header
- * - offsets are in BYTES from the start of the update header
- * - two raw bitmaps will be included, the "busy" and "fail" bitmaps
- * - for dream, the bitmaps will be 320x480x16bpp RGB565
- */
-
-#define UPDATE_MAGIC "MSM-RADIO-UPDATE"
-#define UPDATE_MAGIC_SIZE 16
-#define UPDATE_VERSION 0x00010000
-
-struct update_header {
- unsigned char MAGIC[UPDATE_MAGIC_SIZE];
-
- unsigned version;
- unsigned size;
-
- unsigned image_offset;
- unsigned image_length;
-
- unsigned bitmap_width;
- unsigned bitmap_height;
- unsigned bitmap_bpp;
-
- unsigned busy_bitmap_offset;
- unsigned busy_bitmap_length;
-
- unsigned fail_bitmap_offset;
- unsigned fail_bitmap_length;
-};
-
-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) {
- if (ensure_root_path_unmounted(CACHE_NAME)) {
- LOGE("Can't unmount %s\n", CACHE_NAME);
- return -1;
- }
-
- const MtdPartition *part = get_root_mtd_partition(CACHE_NAME);
- if (part == NULL) {
- LOGE("Can't find %s\n", CACHE_NAME);
- return -1;
- }
-
- MtdWriteContext *write = mtd_write_partition(part);
- if (write == NULL) {
- LOGE("Can't open %s\n(%s)\n", CACHE_NAME, strerror(errno));
- return -1;
- }
-
- /* Write an invalid (zero) header first, to disable any previous
- * update and any other structured contents (like a filesystem),
- * and as a placeholder for the amount of space required.
- */
-
- struct update_header header;
- memset(&header, 0, sizeof(header));
- const ssize_t header_size = sizeof(header);
- if (mtd_write_data(write, (char*) &header, header_size) != header_size) {
- LOGE("Can't write header to %s\n(%s)\n", CACHE_NAME, strerror(errno));
- mtd_write_close(write);
- return -1;
- }
-
- /* Write each section individually block-aligned, so we can write
- * each block independently without complicated buffering.
- */
-
- memcpy(&header.MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE);
- header.version = UPDATE_VERSION;
- header.size = header_size;
-
- off_t image_start_pos = mtd_erase_blocks(write, 0);
- header.image_length = update_length;
- if ((int) header.image_offset == -1 ||
- mtd_write_data(write, update, update_length) != update_length) {
- LOGE("Can't write update to %s\n(%s)\n", CACHE_NAME, strerror(errno));
- mtd_write_close(write);
- return -1;
- }
- off_t busy_start_pos = mtd_erase_blocks(write, 0);
- header.image_offset = mtd_find_write_start(write, image_start_pos);
-
- header.bitmap_width = bitmap_width;
- header.bitmap_height = bitmap_height;
- header.bitmap_bpp = bitmap_bpp;
-
- int bitmap_length = (bitmap_bpp + 7) / 8 * bitmap_width * bitmap_height;
-
- header.busy_bitmap_length = busy_bitmap != NULL ? bitmap_length : 0;
- if ((int) header.busy_bitmap_offset == -1 ||
- mtd_write_data(write, busy_bitmap, bitmap_length) != bitmap_length) {
- LOGE("Can't write bitmap to %s\n(%s)\n", CACHE_NAME, strerror(errno));
- mtd_write_close(write);
- return -1;
- }
- off_t fail_start_pos = mtd_erase_blocks(write, 0);
- header.busy_bitmap_offset = mtd_find_write_start(write, busy_start_pos);
-
- header.fail_bitmap_length = fail_bitmap != NULL ? bitmap_length : 0;
- if ((int) header.fail_bitmap_offset == -1 ||
- mtd_write_data(write, fail_bitmap, bitmap_length) != bitmap_length) {
- LOGE("Can't write bitmap to %s\n(%s)\n", CACHE_NAME, strerror(errno));
- mtd_write_close(write);
- return -1;
- }
- mtd_erase_blocks(write, 0);
- header.fail_bitmap_offset = mtd_find_write_start(write, fail_start_pos);
-
- /* Write the header last, after all the blocks it refers to, so that
- * when the magic number is installed everything is valid.
- */
-
- if (mtd_write_close(write)) {
- LOGE("Can't finish writing %s\n(%s)\n", CACHE_NAME, strerror(errno));
- return -1;
- }
-
- write = mtd_write_partition(part);
- if (write == NULL) {
- LOGE("Can't reopen %s\n(%s)\n", CACHE_NAME, strerror(errno));
- return -1;
- }
-
- if (mtd_write_data(write, (char*) &header, header_size) != header_size) {
- LOGE("Can't rewrite header to %s\n(%s)\n", CACHE_NAME, strerror(errno));
- mtd_write_close(write);
- return -1;
- }
-
- if (mtd_erase_blocks(write, 0) != image_start_pos) {
- LOGE("Misalignment rewriting %s\n(%s)\n", CACHE_NAME, strerror(errno));
- mtd_write_close(write);
- return -1;
- }
-
- if (mtd_write_close(write)) {
- LOGE("Can't finish header of %s\n(%s)\n", CACHE_NAME, strerror(errno));
- return -1;
- }
-
- return 0;
-}
diff --git a/bootloader.h b/bootloader.h
index 3d4302f1e..2e749aa12 100644
--- a/bootloader.h
+++ b/bootloader.h
@@ -47,13 +47,4 @@ struct bootloader_message {
int get_bootloader_message(struct bootloader_message *out);
int set_bootloader_message(const struct bootloader_message *in);
-/* Write an update to the cache partition for update-radio or update-hboot.
- * Note, this destroys any filesystem on the cache partition!
- * The expected bitmap format is 240x320, 16bpp (2Bpp), RGB 5:6:5.
- */
-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);
-
#endif
diff --git a/common.h b/common.h
index d962a0a3f..ff577c259 100644
--- a/common.h
+++ b/common.h
@@ -49,17 +49,10 @@ enum {
BACKGROUND_ICON_NONE,
BACKGROUND_ICON_INSTALLING,
BACKGROUND_ICON_ERROR,
- BACKGROUND_ICON_FIRMWARE_INSTALLING,
- BACKGROUND_ICON_FIRMWARE_ERROR,
NUM_BACKGROUND_ICONS
};
void ui_set_background(int icon);
-// Get a malloc'd copy of the screen image showing (only) the specified icon.
-// Also returns the width, height, and bits per pixel of the returned image.
-// TODO: Use some sort of "struct Bitmap" here instead of all these variables?
-char *ui_copy_image(int icon, int *width, int *height, int *bpp);
-
// Show a progress bar and define the scope of the next operation:
// portion - fraction of the progress bar the next operation will use
// seconds - expected time interval (progress bar moves at this minimum rate)
diff --git a/default_recovery_ui.c b/default_recovery_ui.c
index d4e620403..409d67934 100644
--- a/default_recovery_ui.c
+++ b/default_recovery_ui.c
@@ -29,6 +29,10 @@ char* MENU_ITEMS[] = { "reboot system now",
"wipe cache partition",
NULL };
+int device_recovery_start() {
+ return 0;
+}
+
int device_toggle_display(volatile char* key_pressed, int key_code) {
return key_code == KEY_HOME;
}
diff --git a/efs_migration.c b/efs_migration.c
new file mode 100644
index 000000000..aeadd1865
--- /dev/null
+++ b/efs_migration.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "efs_migration.h"
+#include "cutils/misc.h"
+#include "cutils/properties.h"
+#include "common.h"
+#include "mtdutils/mtdutils.h"
+#include "mtdutils/mounts.h"
+#include "roots.h"
+
+const char* efs_enabled_property = "persist.security.efs.enabled";
+const char* efs_transition_property = "persist.security.efs.trans";
+const char* efs_property_dir = "/data/property/";
+
+void get_property_file_name(char *buffer, const char *property_name) {
+ sprintf(buffer, "%s%s", efs_property_dir, property_name);
+}
+
+int get_text_file_contents(char *buffer, int buf_size, char *file_name) {
+ FILE *in_file;
+ char *read_data;
+
+ in_file = fopen(file_name, "r");
+ if (in_file == NULL) {
+ LOGE("Encrypted FS: error accessing properties.");
+ return EFS_ERROR;
+ }
+
+ read_data = fgets(buffer, buf_size, in_file);
+ if (read_data == NULL) {
+ // Error or unexpected data
+ fclose(in_file);
+ LOGE("Encrypted FS: error accessing properties.");
+ return EFS_ERROR;
+ }
+
+ fclose(in_file);
+ return EFS_OK;
+}
+
+int set_text_file_contents(char *buffer, char *file_name) {
+ FILE *out_file;
+ int result;
+
+ out_file = fopen(file_name, "w");
+ if (out_file == NULL) {
+ LOGE("Encrypted FS: error setting up properties.");
+ return EFS_ERROR;
+ }
+
+ result = fputs(buffer, out_file);
+ if (result != 0) {
+ // Error or unexpected data
+ fclose(out_file);
+ LOGE("Encrypted FS: error setting up properties.");
+ return EFS_ERROR;
+ }
+
+ fflush(out_file);
+ fclose(out_file);
+ return EFS_OK;
+}
+
+
+int read_efs_boolean_property(const char *prop_name, int *value) {
+ char prop_file_name[PROPERTY_KEY_MAX + 32];
+ char prop_value[PROPERTY_VALUE_MAX];
+ int result;
+
+ get_property_file_name(prop_file_name, prop_name);
+ result = get_text_file_contents(prop_value, PROPERTY_VALUE_MAX, prop_file_name);
+
+ if (result < 0) {
+ return result;
+ }
+
+ if (strncmp(prop_value, "1", 1) == 0) {
+ *value = 1;
+ } else if (strncmp(prop_value, "0", 1) == 0) {
+ *value = 0;
+ } else {
+ LOGE("Encrypted FS: error accessing properties.");
+ return EFS_ERROR;
+ }
+
+ return EFS_OK;
+}
+
+int write_efs_boolean_property(const char *prop_name, int value) {
+ char prop_file_name[PROPERTY_KEY_MAX + 32];
+ char prop_value[PROPERTY_VALUE_MAX];
+ int result;
+
+ get_property_file_name(prop_file_name, prop_name);
+
+ // Create the directory if needed
+ mkdir(efs_property_dir, 0755);
+ if (value == 1) {
+ result = set_text_file_contents("1", prop_file_name);
+ } else if (value == 0) {
+ result = set_text_file_contents("0", prop_file_name);
+ } else {
+ return EFS_ERROR;
+ }
+ if (result < 0) {
+ return result;
+ }
+
+ return EFS_OK;
+}
+
+int read_encrypted_fs_info(encrypted_fs_info *efs_data) {
+ int result;
+ int value;
+ result = ensure_root_path_mounted("DATA:");
+ if (result != 0) {
+ LOGE("Encrypted FS: error mounting userdata partition.");
+ return EFS_ERROR;
+ }
+
+ // STOPSHIP: Read the EFS key from a file (TBD later)
+ // Future code goes here...
+
+ result = ensure_root_path_unmounted("DATA:");
+ if (result != 0) {
+ LOGE("Encrypted FS: error unmounting data partition.");
+ return EFS_ERROR;
+ }
+
+ return EFS_OK;
+}
+
+int restore_encrypted_fs_info(encrypted_fs_info *efs_data) {
+ int result;
+ result = ensure_root_path_mounted("DATA:");
+ if (result != 0) {
+ LOGE("Encrypted FS: error mounting userdata partition.");
+ return EFS_ERROR;
+ }
+
+ // Set the EFS properties to their respective values
+ result = write_efs_boolean_property(efs_enabled_property, efs_data->encrypted_fs_mode);
+ if (result != 0) {
+ return result;
+ }
+
+ // Signal "transition" of Encrypted File System settings
+ result = write_efs_boolean_property(efs_transition_property, 1);
+ if (result != 0) {
+ return result;
+ }
+
+ result = ensure_root_path_unmounted("DATA:");
+ if (result != 0) {
+ LOGE("Encrypted FS: error unmounting data partition.");
+ return EFS_ERROR;
+ }
+
+ return EFS_OK;
+}
+
diff --git a/efs_migration.h b/efs_migration.h
new file mode 100644
index 000000000..7857f94fe
--- /dev/null
+++ b/efs_migration.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#ifndef __EFS_MIGRATION_H__
+#define __EFS_MIGRATION_H__
+
+#define MODE_ENCRYPTEDFS_DISABLED 0
+#define MODE_ENCRYPTEDFS_ENABLED 1
+
+#define EFS_OK 0
+#define EFS_ERROR (-1)
+
+struct encrypted_fs_info {
+ int encrypted_fs_mode;
+ char *encrypted_fs_key;
+};
+
+typedef struct encrypted_fs_info encrypted_fs_info;
+
+int read_encrypted_fs_info(encrypted_fs_info *efs_data);
+
+int restore_encrypted_fs_info(encrypted_fs_info *efs_data);
+
+#endif /* __EFS_MIGRATION_H__ */
+
diff --git a/firmware.c b/firmware.c
deleted file mode 100644
index e2e4fe630..000000000
--- a/firmware.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "bootloader.h"
-#include "common.h"
-#include "firmware.h"
-#include "roots.h"
-
-#include <errno.h>
-#include <string.h>
-#include <sys/reboot.h>
-
-static const char *update_type = NULL;
-static const char *update_data = NULL;
-static int update_length = 0;
-
-int remember_firmware_update(const char *type, const char *data, int length) {
- if (update_type != NULL || update_data != NULL) {
- LOGE("Multiple firmware images\n");
- return -1;
- }
-
- update_type = type;
- update_data = data;
- update_length = length;
- return 0;
-}
-
-// Return true if there is a firmware update pending.
-int firmware_update_pending() {
- return update_data != NULL && update_length > 0;
-}
-
-/* Bootloader / Recovery Flow
- *
- * On every boot, the bootloader will read the bootloader_message
- * from flash and check the command field. The bootloader should
- * deal with the command field not having a 0 terminator correctly
- * (so as to not crash if the block is invalid or corrupt).
- *
- * The bootloader will have to publish the partition that contains
- * the bootloader_message to the linux kernel so it can update it.
- *
- * if command == "boot-recovery" -> boot recovery.img
- * else if command == "update-radio" -> update radio image (below)
- * else if command == "update-hboot" -> update hboot image (below)
- * else -> boot boot.img (normal boot)
- *
- * Radio/Hboot Update Flow
- * 1. the bootloader will attempt to load and validate the header
- * 2. if the header is invalid, status="invalid-update", goto #8
- * 3. display the busy image on-screen
- * 4. if the update image is invalid, status="invalid-radio-image", goto #8
- * 5. attempt to update the firmware (depending on the command)
- * 6. if successful, status="okay", goto #8
- * 7. if failed, and the old image can still boot, status="failed-update"
- * 8. write the bootloader_message, leaving the recovery field
- * unchanged, updating status, and setting command to
- * "boot-recovery"
- * 9. reboot
- *
- * The bootloader will not modify or erase the cache partition.
- * It is recovery's responsibility to clean up the mess afterwards.
- */
-
-int maybe_install_firmware_update(const char *send_intent) {
- if (update_data == NULL || update_length == 0) return 0;
-
- /* We destroy the cache partition to pass the update image to the
- * bootloader, so all we can really do afterwards is wipe cache and reboot.
- * Set up this instruction now, in case we're interrupted while writing.
- */
-
- struct bootloader_message boot;
- memset(&boot, 0, sizeof(boot));
- strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
- strlcpy(boot.recovery, "recovery\n--wipe_cache\n", sizeof(boot.command));
- if (send_intent != NULL) {
- strlcat(boot.recovery, "--send_intent=", sizeof(boot.recovery));
- strlcat(boot.recovery, send_intent, sizeof(boot.recovery));
- strlcat(boot.recovery, "\n", sizeof(boot.recovery));
- }
- if (set_bootloader_message(&boot)) return -1;
-
- int width = 0, height = 0, bpp = 0;
- char *busy_image = ui_copy_image(
- BACKGROUND_ICON_FIRMWARE_INSTALLING, &width, &height, &bpp);
- char *fail_image = ui_copy_image(
- BACKGROUND_ICON_FIRMWARE_ERROR, &width, &height, &bpp);
-
- ui_print("Writing %s image...\n", update_type);
- if (write_update_for_bootloader(
- update_data, update_length,
- width, height, bpp, busy_image, fail_image)) {
- 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;
- }
-
- free(busy_image);
- free(fail_image);
-
- /* The update image is fully written, so now we can instruct the bootloader
- * to install it. (After doing so, it will come back here, and we will
- * wipe the cache and reboot into the system.)
- */
- snprintf(boot.command, sizeof(boot.command), "update-%s", update_type);
- if (set_bootloader_message(&boot)) {
- format_root_device("CACHE:");
- return -1;
- }
-
- reboot(RB_AUTOBOOT);
-
- // Can't reboot? WTF?
- LOGE("Can't reboot\n");
- return -1;
-}
diff --git a/firmware.h b/firmware.h
deleted file mode 100644
index aeb8f97aa..000000000
--- a/firmware.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _RECOVERY_FIRMWARE_H
-#define _RECOVERY_FIRMWARE_H
-
-/* Save a radio or bootloader update image for later installation.
- * The type should be one of "hboot" or "radio".
- * Takes ownership of type and data. Returns nonzero on error.
- */
-int remember_firmware_update(const char *type, const char *data, int length);
-
-/* Returns true if a firmware update has been saved. */
-int firmware_update_pending();
-
-/* If an update was saved, reboot into the bootloader now to install it.
- * 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);
-
-#endif
diff --git a/install.c b/install.c
index 7710cecf2..37a4f0770 100644
--- a/install.c
+++ b/install.c
@@ -32,71 +32,10 @@
#include "mtdutils/mtdutils.h"
#include "roots.h"
#include "verifier.h"
-#include "firmware.h"
#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary"
#define PUBLIC_KEYS_FILE "/res/keys"
-// The update binary ask us to install a firmware file on reboot. Set
-// that up. Takes ownership of type and filename.
-static int
-handle_firmware_update(char* type, char* filename, ZipArchive* zip) {
- unsigned int data_size;
- const ZipEntry* entry = NULL;
-
- if (strncmp(filename, "PACKAGE:", 8) == 0) {
- entry = mzFindZipEntry(zip, filename+8);
- if (entry == NULL) {
- LOGE("Failed to find \"%s\" in package", filename+8);
- return INSTALL_ERROR;
- }
- data_size = entry->uncompLen;
- } else {
- struct stat st_data;
- if (stat(filename, &st_data) < 0) {
- LOGE("Error stat'ing %s: %s\n", filename, strerror(errno));
- return INSTALL_ERROR;
- }
- data_size = st_data.st_size;
- }
-
- LOGI("type is %s; size is %d; file is %s\n",
- type, data_size, filename);
-
- char* data = malloc(data_size);
- if (data == NULL) {
- LOGI("Can't allocate %d bytes for firmware data\n", data_size);
- return INSTALL_ERROR;
- }
-
- if (entry) {
- if (mzReadZipEntry(zip, entry, data, data_size) == false) {
- LOGE("Failed to read \"%s\" from package", filename+8);
- return INSTALL_ERROR;
- }
- } else {
- FILE* f = fopen(filename, "rb");
- if (f == NULL) {
- LOGE("Failed to open %s: %s\n", filename, strerror(errno));
- return INSTALL_ERROR;
- }
- if (fread(data, 1, data_size, f) != data_size) {
- LOGE("Failed to read firmware data: %s\n", strerror(errno));
- return INSTALL_ERROR;
- }
- fclose(f);
- }
-
- if (remember_firmware_update(type, data, data_size)) {
- LOGE("Can't store %s image\n", type);
- free(data);
- return INSTALL_ERROR;
- }
- free(filename);
-
- return INSTALL_SUCCESS;
-}
-
// If the package contains an update binary, extract it and run it.
static int
try_update_binary(const char *path, ZipArchive *zip) {
@@ -145,9 +84,12 @@ try_update_binary(const char *path, ZipArchive *zip) {
//
// firmware <"hboot"|"radio"> <filename>
// arrange to install the contents of <filename> in the
- // given partition on reboot. (API v2: <filename> may
- // start with "PACKAGE:" to indicate taking a file from
- // the OTA package.)
+ // given partition on reboot.
+ //
+ // (API v2: <filename> may start with "PACKAGE:" to
+ // indicate taking a file from the OTA package.)
+ //
+ // (API v3: this command no longer exists.)
//
// ui_print <string>
// display <string> on the screen.
@@ -172,9 +114,6 @@ try_update_binary(const char *path, ZipArchive *zip) {
}
close(pipefd[1]);
- char* firmware_type = NULL;
- char* firmware_filename = NULL;
-
char buffer[1024];
FILE* from_child = fdopen(pipefd[0], "r");
while (fgets(buffer, sizeof(buffer), from_child) != NULL) {
@@ -194,18 +133,6 @@ try_update_binary(const char *path, ZipArchive *zip) {
char* fraction_s = strtok(NULL, " \n");
float fraction = strtof(fraction_s, NULL);
ui_set_progress(fraction);
- } else if (strcmp(command, "firmware") == 0) {
- char* type = strtok(NULL, " \n");
- char* filename = strtok(NULL, " \n");
-
- if (type != NULL && filename != NULL) {
- if (firmware_type != NULL) {
- LOGE("ignoring attempt to do multiple firmware updates");
- } else {
- firmware_type = strdup(type);
- firmware_filename = strdup(filename);
- }
- }
} else if (strcmp(command, "ui_print") == 0) {
char* str = strtok(NULL, "\n");
if (str) {
@@ -226,11 +153,7 @@ try_update_binary(const char *path, ZipArchive *zip) {
return INSTALL_ERROR;
}
- if (firmware_type != NULL) {
- return handle_firmware_update(firmware_type, firmware_filename, zip);
- } else {
- return INSTALL_SUCCESS;
- }
+ return INSTALL_SUCCESS;
}
static int
@@ -275,7 +198,7 @@ load_keys(const char* filename, int* numKeys) {
++*numKeys;
out = realloc(out, *numKeys * sizeof(RSAPublicKey));
RSAPublicKey* key = out + (*numKeys - 1);
- if (fscanf(f, " { %i , %i , { %i",
+ if (fscanf(f, " { %i , 0x%x , { %u",
&(key->len), &(key->n0inv), &(key->n[0])) != 3) {
goto exit;
}
@@ -284,11 +207,11 @@ load_keys(const char* filename, int* numKeys) {
goto exit;
}
for (i = 1; i < key->len; ++i) {
- if (fscanf(f, " , %i", &(key->n[i])) != 1) goto exit;
+ if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit;
}
- if (fscanf(f, " } , { %i", &(key->rr[0])) != 1) goto exit;
+ if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit;
for (i = 1; i < key->len; ++i) {
- if (fscanf(f, " , %i", &(key->rr[i])) != 1) goto exit;
+ if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit;
}
fscanf(f, " } } ");
diff --git a/minui/resources.c b/minui/resources.c
index 7ecfeefce..3d2c727fb 100644
--- a/minui/resources.c
+++ b/minui/resources.c
@@ -97,9 +97,10 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
int color_type = info_ptr->color_type;
int bit_depth = info_ptr->bit_depth;
int channels = info_ptr->channels;
- if (bit_depth != 8 || (channels != 3 && channels != 4) ||
- (color_type != PNG_COLOR_TYPE_RGB &&
- color_type != PNG_COLOR_TYPE_RGBA)) {
+ if (!(bit_depth == 8 &&
+ ((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) ||
+ (channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) ||
+ (channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE)))) {
return -7;
goto exit;
}
@@ -118,6 +119,10 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
surface->format = (channels == 3) ?
GGL_PIXEL_FORMAT_RGBX_8888 : GGL_PIXEL_FORMAT_RGBA_8888;
+ if (color_type == PNG_COLOR_TYPE_PALETTE) {
+ png_set_palette_to_rgb(png_ptr);
+ }
+
int y;
if (channels == 3) {
for (y = 0; y < height; ++y) {
diff --git a/minzip/Zip.c b/minzip/Zip.c
index 8cdb89874..46d2f829e 100644
--- a/minzip/Zip.c
+++ b/minzip/Zip.c
@@ -810,6 +810,43 @@ bool mzExtractZipEntryToFile(const ZipArchive *pArchive,
return true;
}
+typedef struct {
+ unsigned char* buffer;
+ long len;
+} BufferExtractCookie;
+
+static bool bufferProcessFunction(const unsigned char *data, int dataLen,
+ void *cookie) {
+ BufferExtractCookie *bec = (BufferExtractCookie*)cookie;
+
+ memmove(bec->buffer, data, dataLen);
+ bec->buffer += dataLen;
+ bec->len -= dataLen;
+
+ return true;
+}
+
+/*
+ * Uncompress "pEntry" in "pArchive" to buffer, which must be large
+ * enough to hold mzGetZipEntryUncomplen(pEntry) bytes.
+ */
+bool mzExtractZipEntryToBuffer(const ZipArchive *pArchive,
+ const ZipEntry *pEntry, unsigned char *buffer)
+{
+ BufferExtractCookie bec;
+ bec.buffer = buffer;
+ bec.len = mzGetZipEntryUncompLen(pEntry);
+
+ bool ret = mzProcessZipEntryContents(pArchive, pEntry,
+ bufferProcessFunction, (void*)&bec);
+ if (!ret || bec.len != 0) {
+ LOGE("Can't extract entry to memory buffer.\n");
+ return false;
+ }
+ return true;
+}
+
+
/* Helper state to make path translation easier and less malloc-happy.
*/
typedef struct {
diff --git a/minzip/Zip.h b/minzip/Zip.h
index 1c1df2fae..9f99fba5b 100644
--- a/minzip/Zip.h
+++ b/minzip/Zip.h
@@ -169,6 +169,13 @@ bool mzExtractZipEntryToFile(const ZipArchive *pArchive,
const ZipEntry *pEntry, int fd);
/*
+ * Inflate and write an entry to a memory buffer, which must be long
+ * enough to hold mzGetZipEntryUncomplen(pEntry) bytes.
+ */
+bool mzExtractZipEntryToBuffer(const ZipArchive *pArchive,
+ const ZipEntry *pEntry, unsigned char* buffer);
+
+/*
* Inflate all entries under zipDir to the directory specified by
* targetDir, which must exist and be a writable directory.
*
diff --git a/recovery.c b/recovery.c
index 438530710..4c437e599 100644
--- a/recovery.c
+++ b/recovery.c
@@ -31,18 +31,20 @@
#include "bootloader.h"
#include "common.h"
#include "cutils/properties.h"
-#include "firmware.h"
#include "install.h"
#include "minui/minui.h"
#include "minzip/DirUtil.h"
#include "roots.h"
#include "recovery_ui.h"
+#include "efs_migration.h"
static const struct option OPTIONS[] = {
{ "send_intent", required_argument, NULL, 's' },
{ "update_package", required_argument, NULL, 'u' },
{ "wipe_data", no_argument, NULL, 'w' },
{ "wipe_cache", no_argument, NULL, 'c' },
+ // TODO{oam}: implement improved command line passing key, egnor to review.
+ { "set_encrypted_filesystem", required_argument, NULL, 'e' },
{ NULL, 0, NULL, 0 },
};
@@ -63,6 +65,7 @@ static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
* --update_package=root:path - verify install an OTA package file
* --wipe_data - erase user data (and cache), then reboot
* --wipe_cache - wipe cache (but not user data), then reboot
+ * --set_encrypted_filesystem=on|off - enables / diasables encrypted fs
*
* After completing, we remove /cache/recovery/command and reboot.
* Arguments may also be supplied in the bootloader control block (BCB).
@@ -107,6 +110,26 @@ static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
* 8g. finish_recovery() erases BCB
* -- after this, rebooting will (try to) restart the main system --
* 9. main() calls reboot() to boot main system
+ *
+ * ENCRYPTED FILE SYSTEMS ENABLE/DISABLE
+ * 1. user selects "enable encrypted file systems"
+ * 2. main system writes "--set_encrypted_filesystem=on|off" to
+ * /cache/recovery/command
+ * 3. main system reboots into recovery
+ * 4. get_args() writes BCB with "boot-recovery" and
+ * "--set_encrypted_filesystems=on|off"
+ * -- after this, rebooting will restart the transition --
+ * 5. read_encrypted_fs_info() retrieves encrypted file systems settings from /data
+ * Settings include: property to specify the Encrypted FS istatus and
+ * FS encryption key if enabled (not yet implemented)
+ * 6. erase_root() reformats /data
+ * 7. erase_root() reformats /cache
+ * 8. restore_encrypted_fs_info() writes required encrypted file systems settings to /data
+ * Settings include: property to specify the Encrypted FS status and
+ * FS encryption key if enabled (not yet implemented)
+ * 9. finish_recovery() erases BCB
+ * -- after this, rebooting will restart the main system --
+ * 10. main() calls reboot() to boot main system
*/
static const int MAX_ARG_LENGTH = 4096;
@@ -209,8 +232,7 @@ get_args(int *argc, char ***argv) {
}
static void
-set_sdcard_update_bootloader_message()
-{
+set_sdcard_update_bootloader_message() {
struct bootloader_message boot;
memset(&boot, 0, sizeof(boot));
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
@@ -223,8 +245,7 @@ set_sdcard_update_bootloader_message()
// record any intent we were asked to communicate back to the system.
// this function is idempotent: call it as many times as you like.
static void
-finish_recovery(const char *send_intent)
-{
+finish_recovery(const char *send_intent) {
// By this point, we're ready to return to the main system...
if (send_intent != NULL) {
FILE *fp = fopen_root_path(INTENT_FILE, "w");
@@ -255,7 +276,7 @@ finish_recovery(const char *send_intent)
check_and_fclose(log, LOG_FILE);
}
- // Reset the bootloader message to revert to a normal main system boot.
+ // Reset to mormal system boot so recovery won't cycle indefinitely.
struct bootloader_message boot;
memset(&boot, 0, sizeof(boot));
set_bootloader_message(&boot);
@@ -272,8 +293,7 @@ finish_recovery(const char *send_intent)
}
static int
-erase_root(const char *root)
-{
+erase_root(const char *root) {
ui_set_background(BACKGROUND_ICON_INSTALLING);
ui_show_indeterminate_progress();
ui_print("Formatting %s...\n", root);
@@ -384,8 +404,7 @@ wipe_data(int confirm) {
}
static void
-prompt_and_wait()
-{
+prompt_and_wait() {
char** headers = prepend_title(MENU_HEADERS);
for (;;) {
@@ -425,12 +444,7 @@ prompt_and_wait()
} else if (!ui_text_visible()) {
return; // reboot if logs aren't visible
} else {
- if (firmware_update_pending()) {
- ui_print("\nReboot via menu to complete\n"
- "installation.\n");
- } else {
- ui_print("\nInstall from sdcard complete.\n");
- }
+ ui_print("\nInstall from sdcard complete.\n");
}
break;
}
@@ -438,14 +452,12 @@ prompt_and_wait()
}
static void
-print_property(const char *key, const char *name, void *cookie)
-{
+print_property(const char *key, const char *name, void *cookie) {
fprintf(stderr, "%s=%s\n", key, name);
}
int
-main(int argc, char **argv)
-{
+main(int argc, char **argv) {
time_t start = time(NULL);
// If these fail, there's not really anywhere to complain...
@@ -459,7 +471,10 @@ main(int argc, char **argv)
int previous_runs = 0;
const char *send_intent = NULL;
const char *update_package = NULL;
+ const char *efs_mode = NULL;
int wipe_data = 0, wipe_cache = 0;
+ int toggle_efs = 0;
+ encrypted_fs_info efs_data;
int arg;
while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
@@ -469,12 +484,15 @@ main(int argc, char **argv)
case 'u': update_package = optarg; break;
case 'w': wipe_data = wipe_cache = 1; break;
case 'c': wipe_cache = 1; break;
+ case 'e': efs_mode = optarg; toggle_efs = 1; break;
case '?':
LOGE("Invalid command argument\n");
continue;
}
}
+ device_recovery_start();
+
fprintf(stderr, "Command:");
for (arg = 0; arg < argc; arg++) {
fprintf(stderr, " \"%s\"", argv[arg]);
@@ -486,7 +504,42 @@ main(int argc, char **argv)
int status = INSTALL_SUCCESS;
- if (update_package != NULL) {
+ if (toggle_efs) {
+ if (strcmp(efs_mode,"on") == 0) {
+ efs_data.encrypted_fs_mode = MODE_ENCRYPTEDFS_ENABLED;
+ ui_print("Enabling Encrypted FS.\n");
+ } else if (strcmp(efs_mode,"off") == 0) {
+ efs_data.encrypted_fs_mode = MODE_ENCRYPTEDFS_DISABLED;
+ ui_print("Disabling Encrypted FS.\n");
+ } else {
+ ui_print("Error: invalid Encrypted FS setting.\n");
+ status = INSTALL_ERROR;
+ }
+
+ // Recovery strategy: if the data partition is damaged, disable encrypted file systems.
+ // This preventsthe device recycling endlessly in recovery mode.
+ // TODO{oam}: implement improved recovery strategy later. egnor to review.
+ if (read_encrypted_fs_info(&efs_data)) {
+ ui_print("Encrypted FS change aborted, resetting to disabled state.\n");
+ efs_data.encrypted_fs_mode = MODE_ENCRYPTEDFS_DISABLED;
+ }
+
+ if (status != INSTALL_ERROR) {
+ if (erase_root("DATA:")) {
+ ui_print("Data wipe failed.\n");
+ status = INSTALL_ERROR;
+ } else if (erase_root("CACHE:")) {
+ ui_print("Cache wipe failed.\n");
+ status = INSTALL_ERROR;
+ } else if (restore_encrypted_fs_info(&efs_data)) {
+ ui_print("Encrypted FS change aborted.\n");
+ status = INSTALL_ERROR;
+ } else {
+ ui_print("Successfully updated Encrypted FS.\n");
+ status = INSTALL_SUCCESS;
+ }
+ }
+ } else if (update_package != NULL) {
status = install_package(update_package);
if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n");
} else if (wipe_data) {
@@ -504,9 +557,6 @@ main(int argc, char **argv)
if (status != INSTALL_SUCCESS) ui_set_background(BACKGROUND_ICON_ERROR);
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);
-
// Otherwise, get ready to boot the main system...
finish_recovery(send_intent);
ui_print("Rebooting...\n");
diff --git a/recovery_ui.h b/recovery_ui.h
index 8818ef303..e451bdfa2 100644
--- a/recovery_ui.h
+++ b/recovery_ui.h
@@ -17,6 +17,9 @@
#ifndef _RECOVERY_UI_H
#define _RECOVERY_UI_H
+// Called when recovery starts up. Returns 0.
+extern int device_recovery_start();
+
// Called in the input thread when a new key (key_code) is pressed.
// *key_pressed is an array of KEY_MAX+1 bytes indicating which other
// keys are already pressed. Return true if the text display should
diff --git a/res/images/icon_firmware_error.png b/res/images/icon_firmware_error.png
deleted file mode 100644
index 0c32c9ede..000000000
--- a/res/images/icon_firmware_error.png
+++ /dev/null
Binary files differ
diff --git a/res/images/icon_firmware_install.png b/res/images/icon_firmware_install.png
deleted file mode 100755
index 2da9e5ffe..000000000
--- a/res/images/icon_firmware_install.png
+++ /dev/null
Binary files differ
diff --git a/res/images/indeterminate1.png b/res/images/indeterminate1.png
index 264bf27e5..90cb9fba9 100644
--- a/res/images/indeterminate1.png
+++ b/res/images/indeterminate1.png
Binary files differ
diff --git a/res/images/indeterminate2.png b/res/images/indeterminate2.png
index c30c049ab..f7fb28989 100644
--- a/res/images/indeterminate2.png
+++ b/res/images/indeterminate2.png
Binary files differ
diff --git a/res/images/indeterminate3.png b/res/images/indeterminate3.png
index 891a00095..ba10dfa53 100644
--- a/res/images/indeterminate3.png
+++ b/res/images/indeterminate3.png
Binary files differ
diff --git a/res/images/indeterminate4.png b/res/images/indeterminate4.png
index 7a6415149..ad5d9a542 100644
--- a/res/images/indeterminate4.png
+++ b/res/images/indeterminate4.png
Binary files differ
diff --git a/res/images/indeterminate5.png b/res/images/indeterminate5.png
index cd6ab20a7..8c19c8d57 100644
--- a/res/images/indeterminate5.png
+++ b/res/images/indeterminate5.png
Binary files differ
diff --git a/res/images/indeterminate6.png b/res/images/indeterminate6.png
index ddd9e7384..c0c66386a 100644
--- a/res/images/indeterminate6.png
+++ b/res/images/indeterminate6.png
Binary files differ
diff --git a/res/images/progress_bar_empty.png b/res/images/progress_bar_empty.png
deleted file mode 100644
index 9013f04ac..000000000
--- a/res/images/progress_bar_empty.png
+++ /dev/null
Binary files differ
diff --git a/res/images/progress_bar_empty_left_round.png b/res/images/progress_bar_empty_left_round.png
deleted file mode 100644
index dae7d5d13..000000000
--- a/res/images/progress_bar_empty_left_round.png
+++ /dev/null
Binary files differ
diff --git a/res/images/progress_bar_empty_right_round.png b/res/images/progress_bar_empty_right_round.png
deleted file mode 100644
index 542708823..000000000
--- a/res/images/progress_bar_empty_right_round.png
+++ /dev/null
Binary files differ
diff --git a/res/images/progress_bar_fill.png b/res/images/progress_bar_fill.png
deleted file mode 100644
index 37c04b4f4..000000000
--- a/res/images/progress_bar_fill.png
+++ /dev/null
Binary files differ
diff --git a/res/images/progress_bar_left_round.png b/res/images/progress_bar_left_round.png
deleted file mode 100644
index e72af47d4..000000000
--- a/res/images/progress_bar_left_round.png
+++ /dev/null
Binary files differ
diff --git a/res/images/progress_bar_right_round.png b/res/images/progress_bar_right_round.png
deleted file mode 100644
index d04c980b9..000000000
--- a/res/images/progress_bar_right_round.png
+++ /dev/null
Binary files differ
diff --git a/res/images/progress_empty.png b/res/images/progress_empty.png
new file mode 100644
index 000000000..4cb4998dd
--- /dev/null
+++ b/res/images/progress_empty.png
Binary files differ
diff --git a/res/images/progress_fill.png b/res/images/progress_fill.png
new file mode 100644
index 000000000..eb71754db
--- /dev/null
+++ b/res/images/progress_fill.png
Binary files differ
diff --git a/testdata/alter-footer.zip b/testdata/alter-footer.zip
new file mode 100644
index 000000000..f497ec000
--- /dev/null
+++ b/testdata/alter-footer.zip
Binary files differ
diff --git a/testdata/alter-metadata.zip b/testdata/alter-metadata.zip
new file mode 100644
index 000000000..1c71fbc49
--- /dev/null
+++ b/testdata/alter-metadata.zip
Binary files differ
diff --git a/testdata/fake-eocd.zip b/testdata/fake-eocd.zip
new file mode 100644
index 000000000..15dc0a946
--- /dev/null
+++ b/testdata/fake-eocd.zip
Binary files differ
diff --git a/testdata/jarsigned.zip b/testdata/jarsigned.zip
new file mode 100644
index 000000000..8b1ef8bdd
--- /dev/null
+++ b/testdata/jarsigned.zip
Binary files differ
diff --git a/testdata/otasigned.zip b/testdata/otasigned.zip
new file mode 100644
index 000000000..a6bc53e41
--- /dev/null
+++ b/testdata/otasigned.zip
Binary files differ
diff --git a/testdata/random.zip b/testdata/random.zip
new file mode 100644
index 000000000..18c0b3b9f
--- /dev/null
+++ b/testdata/random.zip
Binary files differ
diff --git a/testdata/unsigned.zip b/testdata/unsigned.zip
new file mode 100644
index 000000000..24e3eadac
--- /dev/null
+++ b/testdata/unsigned.zip
Binary files differ
diff --git a/ui.c b/ui.c
index 51df1fa9f..01a005f80 100644
--- a/ui.c
+++ b/ui.c
@@ -38,33 +38,23 @@
#define PROGRESSBAR_INDETERMINATE_STATES 6
#define PROGRESSBAR_INDETERMINATE_FPS 15
-enum { LEFT_SIDE, CENTER_TILE, RIGHT_SIDE, NUM_SIDES };
-
static pthread_mutex_t gUpdateMutex = PTHREAD_MUTEX_INITIALIZER;
static gr_surface gBackgroundIcon[NUM_BACKGROUND_ICONS];
static gr_surface gProgressBarIndeterminate[PROGRESSBAR_INDETERMINATE_STATES];
-static gr_surface gProgressBarEmpty[NUM_SIDES];
-static gr_surface gProgressBarFill[NUM_SIDES];
+static gr_surface gProgressBarEmpty;
+static gr_surface gProgressBarFill;
static const struct { gr_surface* surface; const char *name; } BITMAPS[] = {
{ &gBackgroundIcon[BACKGROUND_ICON_INSTALLING], "icon_installing" },
{ &gBackgroundIcon[BACKGROUND_ICON_ERROR], "icon_error" },
- { &gBackgroundIcon[BACKGROUND_ICON_FIRMWARE_INSTALLING],
- "icon_firmware_install" },
- { &gBackgroundIcon[BACKGROUND_ICON_FIRMWARE_ERROR],
- "icon_firmware_error" },
{ &gProgressBarIndeterminate[0], "indeterminate1" },
{ &gProgressBarIndeterminate[1], "indeterminate2" },
{ &gProgressBarIndeterminate[2], "indeterminate3" },
{ &gProgressBarIndeterminate[3], "indeterminate4" },
{ &gProgressBarIndeterminate[4], "indeterminate5" },
{ &gProgressBarIndeterminate[5], "indeterminate6" },
- { &gProgressBarEmpty[LEFT_SIDE], "progress_bar_empty_left_round" },
- { &gProgressBarEmpty[CENTER_TILE], "progress_bar_empty" },
- { &gProgressBarEmpty[RIGHT_SIDE], "progress_bar_empty_right_round" },
- { &gProgressBarFill[LEFT_SIDE], "progress_bar_left_round" },
- { &gProgressBarFill[CENTER_TILE], "progress_bar_fill" },
- { &gProgressBarFill[RIGHT_SIDE], "progress_bar_right_round" },
+ { &gProgressBarEmpty, "progress_empty" },
+ { &gProgressBarFill, "progress_fill" },
{ NULL, NULL },
};
@@ -123,8 +113,8 @@ static void draw_progress_locked()
if (gProgressBarType == PROGRESSBAR_TYPE_NONE) return;
int iconHeight = gr_get_height(gBackgroundIcon[BACKGROUND_ICON_INSTALLING]);
- int width = gr_get_width(gProgressBarIndeterminate[0]);
- int height = gr_get_height(gProgressBarIndeterminate[0]);
+ int width = gr_get_width(gProgressBarEmpty);
+ int height = gr_get_height(gProgressBarEmpty);
int dx = (gr_fb_width() - width)/2;
int dy = (3*gr_fb_height() + iconHeight - 2*height)/4;
@@ -137,18 +127,12 @@ static void draw_progress_locked()
float progress = gProgressScopeStart + gProgress * gProgressScopeSize;
int pos = (int) (progress * width);
- gr_surface s = (pos ? gProgressBarFill : gProgressBarEmpty)[LEFT_SIDE];
- gr_blit(s, 0, 0, gr_get_width(s), gr_get_height(s), dx, dy);
-
- int x = gr_get_width(s);
- while (x + (int) gr_get_width(gProgressBarEmpty[RIGHT_SIDE]) < width) {
- s = (pos > x ? gProgressBarFill : gProgressBarEmpty)[CENTER_TILE];
- gr_blit(s, 0, 0, gr_get_width(s), gr_get_height(s), dx + x, dy);
- x += gr_get_width(s);
+ if (pos > 0) {
+ gr_blit(gProgressBarFill, 0, 0, pos, height, dx, dy);
+ }
+ if (pos < width-1) {
+ gr_blit(gProgressBarEmpty, pos, 0, width-pos, height, dx+pos, dy);
}
-
- s = (pos > x ? gProgressBarFill : gProgressBarEmpty)[RIGHT_SIDE];
- gr_blit(s, 0, 0, gr_get_width(s), gr_get_height(s), dx + x, dy);
}
if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE) {
@@ -353,23 +337,6 @@ void ui_init(void)
pthread_create(&t, NULL, input_thread, NULL);
}
-char *ui_copy_image(int icon, int *width, int *height, int *bpp) {
- pthread_mutex_lock(&gUpdateMutex);
- draw_background_locked(gBackgroundIcon[icon]);
- *width = gr_fb_width();
- *height = gr_fb_height();
- *bpp = sizeof(gr_pixel) * 8;
- int size = *width * *height * sizeof(gr_pixel);
- char *ret = malloc(size);
- if (ret == NULL) {
- LOGE("Can't allocate %d bytes for image\n", size);
- } else {
- memcpy(ret, gr_fb_data(), size);
- }
- pthread_mutex_unlock(&gUpdateMutex);
- return ret;
-}
-
void ui_set_background(int icon)
{
pthread_mutex_lock(&gUpdateMutex);
diff --git a/updater/install.c b/updater/install.c
index aa80d7576..852b393ea 100644
--- a/updater/install.c
+++ b/updater/install.c
@@ -315,37 +315,82 @@ char* PackageExtractDirFn(const char* name, State* state,
// package_extract_file(package_path, destination_path)
+// or
+// package_extract_file(package_path)
+// to return the entire contents of the file as the result of this
+// function (the char* returned points to a long giving the length
+// followed by that many bytes of data).
char* PackageExtractFileFn(const char* name, State* state,
int argc, Expr* argv[]) {
- if (argc != 2) {
- return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
+ if (argc != 1 && argc != 2) {
+ return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
+ name, argc);
}
- char* zip_path;
- char* dest_path;
- if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
-
bool success = false;
+ if (argc == 2) {
+ // The two-argument version extracts to a file.
+
+ char* zip_path;
+ char* dest_path;
+ if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL;
+
+ ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
+ const ZipEntry* entry = mzFindZipEntry(za, zip_path);
+ if (entry == NULL) {
+ fprintf(stderr, "%s: no %s in package\n", name, zip_path);
+ goto done2;
+ }
- ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
- const ZipEntry* entry = mzFindZipEntry(za, zip_path);
- if (entry == NULL) {
- fprintf(stderr, "%s: no %s in package\n", name, zip_path);
- goto done;
- }
+ FILE* f = fopen(dest_path, "wb");
+ if (f == NULL) {
+ fprintf(stderr, "%s: can't open %s for write: %s\n",
+ name, dest_path, strerror(errno));
+ goto done2;
+ }
+ success = mzExtractZipEntryToFile(za, entry, fileno(f));
+ fclose(f);
- FILE* f = fopen(dest_path, "wb");
- if (f == NULL) {
- fprintf(stderr, "%s: can't open %s for write: %s\n",
- name, dest_path, strerror(errno));
- goto done;
- }
- success = mzExtractZipEntryToFile(za, entry, fileno(f));
- fclose(f);
+ done2:
+ free(zip_path);
+ free(dest_path);
+ return strdup(success ? "t" : "");
+ } else {
+ // The one-argument version returns the contents of the file
+ // as the result.
- done:
- free(zip_path);
- free(dest_path);
- return strdup(success ? "t" : "");
+ char* zip_path;
+ char* buffer = NULL;
+
+ if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL;
+
+ ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
+ const ZipEntry* entry = mzFindZipEntry(za, zip_path);
+ if (entry == NULL) {
+ fprintf(stderr, "%s: no %s in package\n", name, zip_path);
+ goto done1;
+ }
+
+ long size = mzGetZipEntryUncompLen(entry);
+ buffer = malloc(size + sizeof(long));
+ if (buffer == NULL) {
+ fprintf(stderr, "%s: failed to allocate %ld bytes for %s\n",
+ name, size+sizeof(long), zip_path);
+ goto done1;
+ }
+
+ *(long *)buffer = size;
+ success = mzExtractZipEntryToBuffer(
+ za, entry, (unsigned char *)(buffer + sizeof(long)));
+
+ done1:
+ free(zip_path);
+ if (!success) {
+ free(buffer);
+ buffer = malloc(sizeof(long));
+ *(long *)buffer = -1L;
+ }
+ return buffer;
+ }
}
@@ -658,44 +703,6 @@ done:
return result;
}
-// write_firmware_image(file, partition)
-//
-// partition is "radio" or "hboot"
-// file is not used until after updater exits
-//
-// TODO: this should live in some HTC-specific library
-char* WriteFirmwareImageFn(const char* name, State* state,
- int argc, Expr* argv[]) {
- char* result = NULL;
-
- char* partition;
- char* filename;
- if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
- return NULL;
- }
-
- if (strlen(partition) == 0) {
- ErrorAbort(state, "partition argument to %s can't be empty", name);
- goto done;
- }
- if (strlen(filename) == 0) {
- ErrorAbort(state, "file argument to %s can't be empty", name);
- goto done;
- }
-
- FILE* cmd = ((UpdaterInfo*)(state->cookie))->cmd_pipe;
- fprintf(cmd, "firmware %s %s\n", partition, filename);
-
- printf("will write %s firmware from %s\n", partition, filename);
- result = partition;
-
-done:
- if (result != partition) free(partition);
- free(filename);
- return result;
-}
-
-
extern int applypatch(int argc, char** argv);
// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1:patch, ...)
@@ -843,7 +850,6 @@ void RegisterInstallFunctions() {
RegisterFunction("getprop", GetPropFn);
RegisterFunction("file_getprop", FileGetPropFn);
RegisterFunction("write_raw_image", WriteRawImageFn);
- RegisterFunction("write_firmware_image", WriteFirmwareImageFn);
RegisterFunction("apply_patch", ApplyPatchFn);
RegisterFunction("apply_patch_check", ApplyPatchFn);
diff --git a/updater/updater.c b/updater/updater.c
index 1aa277c7f..2d16deeba 100644
--- a/updater/updater.c
+++ b/updater/updater.c
@@ -39,9 +39,11 @@ int main(int argc, char** argv) {
}
char* version = argv[1];
- if ((version[0] != '1' && version[0] != '2') || version[1] != '\0') {
- // We support version "1" or "2".
- fprintf(stderr, "wrong updater binary API; expected 1 or 2, got %s\n",
+ if ((version[0] != '1' && version[0] != '2' && version[0] != '3') ||
+ version[1] != '\0') {
+ // We support version 1, 2, or 3.
+ fprintf(stderr, "wrong updater binary API; expected 1, 2, or 3; "
+ "got %s\n",
argv[1]);
return 2;
}
@@ -100,6 +102,7 @@ int main(int argc, char** argv) {
UpdaterInfo updater_info;
updater_info.cmd_pipe = cmd_pipe;
updater_info.package_zip = &za;
+ updater_info.version = atoi(version);
State state;
state.cookie = &updater_info;
diff --git a/updater/updater.h b/updater/updater.h
index 22fbfd285..bd60dc1fd 100644
--- a/updater/updater.h
+++ b/updater/updater.h
@@ -23,6 +23,7 @@
typedef struct {
FILE* cmd_pipe;
ZipArchive* package_zip;
+ int version;
} UpdaterInfo;
#endif
diff --git a/verifier.c b/verifier.c
index 164fb4a01..9d39fd139 100644
--- a/verifier.c
+++ b/verifier.c
@@ -42,7 +42,7 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
// An archive with a whole-file signature will end in six bytes:
//
- // $ff $ff (2-byte comment size) (2-byte signature start)
+ // (2-byte signature start) $ff $ff (2-byte comment size)
//
// (As far as the ZIP format is concerned, these are part of the
// archive comment.) We start by reading this footer, this tells
@@ -169,7 +169,7 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
const uint8_t* sha1 = SHA_final(&ctx);
for (i = 0; i < numKeys; ++i) {
- // The 6 bytes is the "$ff $ff (signature_start) (comment_size)" that
+ // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that
// the signing tool appends after the signature itself.
if (RSA_verify(pKeys+i, eocd + eocd_size - 6 - RSANUMBYTES,
RSANUMBYTES, sha1)) {
diff --git a/verifier_test.c b/verifier_test.c
new file mode 100644
index 000000000..5b6c1f451
--- /dev/null
+++ b/verifier_test.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "verifier.h"
+
+// This is build/target/product/security/testkey.x509.pem after being
+// dumped out by dumpkey.jar.
+RSAPublicKey test_key =
+ { 64, 0xc926ad21,
+ { 1795090719, 2141396315, 950055447, -1713398866,
+ -26044131, 1920809988, 546586521, -795969498,
+ 1776797858, -554906482, 1805317999, 1429410244,
+ 129622599, 1422441418, 1783893377, 1222374759,
+ -1731647369, 323993566, 28517732, 609753416,
+ 1826472888, 215237850, -33324596, -245884705,
+ -1066504894, 774857746, 154822455, -1797768399,
+ -1536767878, -1275951968, -1500189652, 87251430,
+ -1760039318, 120774784, 571297800, -599067824,
+ -1815042109, -483341846, -893134306, -1900097649,
+ -1027721089, 950095497, 555058928, 414729973,
+ 1136544882, -1250377212, 465547824, -236820568,
+ -1563171242, 1689838846, -404210357, 1048029507,
+ 895090649, 247140249, 178744550, -747082073,
+ -1129788053, 109881576, -350362881, 1044303212,
+ -522594267, -1309816990, -557446364, -695002876},
+ { -857949815, -510492167, -1494742324, -1208744608,
+ 251333580, 2131931323, 512774938, 325948880,
+ -1637480859, 2102694287, -474399070, 792812816,
+ 1026422502, 2053275343, -1494078096, -1181380486,
+ 165549746, -21447327, -229719404, 1902789247,
+ 772932719, -353118870, -642223187, 216871947,
+ -1130566647, 1942378755, -298201445, 1055777370,
+ 964047799, 629391717, -2062222979, -384408304,
+ 191868569, -1536083459, -612150544, -1297252564,
+ -1592438046, -724266841, -518093464, -370899750,
+ -739277751, -1536141862, 1323144535, 61311905,
+ 1997411085, 376844204, 213777604, -217643712,
+ 9135381, 1625809335, -1490225159, -1342673351,
+ 1117190829, -57654514, 1825108855, -1281819325,
+ 1111251351, -1726129724, 1684324211, -1773988491,
+ 367251975, 810756730, -1941182952, 1175080310 }
+ };
+
+void ui_print(const char* fmt, ...) {
+ char buf[256];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buf, 256, fmt, ap);
+ va_end(ap);
+
+ fputs(buf, stderr);
+}
+
+void ui_set_progress(float fraction) {
+}
+
+int main(int argc, char **argv) {
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <package>\n", argv[0]);
+ return 2;
+ }
+
+ int result = verify_file(argv[1], &test_key, 1);
+ if (result == VERIFY_SUCCESS) {
+ printf("SUCCESS\n");
+ return 0;
+ } else if (result == VERIFY_FAILURE) {
+ printf("FAILURE\n");
+ return 1;
+ } else {
+ printf("bad return value\n");
+ return 3;
+ }
+}
diff --git a/verifier_test.sh b/verifier_test.sh
new file mode 100755
index 000000000..6350e80d3
--- /dev/null
+++ b/verifier_test.sh
@@ -0,0 +1,94 @@
+#!/bin/bash
+#
+# A test suite for applypatch. Run in a client where you have done
+# envsetup, choosecombo, etc.
+#
+# DO NOT RUN THIS ON A DEVICE YOU CARE ABOUT. It will mess up your
+# system partition.
+#
+#
+# TODO: find some way to get this run regularly along with the rest of
+# the tests.
+
+EMULATOR_PORT=5580
+DATA_DIR=$ANDROID_BUILD_TOP/bootable/recovery/testdata
+
+WORK_DIR=/data/local/tmp
+
+# set to 0 to use a device instead
+USE_EMULATOR=0
+
+# ------------------------
+
+if [ "$USE_EMULATOR" == 1 ]; then
+ emulator -wipe-data -noaudio -no-window -port $EMULATOR_PORT &
+ pid_emulator=$!
+ ADB="adb -s emulator-$EMULATOR_PORT "
+else
+ ADB="adb -d "
+fi
+
+echo "waiting to connect to device"
+$ADB wait-for-device
+
+# run a command on the device; exit with the exit status of the device
+# command.
+run_command() {
+ $ADB shell "$@" \; echo \$? | awk '{if (b) {print a}; a=$0; b=1} END {exit a}'
+}
+
+testname() {
+ echo
+ echo "::: testing $1 :::"
+ testname="$1"
+}
+
+fail() {
+ echo
+ echo FAIL: $testname
+ echo
+ [ "$open_pid" == "" ] || kill $open_pid
+ [ "$pid_emulator" == "" ] || kill $pid_emulator
+ exit 1
+}
+
+
+cleanup() {
+ # not necessary if we're about to kill the emulator, but nice for
+ # running on real devices or already-running emulators.
+ run_command rm $WORK_DIR/verifier_test
+ run_command rm $WORK_DIR/package.zip
+
+ [ "$pid_emulator" == "" ] || kill $pid_emulator
+}
+
+$ADB push $ANDROID_PRODUCT_OUT/system/bin/verifier_test \
+ $WORK_DIR/verifier_test
+
+expect_succeed() {
+ testname "$1 (should succeed)"
+ $ADB push $DATA_DIR/$1 $WORK_DIR/package.zip
+ run_command $WORK_DIR/verifier_test $WORK_DIR/package.zip || fail
+}
+
+expect_fail() {
+ testname "$1 (should fail)"
+ $ADB push $DATA_DIR/$1 $WORK_DIR/package.zip
+ run_command $WORK_DIR/verifier_test $WORK_DIR/package.zip && fail
+}
+
+expect_fail unsigned.zip
+expect_fail jarsigned.zip
+expect_succeed otasigned.zip
+expect_fail random.zip
+expect_fail fake-eocd.zip
+expect_fail alter-metadata.zip
+expect_fail alter-footer.zip
+
+# --------------- cleanup ----------------------
+
+cleanup
+
+echo
+echo PASS
+echo