• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  
TargetInfo(std::string hash,RangeSet ranges)36    TargetInfo(std::string hash, RangeSet ranges)
37        : hash_(std::move(hash)), ranges_(std::move(ranges)) {}
38  
hash()39    const std::string& hash() const {
40      return hash_;
41    }
42  
ranges()43    const RangeSet& ranges() const {
44      return ranges_;
45    }
46  
blocks()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  
StashInfo(std::string id,RangeSet ranges)71    StashInfo(std::string id, RangeSet ranges) : id_(std::move(id)), ranges_(std::move(ranges)) {}
72  
blocks()73    size_t blocks() const {
74      return ranges_.blocks();
75    }
76  
id()77    const std::string& id() const {
78      return id_;
79    }
80  
ranges()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  
SourceInfo(std::string hash,RangeSet ranges,RangeSet location,std::vector<StashInfo> stashes)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  
hash()134    const std::string& hash() const {
135      return hash_;
136    }
137  
blocks()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  
PatchInfo(size_t offset,size_t length)170    PatchInfo(size_t offset, size_t length) : offset_(offset), length_(length) {}
171  
offset()172    size_t offset() const {
173      return offset_;
174    }
175  
length()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  
HashTreeInfo(RangeSet hash_tree_ranges,RangeSet source_ranges,std::string hash_algorithm,std::string salt_hex,std::string root_hash)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  
hash_tree_ranges()202    const RangeSet& hash_tree_ranges() const {
203      return hash_tree_ranges_;
204    }
source_ranges()205    const RangeSet& source_ranges() const {
206      return source_ranges_;
207    }
208  
hash_algorithm()209    const std::string& hash_algorithm() const {
210      return hash_algorithm_;
211    }
salt_hex()212    const std::string& salt_hex() const {
213      return salt_hex_;
214    }
root_hash()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  
Command(Type type,size_t index,std::string cmdline,PatchInfo patch,TargetInfo target,SourceInfo source,StashInfo stash)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_(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  
type()325    Type type() const {
326      return type_;
327    }
328  
index()329    size_t index() const {
330      return index_;
331    }
332  
cmdline()333    const std::string& cmdline() const {
334      return cmdline_;
335    }
336  
patch()337    const PatchInfo& patch() const {
338      return patch_;
339    }
340  
target()341    const TargetInfo& target() const {
342      return target_;
343    }
344  
source()345    const SourceInfo& source() const {
346      return source_;
347    }
348  
stash()349    const StashInfo& stash() const {
350      return stash_;
351    }
352  
hash_tree_info()353    const HashTreeInfo& hash_tree_info() const {
354      return hash_tree_info_;
355    }
356  
block_size()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  
version()439    int version() const {
440      return version_;
441    }
442  
total_blocks()443    size_t total_blocks() const {
444      return total_blocks_;
445    }
446  
stash_max_entries()447    size_t stash_max_entries() const {
448      return stash_max_entries_;
449    }
450  
stash_max_blocks()451    size_t stash_max_blocks() const {
452      return stash_max_blocks_;
453    }
454  
commands()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