diff options
-rw-r--r-- | Android.bp | 2 | ||||
-rw-r--r-- | Android.mk | 2 | ||||
-rw-r--r-- | tests/Android.mk | 10 | ||||
-rw-r--r-- | tests/unit/commands_test.cpp | 20 | ||||
-rw-r--r-- | updater/Android.bp | 71 | ||||
-rw-r--r-- | updater/Android.mk | 35 | ||||
-rw-r--r-- | updater/commands.cpp | 42 | ||||
-rw-r--r-- | updater/include/private/commands.h | 52 |
8 files changed, 194 insertions, 40 deletions
diff --git a/Android.bp b/Android.bp index 177eeb715..1e7f54361 100644 --- a/Android.bp +++ b/Android.bp @@ -108,7 +108,6 @@ cc_defaults { "libbase", "libbootloader_message", "libcrypto", - "libcrypto_utils", "libcutils", "libext4_utils", "libfs_mgr", @@ -119,7 +118,6 @@ cc_defaults { "liblog", "libpng", "libselinux", - "libsparse", "libtinyxml2", "libutils", "libz", diff --git a/Android.mk b/Android.mk index 9888f8616..7d13f4cc4 100644 --- a/Android.mk +++ b/Android.mk @@ -14,7 +14,7 @@ LOCAL_PATH := $(call my-dir) -# Needed by build/make/core/Makefile. +# Needed by build/make/core/Makefile. Must be consistent with the value in Android.bp. RECOVERY_API_VERSION := 3 RECOVERY_FSTAB_VERSION := 2 diff --git a/tests/Android.mk b/tests/Android.mk index 987e372e5..b59da8045 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -127,13 +127,11 @@ tune2fs_static_libraries := \ libupdater_static_libraries := \ libupdater \ libapplypatch \ + libbootloader_message \ libbspatch \ libedify \ - libziparchive \ - libotautil \ - libbootloader_message \ - libutils \ libotafault \ + libotautil \ libext4_utils \ libfec \ libfec_rs \ @@ -144,14 +142,16 @@ libupdater_static_libraries := \ libselinux \ libsparse \ libsquashfs_utils \ + libbrotli \ libbz \ + libziparchive \ libz \ libbase \ libcrypto \ libcrypto_utils \ libcutils \ + libutils \ libtune2fs \ - libbrotli \ $(tune2fs_static_libraries) librecovery_static_libraries := \ diff --git a/tests/unit/commands_test.cpp b/tests/unit/commands_test.cpp index 9679a9e73..19841d676 100644 --- a/tests/unit/commands_test.cpp +++ b/tests/unit/commands_test.cpp @@ -333,6 +333,25 @@ TEST(CommandsTest, Parse_ZERO) { ASSERT_EQ(PatchInfo(), command.patch()); } +TEST(CommandsTest, Parse_COMPUTE_HASH_TREE) { + const std::string input{ "compute_hash_tree 2,0,1 2,3,4 sha1 unknown-salt unknown-root-hash" }; + std::string err; + Command command = Command::Parse(input, 9, &err); + ASSERT_TRUE(command); + + ASSERT_EQ(Command::Type::COMPUTE_HASH_TREE, command.type()); + ASSERT_EQ(9, command.index()); + ASSERT_EQ(input, command.cmdline()); + + HashTreeInfo expected_info(RangeSet({ { 0, 1 } }), RangeSet({ { 3, 4 } }), "sha1", "unknown-salt", + "unknown-root-hash"); + ASSERT_EQ(expected_info, command.hash_tree_info()); + ASSERT_EQ(TargetInfo(), command.target()); + ASSERT_EQ(SourceInfo(), command.source()); + ASSERT_EQ(StashInfo(), command.stash()); + ASSERT_EQ(PatchInfo(), command.patch()); +} + TEST(CommandsTest, Parse_InvalidNumberOfArgs) { Command::abort_allowed_ = true; @@ -341,6 +360,7 @@ TEST(CommandsTest, Parse_InvalidNumberOfArgs) { std::vector<std::string> inputs{ "abort foo", "bsdiff", + "compute_hash_tree, 2,0,1 2,0,1 unknown-algorithm unknown-salt", "erase", "erase 4,3,5,10,12 hash1", "free", diff --git a/updater/Android.bp b/updater/Android.bp new file mode 100644 index 000000000..9a36ebbb7 --- /dev/null +++ b/updater/Android.bp @@ -0,0 +1,71 @@ +// Copyright (C) 2018 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. + +cc_library_static { + name: "libupdater", + + defaults: [ + "recovery_defaults", + ], + + srcs: [ + "blockimg.cpp", + "commands.cpp", + "install.cpp", + ], + + include_dirs: [ + "external/e2fsprogs/misc", + ], + + export_include_dirs: [ + "include", + ], + + static_libs: [ + "libapplypatch", + "libbootloader_message", + "libbspatch", + "libedify", + "libotafault", + "libotautil", + "libext4_utils", + "libfec", + "libfec_rs", + "libverity_tree", + "libfs_mgr", + "libgtest_prod", + "liblog", + "libselinux", + "libsparse", + "libsquashfs_utils", + "libbrotli", + "libbz", + "libziparchive", + "libz", + "libbase", + "libcrypto", + "libcrypto_utils", + "libcutils", + "libutils", + "libtune2fs", + + "libext2_com_err", + "libext2_blkid", + "libext2_quota", + "libext2_uuid", + "libext2_e2p", + "libext2fs", + ], +} diff --git a/updater/Android.mk b/updater/Android.mk index 78d0bd451..5478a7df6 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -25,12 +25,10 @@ tune2fs_static_libraries := \ updater_common_static_libraries := \ libapplypatch \ libbootloader_message \ + libbspatch \ libedify \ libotafault \ libotautil \ - libbspatch \ - libziparchive \ - libutils \ libext4_utils \ libfec \ libfec_rs \ @@ -41,43 +39,18 @@ updater_common_static_libraries := \ libselinux \ libsparse \ libsquashfs_utils \ + libbrotli \ libbz \ + libziparchive \ libz \ libbase \ libcrypto \ libcrypto_utils \ libcutils \ + libutils \ libtune2fs \ - libbrotli \ $(tune2fs_static_libraries) -# libupdater (static library) -# =============================== -include $(CLEAR_VARS) - -LOCAL_MODULE := libupdater - -LOCAL_SRC_FILES := \ - commands.cpp \ - install.cpp \ - blockimg.cpp - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/include \ - external/e2fsprogs/misc - -LOCAL_CFLAGS := \ - -Wall \ - -Werror - -LOCAL_EXPORT_C_INCLUDE_DIRS := \ - $(LOCAL_PATH)/include - -LOCAL_STATIC_LIBRARIES := \ - $(updater_common_static_libraries) - -include $(BUILD_STATIC_LIBRARY) - # updater (static executable) # =============================== include $(CLEAR_VARS) diff --git a/updater/commands.cpp b/updater/commands.cpp index 15a787c51..4a90ea873 100644 --- a/updater/commands.cpp +++ b/updater/commands.cpp @@ -31,6 +31,14 @@ using namespace std::string_literals; bool Command::abort_allowed_ = false; +Command::Command(Type type, size_t index, std::string cmdline, HashTreeInfo hash_tree_info) + : type_(type), + index_(index), + cmdline_(std::move(cmdline)), + hash_tree_info_(std::move(hash_tree_info)) { + CHECK(type == Type::COMPUTE_HASH_TREE); +} + Command::Type Command::ParseType(const std::string& type_str) { if (type_str == "abort") { if (!abort_allowed_) { @@ -177,7 +185,6 @@ Command Command::Parse(const std::string& line, size_t index, std::string* err) SourceInfo source_info; StashInfo stash_info; - // TODO(xunchang) add the parse code of compute_hash_tree if (op == Type::ZERO || op == Type::NEW || op == Type::ERASE) { // zero/new/erase <rangeset> if (pos + 1 != tokens.size()) { @@ -255,6 +262,39 @@ Command Command::Parse(const std::string& line, size_t index, std::string* err) tokens.size() - pos); return {}; } + } else if (op == Type::COMPUTE_HASH_TREE) { + // <hash_tree_ranges> <source_ranges> <hash_algorithm> <salt_hex> <root_hash> + if (pos + 5 != tokens.size()) { + *err = android::base::StringPrintf("invalid number of args: %zu (expected 5)", + tokens.size() - pos); + return {}; + } + + // Expects the hash_tree data to be contiguous. + RangeSet hash_tree_ranges = RangeSet::Parse(tokens[pos++]); + if (!hash_tree_ranges || hash_tree_ranges.size() != 1) { + *err = "invalid hash tree ranges in: " + line; + return {}; + } + + RangeSet source_ranges = RangeSet::Parse(tokens[pos++]); + if (!source_ranges) { + *err = "invalid source ranges in: " + line; + return {}; + } + + std::string hash_algorithm = tokens[pos++]; + std::string salt_hex = tokens[pos++]; + std::string root_hash = tokens[pos++]; + if (hash_algorithm.empty() || salt_hex.empty() || root_hash.empty()) { + *err = "invalid hash tree arguments in " + line; + return {}; + } + + HashTreeInfo hash_tree_info(std::move(hash_tree_ranges), std::move(source_ranges), + std::move(hash_algorithm), std::move(salt_hex), + std::move(root_hash)); + return Command(op, index, line, std::move(hash_tree_info)); } else { *err = "invalid op"; return {}; diff --git a/updater/include/private/commands.h b/updater/include/private/commands.h index 7f9dc79f4..85b52883b 100644 --- a/updater/include/private/commands.h +++ b/updater/include/private/commands.h @@ -166,6 +166,50 @@ class PatchInfo { size_t length_{ 0 }; }; +// The arguments to build a hash tree from blocks on the block device. +class HashTreeInfo { + public: + HashTreeInfo() = default; + + HashTreeInfo(RangeSet hash_tree_ranges, RangeSet source_ranges, std::string hash_algorithm, + std::string salt_hex, std::string root_hash) + : hash_tree_ranges_(std::move(hash_tree_ranges)), + source_ranges_(std::move(source_ranges)), + hash_algorithm_(std::move(hash_algorithm)), + salt_hex_(std::move(salt_hex)), + root_hash_(std::move(root_hash)) {} + + const RangeSet& hash_tree_ranges() const { + return hash_tree_ranges_; + } + const RangeSet& source_ranges() const { + return source_ranges_; + } + + const std::string& hash_algorithm() const { + return hash_algorithm_; + } + const std::string& salt_hex() const { + return salt_hex_; + } + const std::string& root_hash() const { + return root_hash_; + } + + bool operator==(const HashTreeInfo& other) const { + return hash_tree_ranges_ == other.hash_tree_ranges_ && source_ranges_ == other.source_ranges_ && + hash_algorithm_ == other.hash_algorithm_ && salt_hex_ == other.salt_hex_ && + root_hash_ == other.root_hash_; + } + + private: + RangeSet hash_tree_ranges_; + RangeSet source_ranges_; + std::string hash_algorithm_; + std::string salt_hex_; + std::string root_hash_; +}; + // Command class holds the info for an update command that performs block-based OTA (BBOTA). Each // command consists of one or several args, namely TargetInfo, SourceInfo, StashInfo and PatchInfo. // The currently used BBOTA version is v4. @@ -248,6 +292,8 @@ class Command { source_(std::move(source)), stash_(std::move(stash)) {} + Command(Type type, size_t index, std::string cmdline, HashTreeInfo hash_tree_info); + // Parses the given command 'line' into a Command object and returns it. The 'index' is specified // by the caller to index the object. On parsing error, it returns an empty Command object that // evaluates to false, and the specific error message will be set in 'err'. @@ -284,6 +330,10 @@ class Command { return stash_; } + const HashTreeInfo& hash_tree_info() const { + return hash_tree_info_; + } + constexpr explicit operator bool() const { return type_ != Type::LAST; } @@ -325,6 +375,8 @@ class Command { // The stash info. Only meaningful for STASH and FREE commands. Note that although SourceInfo may // also load data from stash, such info will be owned and managed by SourceInfo (i.e. in source_). StashInfo stash_; + // The hash_tree info. Only meaningful for COMPUTE_HASH_TREE. + HashTreeInfo hash_tree_info_; }; std::ostream& operator<<(std::ostream& os, const Command& command); |