From 4d9e62d8a07b233da4d82a42eb30de64cf2b45bd Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Fri, 11 May 2018 10:41:44 -0700 Subject: Add proto3 support for care_map Switching to the protobuf format helps to make the care_map more extensible. As we have such plans in the future, add the support to parse the protobuf message in the update_verifier. Bug: 77867897 Test: unit tests pass, update_verifier successfully verifies a care_map.pb Change-Id: I9fe83cb4dd3cc8d6fd0260f2a47338fe142d3938 --- update_verifier/update_verifier.cpp | 72 ++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 24 deletions(-) (limited to 'update_verifier/update_verifier.cpp') diff --git a/update_verifier/update_verifier.cpp b/update_verifier/update_verifier.cpp index dc7276326..5e5aa1819 100644 --- a/update_verifier/update_verifier.cpp +++ b/update_verifier/update_verifier.cpp @@ -60,6 +60,7 @@ #include #include +#include "care_map.pb.h" #include "otautil/rangeset.h" using android::sp; @@ -189,33 +190,12 @@ static bool read_blocks(const std::string& partition, const std::string& range_s return ret; } -// Returns true to indicate a passing verification (or the error should be ignored); Otherwise -// returns false on fatal errors, where we should reject the current boot and trigger a fallback. -// Note that update_verifier should be backward compatible to not reject care_map.txt from old -// releases, which could otherwise fail to boot into the new release. For example, we've changed -// the care_map format between N and O. An O update_verifier would fail to work with N -// care_map.txt. This could be a result of sideloading an O OTA while the device having a pending N -// update. -bool verify_image(const std::string& care_map_name) { - android::base::unique_fd care_map_fd(TEMP_FAILURE_RETRY(open(care_map_name.c_str(), O_RDONLY))); - // If the device is flashed before the current boot, it may not have care_map.txt - // in /data/ota_package. To allow the device to continue booting in this situation, - // we should print a warning and skip the block verification. - if (care_map_fd.get() == -1) { - PLOG(WARNING) << "Failed to open " << care_map_name; - return true; - } +static bool process_care_map_plain_text(const std::string& care_map_contents) { // care_map file has up to six lines, where every two lines make a pair. Within each pair, the // first line has the partition name (e.g. "system"), while the second line holds the ranges of // all the blocks to verify. - std::string file_content; - if (!android::base::ReadFdToString(care_map_fd.get(), &file_content)) { - LOG(ERROR) << "Error reading care map contents to string."; - return false; - } - - std::vector lines; - lines = android::base::Split(android::base::Trim(file_content), "\n"); + std::vector lines = + android::base::Split(android::base::Trim(care_map_contents), "\n"); if (lines.size() != 2 && lines.size() != 4 && lines.size() != 6) { LOG(ERROR) << "Invalid lines in care_map: found " << lines.size() << " lines, expecting 2 or 4 or 6 lines."; @@ -237,6 +217,50 @@ bool verify_image(const std::string& care_map_name) { return true; } +bool verify_image(const std::string& care_map_name) { + android::base::unique_fd care_map_fd(TEMP_FAILURE_RETRY(open(care_map_name.c_str(), O_RDONLY))); + // If the device is flashed before the current boot, it may not have care_map.txt in + // /data/ota_package. To allow the device to continue booting in this situation, we should + // print a warning and skip the block verification. + if (care_map_fd.get() == -1) { + PLOG(WARNING) << "Failed to open " << care_map_name; + return true; + } + + std::string file_content; + if (!android::base::ReadFdToString(care_map_fd.get(), &file_content)) { + PLOG(ERROR) << "Failed to read " << care_map_name; + return false; + } + + if (file_content.empty()) { + LOG(ERROR) << "Unexpected empty care map"; + return false; + } + + UpdateVerifier::CareMap care_map; + // Falls back to use the plain text version if we cannot parse the file as protobuf message. + if (!care_map.ParseFromString(file_content)) { + return process_care_map_plain_text(file_content); + } + + for (const auto& partition : care_map.partitions()) { + if (partition.name().empty()) { + LOG(ERROR) << "Unexpected empty partition name."; + return false; + } + if (partition.ranges().empty()) { + LOG(ERROR) << "Unexpected block ranges for partition " << partition.name(); + return false; + } + if (!read_blocks(partition.name(), partition.ranges())) { + return false; + } + } + + return true; +} + static int reboot_device() { if (android_reboot(ANDROID_RB_RESTART2, 0, nullptr) == -1) { LOG(ERROR) << "Failed to reboot."; -- cgit v1.2.3