blob: 7a23bb78b693eeb2296a97fbec8b482853ef7095 [file] [log] [blame]
Tao Baoc3901232018-05-21 16:05:56 -07001/*
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
Tao Bao3c892732018-06-18 09:44:33 -070019#include <stdint.h>
20
21#include <functional>
Tao Bao6a7e4af2018-06-14 21:57:43 -070022#include <ostream>
Tao Baoc3901232018-05-21 16:05:56 -070023#include <string>
Tao Bao6a7e4af2018-06-14 21:57:43 -070024#include <vector>
Tao Baoc3901232018-05-21 16:05:56 -070025
Tao Bao6a7e4af2018-06-14 21:57:43 -070026#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.
32class 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
64std::ostream& operator<<(std::ostream& os, const TargetInfo& source);
65
66// Represents the stash info used in a Command.
67class 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
98std::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.
102class 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
Tao Bao3c892732018-06-18 09:44:33 -0700117 // 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
Tao Bao6a7e4af2018-06-14 21:57:43 -0700134 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
164std::ostream& operator<<(std::ostream& os, const SourceInfo& source);
165
166class 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
Tianjie Xu8f64bf62018-08-07 00:22:19 -0700189// The arguments to build a hash tree from blocks on the block device.
190class 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
Tao Bao6a7e4af2018-06-14 21:57:43 -0700233// 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//
Tianjie Xu69ffa152018-08-01 16:40:00 -0700280// 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//
Tao Bao91a649a2018-05-21 16:05:56 -0700284// abort
285// - Abort the current update. Allowed for testing code only.
286//
Tao Bao6a7e4af2018-06-14 21:57:43 -0700287class Command {
288 public:
Tao Baoc3901232018-05-21 16:05:56 -0700289 enum class Type {
Tao Bao91a649a2018-05-21 16:05:56 -0700290 ABORT,
Tao Baoc3901232018-05-21 16:05:56 -0700291 BSDIFF,
Tianjie Xu69ffa152018-08-01 16:40:00 -0700292 COMPUTE_HASH_TREE,
Tao Bao6a7e4af2018-06-14 21:57:43 -0700293 ERASE,
Tao Baoc3901232018-05-21 16:05:56 -0700294 FREE,
Tao Bao6a7e4af2018-06-14 21:57:43 -0700295 IMGDIFF,
296 MOVE,
297 NEW,
298 STASH,
299 ZERO,
Tao Baoc3901232018-05-21 16:05:56 -0700300 LAST, // Not a valid type.
301 };
302
Tao Bao6a7e4af2018-06-14 21:57:43 -0700303 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)),
Tianjie Xufb08b012020-03-07 17:22:40 -0800310 patch_(patch),
Tao Bao6a7e4af2018-06-14 21:57:43 -0700311 target_(std::move(target)),
312 source_(std::move(source)),
313 stash_(std::move(stash)) {}
314
Tianjie Xu8f64bf62018-08-07 00:22:19 -0700315 Command(Type type, size_t index, std::string cmdline, HashTreeInfo hash_tree_info);
316
Tao Bao6a7e4af2018-06-14 21:57:43 -0700317 // 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.
Tao Baoc3901232018-05-21 16:05:56 -0700323 static Type ParseType(const std::string& type_str);
Tao Bao6a7e4af2018-06-14 21:57:43 -0700324
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
Tianjie Xu8f64bf62018-08-07 00:22:19 -0700353 const HashTreeInfo& hash_tree_info() const {
354 return hash_tree_info_;
355 }
356
Tao Bao3c892732018-06-18 09:44:33 -0700357 size_t block_size() const {
358 return block_size_;
359 }
360
Tao Bao6a7e4af2018-06-14 21:57:43 -0700361 constexpr explicit operator bool() const {
362 return type_ != Type::LAST;
363 }
364
365 private:
Tao Bao91a649a2018-05-21 16:05:56 -0700366 friend class ResumableUpdaterTest;
367 friend class UpdaterTest;
368
369 FRIEND_TEST(CommandsTest, Parse_ABORT_Allowed);
370 FRIEND_TEST(CommandsTest, Parse_InvalidNumberOfArgs);
Tao Bao6a7e4af2018-06-14 21:57:43 -0700371 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
Tao Bao91a649a2018-05-21 16:05:56 -0700384 // Allows parsing ABORT command, which should be used for testing purpose only.
385 static bool abort_allowed_;
386
Tao Bao6a7e4af2018-06-14 21:57:43 -0700387 // 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_;
Tianjie Xu8f64bf62018-08-07 00:22:19 -0700402 // The hash_tree info. Only meaningful for COMPUTE_HASH_TREE.
403 HashTreeInfo hash_tree_info_;
Tao Bao3c892732018-06-18 09:44:33 -0700404 // The unit size of each block to be used in this command.
405 size_t block_size_{ 4096 };
Tao Baoc3901232018-05-21 16:05:56 -0700406};
Tao Bao6a7e4af2018-06-14 21:57:43 -0700407
408std::ostream& operator<<(std::ostream& os, const Command& command);
Tao Baof8811bb2018-06-18 10:03:52 -0700409
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.
429class 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};