diff options
Diffstat (limited to 'updater/include/private/commands.h')
-rw-r--r-- | updater/include/private/commands.h | 290 |
1 files changed, 284 insertions, 6 deletions
diff --git a/updater/include/private/commands.h b/updater/include/private/commands.h index b36000072..784892fb5 100644 --- a/updater/include/private/commands.h +++ b/updater/include/private/commands.h @@ -16,20 +16,298 @@ #pragma once +#include <ostream> #include <string> +#include <vector> -struct Command { +#include <gtest/gtest_prod.h> // FRIEND_TEST + +#include "otautil/rangeset.h" + +// Represents the target info used in a Command. TargetInfo contains the ranges of the blocks and +// the expected hash. +class TargetInfo { + public: + TargetInfo() = default; + + TargetInfo(std::string hash, RangeSet ranges) + : hash_(std::move(hash)), ranges_(std::move(ranges)) {} + + const std::string& hash() const { + return hash_; + } + + const RangeSet& ranges() const { + return ranges_; + } + + size_t blocks() const { + return ranges_.blocks(); + } + + bool operator==(const TargetInfo& other) const { + return hash_ == other.hash_ && ranges_ == other.ranges_; + } + + private: + friend std::ostream& operator<<(std::ostream& os, const TargetInfo& source); + + // The hash of the data represented by the object. + std::string hash_; + // The block ranges that the data should be written to. + RangeSet ranges_; +}; + +std::ostream& operator<<(std::ostream& os, const TargetInfo& source); + +// Represents the stash info used in a Command. +class StashInfo { + public: + StashInfo() = default; + + StashInfo(std::string id, RangeSet ranges) : id_(std::move(id)), ranges_(std::move(ranges)) {} + + size_t blocks() const { + return ranges_.blocks(); + } + + const std::string& id() const { + return id_; + } + + const RangeSet& ranges() const { + return ranges_; + } + + bool operator==(const StashInfo& other) const { + return id_ == other.id_ && ranges_ == other.ranges_; + } + + private: + friend std::ostream& operator<<(std::ostream& os, const StashInfo& stash); + + // The id (i.e. hash) of the stash. + std::string id_; + // The matching location of the stash. + RangeSet ranges_; +}; + +std::ostream& operator<<(std::ostream& os, const StashInfo& stash); + +// Represents the source info in a Command, whose data could come from source image, stashed blocks, +// or both. +class SourceInfo { + public: + SourceInfo() = default; + + SourceInfo(std::string hash, RangeSet ranges, RangeSet location, std::vector<StashInfo> stashes) + : hash_(std::move(hash)), + ranges_(std::move(ranges)), + location_(std::move(location)), + stashes_(std::move(stashes)) { + blocks_ = ranges_.blocks(); + for (const auto& stash : stashes_) { + blocks_ += stash.ranges().blocks(); + } + } + + const std::string& hash() const { + return hash_; + } + + size_t blocks() const { + return blocks_; + } + + bool operator==(const SourceInfo& other) const { + return hash_ == other.hash_ && ranges_ == other.ranges_ && location_ == other.location_ && + stashes_ == other.stashes_; + } + + private: + friend std::ostream& operator<<(std::ostream& os, const SourceInfo& source); + + // The hash of the data represented by the object. + std::string hash_; + // The block ranges from the source image to read data from. This could be a subset of all the + // blocks represented by the object, or empty if all the data should be loaded from stash. + RangeSet ranges_; + // The location in the buffer to load ranges_ into. Empty if ranges_ alone covers all the blocks + // (i.e. nothing needs to be loaded from stash). + RangeSet location_; + // The info for the stashed blocks that are part of the source. Empty if there's none. + std::vector<StashInfo> stashes_; + // Total number of blocks represented by the object. + size_t blocks_{ 0 }; +}; + +std::ostream& operator<<(std::ostream& os, const SourceInfo& source); + +class PatchInfo { + public: + PatchInfo() = default; + + PatchInfo(size_t offset, size_t length) : offset_(offset), length_(length) {} + + size_t offset() const { + return offset_; + } + + size_t length() const { + return length_; + } + + bool operator==(const PatchInfo& other) const { + return offset_ == other.offset_ && length_ == other.length_; + } + + private: + size_t offset_{ 0 }; + size_t length_{ 0 }; +}; + +// 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. +// +// zero <tgt_ranges> +// - Fill the indicated blocks with zeros. +// - Meaningful args: TargetInfo +// +// new <tgt_ranges> +// - Fill the blocks with data read from the new_data file. +// - Meaningful args: TargetInfo +// +// erase <tgt_ranges> +// - Mark the given blocks as empty. +// - Meaningful args: TargetInfo +// +// move <hash> <...> +// - Read the source blocks, write result to target blocks. +// - Meaningful args: TargetInfo, SourceInfo +// +// See the note below for <...>. +// +// bsdiff <patchstart> <patchlen> <srchash> <dsthash> <...> +// imgdiff <patchstart> <patchlen> <srchash> <dsthash> <...> +// - Read the source blocks, apply a patch, and write result to target blocks. +// - Meaningful args: PatchInfo, TargetInfo, SourceInfo +// +// It expects <...> in one of the following formats: +// +// <tgt_ranges> <src_block_count> - <[stash_id:stash_location] ...> +// (loads data from stashes only) +// +// <tgt_ranges> <src_block_count> <src_ranges> +// (loads data from source image only) +// +// <tgt_ranges> <src_block_count> <src_ranges> <src_ranges_location> +// <[stash_id:stash_location] ...> +// (loads data from both of source image and stashes) +// +// stash <stash_id> <src_ranges> +// - Load the given source blocks and stash the data in the given slot of the stash table. +// - Meaningful args: StashInfo +// +// free <stash_id> +// - Free the given stash data. +// - Meaningful args: StashInfo +// +class Command { + public: enum class Type { - ZERO, - NEW, - ERASE, - MOVE, BSDIFF, + ERASE, + FREE, IMGDIFF, + MOVE, + NEW, STASH, - FREE, + ZERO, LAST, // Not a valid type. }; + Command() = default; + + Command(Type type, size_t index, std::string cmdline, PatchInfo patch, TargetInfo target, + SourceInfo source, StashInfo stash) + : type_(type), + index_(index), + cmdline_(std::move(cmdline)), + patch_(std::move(patch)), + target_(std::move(target)), + source_(std::move(source)), + stash_(std::move(stash)) {} + + // 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'. + static Command Parse(const std::string& line, size_t index, std::string* err); + + // Parses the command type from the given string. static Type ParseType(const std::string& type_str); + + Type type() const { + return type_; + } + + size_t index() const { + return index_; + } + + const std::string& cmdline() const { + return cmdline_; + } + + const PatchInfo& patch() const { + return patch_; + } + + const TargetInfo& target() const { + return target_; + } + + const SourceInfo& source() const { + return source_; + } + + const StashInfo& stash() const { + return stash_; + } + + constexpr explicit operator bool() const { + return type_ != Type::LAST; + } + + private: + FRIEND_TEST(CommandsTest, ParseTargetInfoAndSourceInfo_InvalidInput); + FRIEND_TEST(CommandsTest, ParseTargetInfoAndSourceInfo_StashesOnly); + FRIEND_TEST(CommandsTest, ParseTargetInfoAndSourceInfo_SourceBlocksAndStashes); + FRIEND_TEST(CommandsTest, ParseTargetInfoAndSourceInfo_SourceBlocksOnly); + + // Parses the target and source info from the given 'tokens' vector. Saves the parsed info into + // 'target' and 'source' objects. Returns the parsing result. Error message will be set in 'err' + // on parsing error, and the contents in 'target' and 'source' will be undefined. + static bool ParseTargetInfoAndSourceInfo(const std::vector<std::string>& tokens, + const std::string& tgt_hash, TargetInfo* target, + const std::string& src_hash, SourceInfo* source, + std::string* err); + + // The type of the command. + Type type_{ Type::LAST }; + // The index of the Command object, which is specified by the caller. + size_t index_{ 0 }; + // The input string that the Command object is parsed from. + std::string cmdline_; + // The patch info. Only meaningful for BSDIFF and IMGDIFF commands. + PatchInfo patch_; + // The target info, where the command should be written to. + TargetInfo target_; + // The source info to load the source blocks for the command. + SourceInfo source_; + // 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_; }; + +std::ostream& operator<<(std::ostream& os, const Command& command); |