Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d2aecd46 authored by Tao Bao's avatar Tao Bao
Browse files

updater: Clean up LoadSrcTgtVersion2().

Rename to LoadSourceBlocks() by moving the target blocks parsing part
into the caller. This allows detecting whether the target blocks have
already had the expected data before loading the source blocks. It
doesn't affect anything when applying an update package for the first
time, but it skips loading the unneeded source blocks when resuming an
update. It additionally avoids unnecessarily dumping the "corrupt"
source/stash blocks when resuming an update.

Bug: 33694730
Test: Apply an incremental update with the new updater.
Test: Resume an incremental update with the new updater.
Change-Id: I794fd0d1045be7b3b7f8619285dc0dade01398d0
parent b4c4f8c4
Loading
Loading
Loading
Loading
+143 −146
Original line number Diff line number Diff line
@@ -883,43 +883,36 @@ static void MoveRange(std::vector<uint8_t>& dest, const RangeSet& locs,
    }
}

// Do a source/target load for move/bsdiff/imgdiff in version 2.
// We expect to parse the remainder of the parameter tokens as one of:
//
//    <tgt_range> <src_block_count> <src_range>
//        (loads data from source image only)
//
//    <tgt_range> <src_block_count> - <[stash_id:stash_range] ...>
//        (loads data from stashes only)
//
//    <tgt_range> <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
//        (loads data from both source image and stashes)
//
// On return, params.buffer is filled with the loaded source data (rearranged and combined with
// stashed data as necessary). buffer may be reallocated if needed to accommodate the source data.
// *tgt is the target RangeSet. Any stashes required are loaded using LoadStash.

static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& src_blocks,
/**
 * We expect to parse the remainder of the parameter tokens as one of:
 *
 *    <src_block_count> <src_range>
 *        (loads data from source image only)
 *
 *    <src_block_count> - <[stash_id:stash_range] ...>
 *        (loads data from stashes only)
 *
 *    <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
 *        (loads data from both source image and stashes)
 *
 * On return, params.buffer is filled with the loaded source data (rearranged and combined with
 * stashed data as necessary). buffer may be reallocated if needed to accommodate the source data.
 * tgt is the target RangeSet for detecting overlaps. Any stashes required are loaded using
 * LoadStash.
 */
static int LoadSourceBlocks(CommandParameters& params, const RangeSet& tgt, size_t* src_blocks,
                            bool* overlap) {

    // At least it needs to provide three parameters: <tgt_range>,
    // <src_block_count> and "-"/<src_range>.
    if (params.cpos + 2 >= params.tokens.size()) {
        LOG(ERROR) << "invalid parameters";
        return -1;
    }

    // <tgt_range>
    tgt = parse_range(params.tokens[params.cpos++]);
  CHECK(src_blocks != nullptr);
  CHECK(overlap != nullptr);

  // <src_block_count>
  const std::string& token = params.tokens[params.cpos++];
    if (!android::base::ParseUint(token.c_str(), &src_blocks)) {
  if (!android::base::ParseUint(token, src_blocks)) {
    LOG(ERROR) << "invalid src_block_count \"" << token << "\"";
    return -1;
  }

    allocate(src_blocks * BLOCKSIZE, params.buffer);
  allocate(*src_blocks * BLOCKSIZE, params.buffer);

  // "-" or <src_range> [<src_loc>]
  if (params.tokens[params.cpos] == "-") {
@@ -927,13 +920,9 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t&
    params.cpos++;
  } else {
    RangeSet src = parse_range(params.tokens[params.cpos++]);
        int res = ReadBlocks(src, params.buffer, params.fd);

        if (overlap) {
    *overlap = range_overlaps(src, tgt);
        }

        if (res == -1) {
    if (ReadBlocks(src, params.buffer, params.fd) == -1) {
      return -1;
    }

@@ -948,9 +937,8 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t&

  // <[stash_id:stash_range]>
  while (params.cpos < params.tokens.size()) {
        // Each word is a an index into the stash table, a colon, and
        // then a rangeset describing where in the source block that
        // stashed data should go.
    // Each word is a an index into the stash table, a colon, and then a RangeSet describing where
    // in the source block that stashed data should go.
    std::vector<std::string> tokens = android::base::Split(params.tokens[params.cpos++], ":");
    if (tokens.size() != 2) {
      LOG(ERROR) << "invalid parameter";
@@ -958,9 +946,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t&
    }

    std::vector<uint8_t> stash;
        int res = LoadStash(params, tokens[0], false, nullptr, stash, true);

        if (res == -1) {
    if (LoadStash(params, tokens[0], false, nullptr, stash, true) == -1) {
      // These source blocks will fail verification if used later, but we
      // will let the caller decide if this is a fatal failure
      LOG(ERROR) << "failed to load stash " << tokens[0];
@@ -968,7 +954,6 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t&
    }

    RangeSet locs = parse_range(tokens[1]);

    MoveRange(params.buffer, locs, stash);
  }

@@ -989,9 +974,8 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t&
 *    <tgt_range> <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
 *        (loads data from both source image and stashes)
 *
 * Parameters are the same as for LoadSrcTgtVersion2, except for 'onehash', which tells the function
 * whether to expect separate source and targe block hashes, or if they are both the same and only
 * one hash should be expected, and 'isunresumable', which receives a non-zero value if block
 * 'onehash' tells whether to expect separate source and targe block hashes, or if they are both the
 * same and only one hash should be expected. params.isunresumable will be set to true if block
 * verification fails in a way that the update cannot be resumed anymore.
 *
 * If the function is unable to load the necessary blocks or their contents don't match the hashes,
@@ -1002,8 +986,11 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t&
 *
 * If the return value is 0, source blocks have expected content and the command can be performed.
 */
static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& src_blocks,
                              bool onehash, bool& overlap) {
static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t* src_blocks,
                              bool onehash, bool* overlap) {
  CHECK(src_blocks != nullptr);
  CHECK(overlap != nullptr);

  if (params.cpos >= params.tokens.size()) {
    LOG(ERROR) << "missing source hash";
    return -1;
@@ -1022,36 +1009,46 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t&
    tgthash = params.tokens[params.cpos++];
  }

    if (LoadSrcTgtVersion2(params, tgt, src_blocks, &overlap) == -1) {
  // At least it needs to provide three parameters: <tgt_range>, <src_block_count> and
  // "-"/<src_range>.
  if (params.cpos + 2 >= params.tokens.size()) {
    LOG(ERROR) << "invalid parameters";
    return -1;
  }

    std::vector<uint8_t> tgtbuffer(tgt.size * BLOCKSIZE);
  // <tgt_range>
  tgt = parse_range(params.tokens[params.cpos++]);

  std::vector<uint8_t> tgtbuffer(tgt.size * BLOCKSIZE);
  if (ReadBlocks(tgt, tgtbuffer, params.fd) == -1) {
    return -1;
  }

  // Return now if target blocks already have expected content.
  if (VerifyBlocks(tgthash, tgtbuffer, tgt.size, false) == 0) {
        // Target blocks already have expected content, command should be skipped.
    return 1;
  }

    if (VerifyBlocks(srchash, params.buffer, src_blocks, true) == 0) {
  // Load source blocks.
  if (LoadSourceBlocks(params, tgt, src_blocks, overlap) == -1) {
    return -1;
  }

  if (VerifyBlocks(srchash, params.buffer, *src_blocks, true) == 0) {
    // If source and target blocks overlap, stash the source blocks so we can
    // resume from possible write errors. In verify mode, we can skip stashing
    // because the source blocks won't be overwritten.
        if (overlap && params.canwrite) {
            LOG(INFO) << "stashing " << src_blocks << " overlapping blocks to " << srchash;
    if (*overlap && params.canwrite) {
      LOG(INFO) << "stashing " << *src_blocks << " overlapping blocks to " << srchash;

      bool stash_exists = false;
            if (WriteStash(params.stashbase, srchash, src_blocks, params.buffer, true,
      if (WriteStash(params.stashbase, srchash, *src_blocks, params.buffer, true,
                     &stash_exists) != 0) {
        LOG(ERROR) << "failed to stash overlapping source blocks";
        return -1;
      }

            params.stashed += src_blocks;
      params.stashed += *src_blocks;
      // Can be deleted when the write has completed.
      if (!stash_exists) {
        params.freestash = srchash;
@@ -1062,10 +1059,10 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t&
    return 0;
  }

    if (overlap && LoadStash(params, srchash, true, nullptr, params.buffer, true) == 0) {
        // Overlapping source blocks were previously stashed, command can proceed.
        // We are recovering from an interrupted command, so we don't know if the
        // stash can safely be deleted after this command.
  if (*overlap && LoadStash(params, srchash, true, nullptr, params.buffer, true) == 0) {
    // Overlapping source blocks were previously stashed, command can proceed. We are recovering
    // from an interrupted command, so we don't know if the stash can safely be deleted after this
    // command.
    return 0;
  }

@@ -1082,7 +1079,7 @@ static int PerformCommandMove(CommandParameters& params) {
  size_t blocks = 0;
  bool overlap = false;
  RangeSet tgt;
  int status = LoadSrcTgtVersion3(params, tgt, blocks, true, overlap);
  int status = LoadSrcTgtVersion3(params, tgt, &blocks, true, &overlap);

  if (status == -1) {
    LOG(ERROR) << "failed to read blocks for move";
@@ -1270,13 +1267,13 @@ static int PerformCommandDiff(CommandParameters& params) {
    }

    size_t offset;
    if (!android::base::ParseUint(params.tokens[params.cpos++].c_str(), &offset)) {
    if (!android::base::ParseUint(params.tokens[params.cpos++], &offset)) {
        LOG(ERROR) << "invalid patch offset";
        return -1;
    }

    size_t len;
    if (!android::base::ParseUint(params.tokens[params.cpos++].c_str(), &len)) {
    if (!android::base::ParseUint(params.tokens[params.cpos++], &len)) {
        LOG(ERROR) << "invalid patch len";
        return -1;
    }
@@ -1284,7 +1281,7 @@ static int PerformCommandDiff(CommandParameters& params) {
    RangeSet tgt;
    size_t blocks = 0;
    bool overlap = false;
    int status = LoadSrcTgtVersion3(params, tgt, blocks, false, overlap);
    int status = LoadSrcTgtVersion3(params, tgt, &blocks, false, &overlap);

    if (status == -1) {
        LOG(ERROR) << "failed to read blocks for diff";
@@ -1871,7 +1868,7 @@ Value* BlockImageRecoverFn(const char* name, State* state,
    LOG(INFO) << filename->data << " image corrupted, attempting to recover...";

    // When opened with O_RDWR, libfec rewrites corrupted blocks when they are read
    fec::io fh(filename->data.c_str(), O_RDWR);
    fec::io fh(filename->data, O_RDWR);

    if (!fh) {
        ErrorAbort(state, kLibfecFailure, "fec_open \"%s\" failed: %s", filename->data.c_str(),