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