diff options
Diffstat (limited to 'applypatch')
-rw-r--r-- | applypatch/Android.mk | 50 | ||||
-rw-r--r-- | applypatch/applypatch.cpp | 320 |
2 files changed, 253 insertions, 117 deletions
diff --git a/applypatch/Android.mk b/applypatch/Android.mk index a7412d238..9cbe3e2a9 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -14,6 +14,35 @@ LOCAL_PATH := $(call my-dir) +ifdef project-path-for + RECOVERY_PATH := $(call project-path-for,recovery) +else + RECOVERY_PATH := bootable/recovery +endif + +include $(CLEAR_VARS) + +BOARD_RECOVERY_DEFINES := BOARD_BML_BOOT BOARD_BML_RECOVERY + +$(foreach board_define,$(BOARD_RECOVERY_DEFINES), \ + $(if $($(board_define)), \ + $(eval LOCAL_CFLAGS += -D$(board_define)=\"$($(board_define))\") \ + ) \ + ) + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/include \ + external/bzip2 \ + external/zlib \ + $(commands_recovery_local_path) + +LOCAL_CLANG := true +LOCAL_SRC_FILES := applypatch.cpp bspatch.cpp freecache.cpp imgpatch.cpp utils.cpp +LOCAL_MODULE := libapplypatch +LOCAL_MODULE_TAGS := eng +LOCAL_C_INCLUDES += $(RECOVERY_PATH) +LOCAL_STATIC_LIBRARIES += libbase libotafault libmtdutils libcrypto_static libbz libz + # libapplypatch (static library) # =============================== include $(CLEAR_VARS) @@ -24,10 +53,10 @@ LOCAL_SRC_FILES := \ imgpatch.cpp LOCAL_MODULE := libapplypatch LOCAL_MODULE_TAGS := eng +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/include \ - bootable/recovery -LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include + $(commands_recovery_local_path) LOCAL_STATIC_LIBRARIES := \ libotafault \ libbase \ @@ -35,6 +64,7 @@ LOCAL_STATIC_LIBRARIES := \ libbspatch \ libbz \ libz +LOCAL_WHOLE_STATIC_LIBRARIES += libmtdutils LOCAL_CFLAGS := \ -DZLIB_CONST \ -Werror @@ -43,13 +73,14 @@ include $(BUILD_STATIC_LIBRARY) # libimgpatch (static library) # =============================== include $(CLEAR_VARS) + LOCAL_SRC_FILES := \ bspatch.cpp \ imgpatch.cpp LOCAL_MODULE := libimgpatch LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/include \ - bootable/recovery + $(commands_recovery_local_path) LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES := \ libcrypto \ @@ -69,10 +100,11 @@ LOCAL_SRC_FILES := \ bspatch.cpp \ imgpatch.cpp LOCAL_MODULE := libimgpatch +LOCAL_C_INCLUDES += $(RECOVERY_PATH) LOCAL_MODULE_HOST_OS := linux LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/include \ - bootable/recovery + $(commands_recovery_local_path) LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_STATIC_LIBRARIES := \ libcrypto \ @@ -91,7 +123,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ applypatch_modes.cpp LOCAL_MODULE := libapplypatch_modes -LOCAL_C_INCLUDES := bootable/recovery +LOCAL_C_INCLUDES := $(commands_recovery_local_path) LOCAL_STATIC_LIBRARIES := \ libapplypatch \ libbase \ @@ -105,7 +137,13 @@ include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_SRC_FILES := applypatch_main.cpp LOCAL_MODULE := applypatch -LOCAL_C_INCLUDES := bootable/recovery +LOCAL_C_INCLUDES += $(RECOVERY_PATH) +LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libcrypto_static libbz \ + libedify \ + +LOCAL_SHARED_LIBRARIES += libz libcutils libc + +LOCAL_C_INCLUDES := $(commands_recovery_local_path) LOCAL_STATIC_LIBRARIES := \ libapplypatch_modes \ libapplypatch \ diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 51bf3932a..43e9b80dc 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -38,6 +38,9 @@ #include <android-base/strings.h> #include <openssl/sha.h> +#include "bmlutils/bmlutils.h" +#include "mtdutils/mtdutils.h" + #include "edify/expr.h" #include "ota_io.h" #include "print_sha1.h" @@ -48,11 +51,16 @@ static int GenerateTarget(const FileContents& source_file, const std::unique_ptr const std::string& target_filename, const uint8_t target_sha1[SHA_DIGEST_LENGTH], const Value* bonus_data); +static bool mtd_partitions_scanned = false; + // Read a file into memory; store the file contents and associated metadata in *file. // Return 0 on success. int LoadFileContents(const char* filename, FileContents* file) { - // A special 'filename' beginning with "EMMC:" means to load the contents of a partition. - if (strncmp(filename, "EMMC:", 5) == 0) { + // A special 'filename' beginning with "MTD:" or "EMMC:" means to + // load the contents of a partition. + if (strncmp(filename, "MTD:", 4) == 0 || + strncmp(filename, "EMMC:", 5) == 0 || + strncmp(filename, "BML:", 4) == 0) { return LoadPartitionContents(filename, file); } @@ -92,13 +100,27 @@ int LoadFileContents(const char* filename, FileContents* file) { // "end-of-file" marker), so the caller must specify the possible // lengths and the hash of the data, and we'll do the load expecting // to find one of those hashes. +enum PartitionType { MTD, EMMC }; + static int LoadPartitionContents(const std::string& filename, FileContents* file) { std::vector<std::string> pieces = android::base::Split(filename, ":"); - if (pieces.size() < 4 || pieces.size() % 2 != 0 || pieces[0] != "EMMC") { + if (pieces.size() < 4 || pieces.size() % 2 != 0) { printf("LoadPartitionContents called with bad filename \"%s\"\n", filename.c_str()); return -1; } + enum PartitionType type; + if (pieces[0] == "MTD") { + type = MTD; + } else if (pieces[0] == "EMMC") { + type = EMMC; + } else if (pieces[0] == "BML") { + type = EMMC; + } else { + printf("LoadPartitionContents called with bad filename (%s)\n", filename.c_str()); + return -1; + } + size_t pair_count = (pieces.size() - 2) / 2; // # of (size, sha1) pairs in filename std::vector<std::pair<size_t, std::string>> pairs; for (size_t i = 0; i < pair_count; ++i) { @@ -147,6 +169,14 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file buffer_ptr += read; } + if (pieces[0] == "BML") { + if (strcmp(partition, "boot") == 0) { + partition = BOARD_BML_BOOT; + } else if (strcmp(partition, "recovery") == 0) { + partition = BOARD_BML_RECOVERY; + } + } + // Duplicate the SHA context and finalize the duplicate so we can // check it against this pair's expected hash. SHA_CTX temp_ctx; @@ -227,131 +257,199 @@ int SaveFileContents(const char* filename, const FileContents* file) { // might contain multiple colons, but WriteToPartition() only uses the first // two and ignores the rest. Return 0 on success. int WriteToPartition(const unsigned char* data, size_t len, const std::string& target) { - std::vector<std::string> pieces = android::base::Split(target, ":"); - if (pieces.size() < 2 || pieces[0] != "EMMC") { - printf("WriteToPartition called with bad target (%s)\n", target.c_str()); - return -1; - } - - const char* partition = pieces[1].c_str(); - unique_fd fd(ota_open(partition, O_RDWR)); - if (fd == -1) { - printf("failed to open %s: %s\n", partition, strerror(errno)); - return -1; - } + std::string copy(target); + std::vector<std::string> pieces = android::base::Split(copy, ":"); - size_t start = 0; - bool success = false; - for (size_t attempt = 0; attempt < 2; ++attempt) { - if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) { - printf("failed seek on %s: %s\n", partition, strerror(errno)); - return -1; - } - while (start < len) { - size_t to_write = len - start; - if (to_write > 1 << 20) to_write = 1 << 20; - - ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data + start, to_write)); - if (written == -1) { - printf("failed write writing to %s: %s\n", partition, strerror(errno)); + if (pieces.size() < 2) { + printf("WriteToPartition called with bad target (%s)\n", target.c_str()); return -1; - } - start += written; - } - - if (ota_fsync(fd) != 0) { - printf("failed to sync to %s: %s\n", partition, strerror(errno)); - return -1; - } - if (ota_close(fd) != 0) { - printf("failed to close %s: %s\n", partition, strerror(errno)); - return -1; - } - - fd.reset(ota_open(partition, O_RDONLY)); - if (fd == -1) { - printf("failed to reopen %s for verify: %s\n", partition, strerror(errno)); - return -1; } - // Drop caches so our subsequent verification read won't just be reading the cache. - sync(); - unique_fd dc(ota_open("/proc/sys/vm/drop_caches", O_WRONLY)); - if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) { - printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); + enum PartitionType type; + if (pieces[0] == "MTD") { + type = MTD; + } else if (pieces[0] == "EMMC") { + type = EMMC; + } else if (pieces[0] == "BML") { + type = EMMC; } else { - printf(" caches dropped\n"); - } - ota_close(dc); - sleep(1); - - // Verify. - if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) { - printf("failed to seek back to beginning of %s: %s\n", partition, strerror(errno)); - return -1; + printf("WriteToPartition called with bad target (%s)\n", target.c_str()); + return -1; } - unsigned char buffer[4096]; - start = len; - for (size_t p = 0; p < len; p += sizeof(buffer)) { - size_t to_read = len - p; - if (to_read > sizeof(buffer)) { - to_read = sizeof(buffer); - } + const char* partition = pieces[1].c_str(); - size_t so_far = 0; - while (so_far < to_read) { - ssize_t read_count = TEMP_FAILURE_RETRY(ota_read(fd, buffer + so_far, to_read - so_far)); - if (read_count == -1) { - printf("verify read error %s at %zu: %s\n", partition, p, strerror(errno)); - return -1; - } else if (read_count == 0) { - printf("verify read reached unexpected EOF, %s at %zu\n", partition, p); - return -1; - } - if (static_cast<size_t>(read_count) < to_read) { - printf("short verify read %s at %zu: %zd %zu\n", partition, p, read_count, to_read); + if (pieces[0] == "BML") { + if (strcmp(partition, "boot") == 0) { + partition = BOARD_BML_BOOT; + } else if (strcmp(partition, "recovery") == 0) { + partition = BOARD_BML_RECOVERY; } - so_far += read_count; - } - if (memcmp(buffer, data + p, to_read) != 0) { - printf("verification failed starting at %zu\n", p); - start = p; - break; - } + int bmlpartition = open(partition, O_RDWR | O_LARGEFILE); + if (bmlpartition < 0) + return -1; + if (ioctl(bmlpartition, BML_UNLOCK_ALL, 0)) { + printf("failed to unlock BML partition: (%s)\n", partition); + return -1; + } + close(bmlpartition); } - if (start == len) { - printf("verification read succeeded (attempt %zu)\n", attempt + 1); - success = true; - break; + if (partition == NULL) { + printf("bad partition target name \"%s\"\n", target.c_str()); + return -1; } - if (ota_close(fd) != 0) { - printf("failed to close %s: %s\n", partition, strerror(errno)); - return -1; - } + switch (type) { + case MTD: { + if (!mtd_partitions_scanned) { + mtd_scan_partitions(); + mtd_partitions_scanned = true; + } + + const MtdPartition* mtd = mtd_find_partition_by_name(partition); + if (mtd == NULL) { + printf("mtd partition \"%s\" not found for writing\n", partition); + return -1; + } + + MtdWriteContext* ctx = mtd_write_partition(mtd); + if (ctx == NULL) { + printf("failed to init mtd partition \"%s\" for writing\n", partition); + return -1; + } + + size_t written = mtd_write_data(ctx, reinterpret_cast<const char*>(data), len); + if (written != len) { + printf("only wrote %zu of %zu bytes to MTD %s\n", written, len, partition); + mtd_write_close(ctx); + return -1; + } + + if (mtd_erase_blocks(ctx, -1) < 0) { + printf("error finishing mtd write of %s\n", partition); + mtd_write_close(ctx); + return -1; + } + + if (mtd_write_close(ctx)) { + printf("error closing mtd write of %s\n", partition); + return -1; + } + break; + } - fd.reset(ota_open(partition, O_RDWR)); - if (fd == -1) { - printf("failed to reopen %s for retry write && verify: %s\n", partition, strerror(errno)); - return -1; + case EMMC: { + size_t start = 0; + bool success = false; + unique_fd fd(ota_open(partition, O_RDWR | O_SYNC)); + if (fd < 0) { + printf("failed to open %s: %s\n", partition, strerror(errno)); + return -1; + } + + for (size_t attempt = 0; attempt < 2; ++attempt) { + if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) { + printf("failed seek on %s: %s\n", partition, strerror(errno)); + return -1; + } + while (start < len) { + size_t to_write = len - start; + if (to_write > 1<<20) to_write = 1<<20; + + ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data+start, to_write)); + if (written == -1) { + printf("failed write writing to %s: %s\n", partition, strerror(errno)); + return -1; + } + start += written; + } + if (ota_fsync(fd) != 0) { + printf("failed to sync to %s (%s)\n", partition, strerror(errno)); + return -1; + } + if (ota_close(fd) != 0) { + printf("failed to close %s (%s)\n", partition, strerror(errno)); + return -1; + } + unique_fd fd(ota_open(partition, O_RDONLY)); + if (fd < 0) { + printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno)); + return -1; + } + + // Drop caches so our subsequent verification read + // won't just be reading the cache. + sync(); + unique_fd dc(ota_open("/proc/sys/vm/drop_caches", O_WRONLY)); + if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) { + printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno)); + } else { + printf(" caches dropped\n"); + } + ota_close(dc); + sleep(1); + + // verify + if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) { + printf("failed to seek back to beginning of %s: %s\n", + partition, strerror(errno)); + return -1; + } + unsigned char buffer[4096]; + start = len; + for (size_t p = 0; p < len; p += sizeof(buffer)) { + size_t to_read = len - p; + if (to_read > sizeof(buffer)) { + to_read = sizeof(buffer); + } + + size_t so_far = 0; + while (so_far < to_read) { + ssize_t read_count = + TEMP_FAILURE_RETRY(ota_read(fd, buffer+so_far, to_read-so_far)); + if (read_count == -1) { + printf("verify read error %s at %zu: %s\n", + partition, p, strerror(errno)); + return -1; + } + if (static_cast<size_t>(read_count) < to_read) { + printf("short verify read %s at %zu: %zd %zu %s\n", + partition, p, read_count, to_read, strerror(errno)); + } + so_far += read_count; + } + + if (memcmp(buffer, data+p, to_read) != 0) { + printf("verification failed starting at %zu\n", p); + start = p; + break; + } + } + + if (start == len) { + printf("verification read succeeded (attempt %zu)\n", attempt+1); + success = true; + break; + } + } + + if (!success) { + printf("failed to verify after all attempts\n"); + return -1; + } + + if (ota_close(fd) != 0) { + printf("error closing %s (%s)\n", partition, strerror(errno)); + return -1; + } + sync(); + break; + } } - } - - if (!success) { - printf("failed to verify after all attempts\n"); - return -1; - } - if (ota_close(fd) == -1) { - printf("error closing %s: %s\n", partition, strerror(errno)); - return -1; - } - sync(); - - return 0; + return 0; } // Take a string 'str' of 40 hex digits and parse it into the 20 |