Home | History | Annotate | Download | only in private
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #pragma once
     18 
     19 #include <stdint.h>
     20 
     21 #include <functional>
     22 #include <ostream>
     23 #include <string>
     24 #include <vector>
     25 
     26 #include <gtest/gtest_prod.h>  // FRIEND_TEST
     27 
     28 #include "otautil/rangeset.h"
     29 
     30 // Represents the target info used in a Command. TargetInfo contains the ranges of the blocks and
     31 // the expected hash.
     32 class TargetInfo {
     33  public:
     34   TargetInfo() = default;
     35 
     36   TargetInfo(std::string hash, RangeSet ranges)
     37       : hash_(std::move(hash)), ranges_(std::move(ranges)) {}
     38 
     39   const std::string& hash() const {
     40     return hash_;
     41   }
     42 
     43   const RangeSet& ranges() const {
     44     return ranges_;
     45   }
     46 
     47   size_t blocks() const {
     48     return ranges_.blocks();
     49   }
     50 
     51   bool operator==(const TargetInfo& other) const {
     52     return hash_ == other.hash_ && ranges_ == other.ranges_;
     53   }
     54 
     55  private:
     56   friend std::ostream& operator<<(std::ostream& os, const TargetInfo& source);
     57 
     58   // The hash of the data represented by the object.
     59   std::string hash_;
     60   // The block ranges that the data should be written to.
     61   RangeSet ranges_;
     62 };
     63 
     64 std::ostream& operator<<(std::ostream& os, const TargetInfo& source);
     65 
     66 // Represents the stash info used in a Command.
     67 class StashInfo {
     68  public:
     69   StashInfo() = default;
     70 
     71   StashInfo(std::string id, RangeSet ranges) : id_(std::move(id)), ranges_(std::move(ranges)) {}
     72 
     73   size_t blocks() const {
     74     return ranges_.blocks();
     75   }
     76 
     77   const std::string& id() const {
     78     return id_;
     79   }
     80 
     81   const RangeSet& ranges() const {
     82     return ranges_;
     83   }
     84 
     85   bool operator==(const StashInfo& other) const {
     86     return id_ == other.id_ && ranges_ == other.ranges_;
     87   }
     88 
     89  private:
     90   friend std::ostream& operator<<(std::ostream& os, const StashInfo& stash);
     91 
     92   // The id (i.e. hash) of the stash.
     93   std::string id_;
     94   // The matching location of the stash.
     95   RangeSet ranges_;
     96 };
     97 
     98 std::ostream& operator<<(std::ostream& os, const StashInfo& stash);
     99 
    100 // Represents the source info in a Command, whose data could come from source image, stashed blocks,
    101 // or both.
    102 class SourceInfo {
    103  public:
    104   SourceInfo() = default;
    105 
    106   SourceInfo(std::string hash, RangeSet ranges, RangeSet location, std::vector<StashInfo> stashes)
    107       : hash_(std::move(hash)),
    108         ranges_(std::move(ranges)),
    109         location_(std::move(location)),
    110         stashes_(std::move(stashes)) {
    111     blocks_ = ranges_.blocks();
    112     for (const auto& stash : stashes_) {
    113       blocks_ += stash.ranges().blocks();
    114     }
    115   }
    116 
    117   // Reads all the data specified by this SourceInfo object into the given 'buffer', by calling the
    118   // given readers. Caller needs to specify the block size for the represented blocks. The given
    119   // buffer needs to be sufficiently large. Otherwise it returns false. 'block_reader' and
    120   // 'stash_reader' read the specified data into the given buffer (guaranteed to be large enough)
    121   // respectively. The readers should return 0 on success, or -1 on error.
    122   bool ReadAll(
    123       std::vector<uint8_t>* buffer, size_t block_size,
    124       const std::function<int(const RangeSet&, std::vector<uint8_t>*)>& block_reader,
    125       const std::function<int(const std::string&, std::vector<uint8_t>*)>& stash_reader) const;
    126 
    127   // Whether this SourceInfo overlaps with the given TargetInfo object.
    128   bool Overlaps(const TargetInfo& target) const;
    129 
    130   // Dumps the hashes in hex for the given buffer that's loaded from this SourceInfo object
    131   // (excluding the stashed blocks which are handled separately).
    132   void DumpBuffer(const std::vector<uint8_t>& buffer, size_t block_size) const;
    133 
    134   const std::string& hash() const {
    135     return hash_;
    136   }
    137 
    138   size_t blocks() const {
    139     return blocks_;
    140   }
    141 
    142   bool operator==(const SourceInfo& other) const {
    143     return hash_ == other.hash_ && ranges_ == other.ranges_ && location_ == other.location_ &&
    144            stashes_ == other.stashes_;
    145   }
    146 
    147  private:
    148   friend std::ostream& operator<<(std::ostream& os, const SourceInfo& source);
    149 
    150   // The hash of the data represented by the object.
    151   std::string hash_;
    152   // The block ranges from the source image to read data from. This could be a subset of all the
    153   // blocks represented by the object, or empty if all the data should be loaded from stash.
    154   RangeSet ranges_;
    155   // The location in the buffer to load ranges_ into. Empty if ranges_ alone covers all the blocks
    156   // (i.e. nothing needs to be loaded from stash).
    157   RangeSet location_;
    158   // The info for the stashed blocks that are part of the source. Empty if there's none.
    159   std::vector<StashInfo> stashes_;
    160   // Total number of blocks represented by the object.
    161   size_t blocks_{ 0 };
    162 };
    163 
    164 std::ostream& operator<<(std::ostream& os, const SourceInfo& source);
    165 
    166 class PatchInfo {
    167  public:
    168   PatchInfo() = default;
    169 
    170   PatchInfo(size_t offset, size_t length) : offset_(offset), length_(length) {}
    171 
    172   size_t offset() const {
    173     return offset_;
    174   }
    175 
    176   size_t length() const {
    177     return length_;
    178   }
    179 
    180   bool operator==(const PatchInfo& other) const {
    181     return offset_ == other.offset_ && length_ == other.length_;
    182   }
    183 
    184  private:
    185   size_t offset_{ 0 };
    186   size_t length_{ 0 };
    187 };
    188 
    189 // The arguments to build a hash tree from blocks on the block device.
    190 class HashTreeInfo {
    191  public:
    192   HashTreeInfo() = default;
    193 
    194   HashTreeInfo(RangeSet hash_tree_ranges, RangeSet source_ranges, std::string hash_algorithm,
    195                std::string salt_hex, std::string root_hash)
    196       : hash_tree_ranges_(std::move(hash_tree_ranges)),
    197         source_ranges_(std::move(source_ranges)),
    198         hash_algorithm_(std::move(hash_algorithm)),
    199         salt_hex_(std::move(salt_hex)),
    200         root_hash_(std::move(root_hash)) {}
    201 
    202   const RangeSet& hash_tree_ranges() const {
    203     return hash_tree_ranges_;
    204   }
    205   const RangeSet& source_ranges() const {
    206     return source_ranges_;
    207   }
    208 
    209   const std::string& hash_algorithm() const {
    210     return hash_algorithm_;
    211   }
    212   const std::string& salt_hex() const {
    213     return salt_hex_;
    214   }
    215   const std::string& root_hash() const {
    216     return root_hash_;
    217   }
    218 
    219   bool operator==(const HashTreeInfo& other) const {
    220     return hash_tree_ranges_ == other.hash_tree_ranges_ && source_ranges_ == other.source_ranges_ &&
    221            hash_algorithm_ == other.hash_algorithm_ && salt_hex_ == other.salt_hex_ &&
    222            root_hash_ == other.root_hash_;
    223   }
    224 
    225  private:
    226   RangeSet hash_tree_ranges_;
    227   RangeSet source_ranges_;
    228   std::string hash_algorithm_;
    229   std::string salt_hex_;
    230   std::string root_hash_;
    231 };
    232 
    233 // Command class holds the info for an update command that performs block-based OTA (BBOTA). Each
    234 // command consists of one or several args, namely TargetInfo, SourceInfo, StashInfo and PatchInfo.
    235 // The currently used BBOTA version is v4.
    236 //
    237 //    zero <tgt_ranges>
    238 //      - Fill the indicated blocks with zeros.
    239 //      - Meaningful args: TargetInfo
    240 //
    241 //    new <tgt_ranges>
    242 //      - Fill the blocks with data read from the new_data file.
    243 //      - Meaningful args: TargetInfo
    244 //
    245 //    erase <tgt_ranges>
    246 //      - Mark the given blocks as empty.
    247 //      - Meaningful args: TargetInfo
    248 //
    249 //    move <hash> <...>
    250 //      - Read the source blocks, write result to target blocks.
    251 //      - Meaningful args: TargetInfo, SourceInfo
    252 //
    253 //      See the note below for <...>.
    254 //
    255 //    bsdiff <patchstart> <patchlen> <srchash> <dsthash> <...>
    256 //    imgdiff <patchstart> <patchlen> <srchash> <dsthash> <...>
    257 //      - Read the source blocks, apply a patch, and write result to target blocks.
    258 //      - Meaningful args: PatchInfo, TargetInfo, SourceInfo
    259 //
    260 //      It expects <...> in one of the following formats:
    261 //
    262 //        <tgt_ranges> <src_block_count> - <[stash_id:stash_location] ...>
    263 //          (loads data from stashes only)
    264 //
    265 //        <tgt_ranges> <src_block_count> <src_ranges>
    266 //          (loads data from source image only)
    267 //
    268 //        <tgt_ranges> <src_block_count> <src_ranges> <src_ranges_location>
    269 //                                       <[stash_id:stash_location] ...>
    270 //          (loads data from both of source image and stashes)
    271 //
    272 //    stash <stash_id> <src_ranges>
    273 //      - Load the given source blocks and stash the data in the given slot of the stash table.
    274 //      - Meaningful args: StashInfo
    275 //
    276 //    free <stash_id>
    277 //      - Free the given stash data.
    278 //      - Meaningful args: StashInfo
    279 //
    280 //    compute_hash_tree <hash_tree_ranges> <source_ranges> <hash_algorithm> <salt_hex> <root_hash>
    281 //      - Computes the hash_tree bytes and writes the result to the specified range on the
    282 //        block_device.
    283 //
    284 //    abort
    285 //      - Abort the current update. Allowed for testing code only.
    286 //
    287 class Command {
    288  public:
    289   enum class Type {
    290     ABORT,
    291     BSDIFF,
    292     COMPUTE_HASH_TREE,
    293     ERASE,
    294     FREE,
    295     IMGDIFF,
    296     MOVE,
    297     NEW,
    298     STASH,
    299     ZERO,
    300     LAST,  // Not a valid type.
    301   };
    302 
    303   Command() = default;
    304 
    305   Command(Type type, size_t index, std::string cmdline, PatchInfo patch, TargetInfo target,
    306           SourceInfo source, StashInfo stash)
    307       : type_(type),
    308         index_(index),
    309         cmdline_(std::move(cmdline)),
    310         patch_(std::move(patch)),
    311         target_(std::move(target)),
    312         source_(std::move(source)),
    313         stash_(std::move(stash)) {}
    314 
    315   Command(Type type, size_t index, std::string cmdline, HashTreeInfo hash_tree_info);
    316 
    317   // Parses the given command 'line' into a Command object and returns it. The 'index' is specified
    318   // by the caller to index the object. On parsing error, it returns an empty Command object that
    319   // evaluates to false, and the specific error message will be set in 'err'.
    320   static Command Parse(const std::string& line, size_t index, std::string* err);
    321 
    322   // Parses the command type from the given string.
    323   static Type ParseType(const std::string& type_str);
    324 
    325   Type type() const {
    326     return type_;
    327   }
    328 
    329   size_t index() const {
    330     return index_;
    331   }
    332 
    333   const std::string& cmdline() const {
    334     return cmdline_;
    335   }
    336 
    337   const PatchInfo& patch() const {
    338     return patch_;
    339   }
    340 
    341   const TargetInfo& target() const {
    342     return target_;
    343   }
    344 
    345   const SourceInfo& source() const {
    346     return source_;
    347   }
    348 
    349   const StashInfo& stash() const {
    350     return stash_;
    351   }
    352 
    353   const HashTreeInfo& hash_tree_info() const {
    354     return hash_tree_info_;
    355   }
    356 
    357   size_t block_size() const {
    358     return block_size_;
    359   }
    360 
    361   constexpr explicit operator bool() const {
    362     return type_ != Type::LAST;
    363   }
    364 
    365  private:
    366   friend class ResumableUpdaterTest;
    367   friend class UpdaterTest;
    368 
    369   FRIEND_TEST(CommandsTest, Parse_ABORT_Allowed);
    370   FRIEND_TEST(CommandsTest, Parse_InvalidNumberOfArgs);
    371   FRIEND_TEST(CommandsTest, ParseTargetInfoAndSourceInfo_InvalidInput);
    372   FRIEND_TEST(CommandsTest, ParseTargetInfoAndSourceInfo_StashesOnly);
    373   FRIEND_TEST(CommandsTest, ParseTargetInfoAndSourceInfo_SourceBlocksAndStashes);
    374   FRIEND_TEST(CommandsTest, ParseTargetInfoAndSourceInfo_SourceBlocksOnly);
    375 
    376   // Parses the target and source info from the given 'tokens' vector. Saves the parsed info into
    377   // 'target' and 'source' objects. Returns the parsing result. Error message will be set in 'err'
    378   // on parsing error, and the contents in 'target' and 'source' will be undefined.
    379   static bool ParseTargetInfoAndSourceInfo(const std::vector<std::string>& tokens,
    380                                            const std::string& tgt_hash, TargetInfo* target,
    381                                            const std::string& src_hash, SourceInfo* source,
    382                                            std::string* err);
    383 
    384   // Allows parsing ABORT command, which should be used for testing purpose only.
    385   static bool abort_allowed_;
    386 
    387   // The type of the command.
    388   Type type_{ Type::LAST };
    389   // The index of the Command object, which is specified by the caller.
    390   size_t index_{ 0 };
    391   // The input string that the Command object is parsed from.
    392   std::string cmdline_;
    393   // The patch info. Only meaningful for BSDIFF and IMGDIFF commands.
    394   PatchInfo patch_;
    395   // The target info, where the command should be written to.
    396   TargetInfo target_;
    397   // The source info to load the source blocks for the command.
    398   SourceInfo source_;
    399   // The stash info. Only meaningful for STASH and FREE commands. Note that although SourceInfo may
    400   // also load data from stash, such info will be owned and managed by SourceInfo (i.e. in source_).
    401   StashInfo stash_;
    402   // The hash_tree info. Only meaningful for COMPUTE_HASH_TREE.
    403   HashTreeInfo hash_tree_info_;
    404   // The unit size of each block to be used in this command.
    405   size_t block_size_{ 4096 };
    406 };
    407 
    408 std::ostream& operator<<(std::ostream& os, const Command& command);
    409 
    410 // TransferList represents the info for a transfer list, which is parsed from input text lines
    411 // containing commands to transfer data from one place to another on the target partition.
    412 //
    413 // The creator of the transfer list will guarantee that no block is read (i.e., used as the source
    414 // for a patch or move) after it has been written.
    415 //
    416 // The creator will guarantee that a given stash is loaded (with a stash command) before it's used
    417 // in a move/bsdiff/imgdiff command.
    418 //
    419 // Within one command the source and target ranges may overlap so in general we need to read the
    420 // entire source into memory before writing anything to the target blocks.
    421 //
    422 // All the patch data is concatenated into one patch_data file in the update package. It must be
    423 // stored uncompressed because we memory-map it in directly from the archive. (Since patches are
    424 // already compressed, we lose very little by not compressing their concatenation.)
    425 //
    426 // Commands that read data from the partition (i.e. move/bsdiff/imgdiff/stash) have one or more
    427 // additional hashes before the range parameters, which are used to check if the command has
    428 // already been completed and verify the integrity of the source data.
    429 class TransferList {
    430  public:
    431   // Number of header lines.
    432   static constexpr size_t kTransferListHeaderLines = 4;
    433 
    434   TransferList() = default;
    435 
    436   // Parses the given input string and returns a TransferList object. Sets error message if any.
    437   static TransferList Parse(const std::string& transfer_list_str, std::string* err);
    438 
    439   int version() const {
    440     return version_;
    441   }
    442 
    443   size_t total_blocks() const {
    444     return total_blocks_;
    445   }
    446 
    447   size_t stash_max_entries() const {
    448     return stash_max_entries_;
    449   }
    450 
    451   size_t stash_max_blocks() const {
    452     return stash_max_blocks_;
    453   }
    454 
    455   const std::vector<Command>& commands() const {
    456     return commands_;
    457   }
    458 
    459   // Returns whether the TransferList is valid.
    460   constexpr explicit operator bool() const {
    461     return version_ != 0;
    462   }
    463 
    464  private:
    465   // BBOTA version.
    466   int version_{ 0 };
    467   // Total number of blocks to be written in this transfer.
    468   size_t total_blocks_;
    469   // Maximum number of stashes that exist at the same time.
    470   size_t stash_max_entries_;
    471   // Maximum number of blocks to be stashed.
    472   size_t stash_max_blocks_;
    473   // Commands in this transfer.
    474   std::vector<Command> commands_;
    475 };
    476