1aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
2aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Copyright (C) 2015 The Android Open Source Project
3aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
4aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Licensed under the Apache License, Version 2.0 (the "License");
5aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// you may not use this file except in compliance with the License.
6aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// You may obtain a copy of the License at
7aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
8aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//      http://www.apache.org/licenses/LICENSE-2.0
9aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
10aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Unless required by applicable law or agreed to in writing, software
11aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// distributed under the License is distributed on an "AS IS" BASIS,
12aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// See the License for the specific language governing permissions and
14aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// limitations under the License.
15aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
1614158570d3995008dc93a628004118b87a6bca01Alex Deymo
1714158570d3995008dc93a628004118b87a6bca01Alex Deymo#include "update_engine/payload_generator/ab_generator.h"
1814158570d3995008dc93a628004118b87a6bca01Alex Deymo
1914158570d3995008dc93a628004118b87a6bca01Alex Deymo#include <algorithm>
2014158570d3995008dc93a628004118b87a6bca01Alex Deymo
2114158570d3995008dc93a628004118b87a6bca01Alex Deymo#include <base/strings/stringprintf.h>
2214158570d3995008dc93a628004118b87a6bca01Alex Deymo
2339910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/hash_calculator.h"
2439910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/utils.h"
2539910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/payload_consumer/payload_constants.h"
2614158570d3995008dc93a628004118b87a6bca01Alex Deymo#include "update_engine/payload_generator/annotated_operation.h"
27abdc0115548985d8ca3f3f2aeb1283741ce409a6Alex Deymo#include "update_engine/payload_generator/bzip.h"
2814158570d3995008dc93a628004118b87a6bca01Alex Deymo#include "update_engine/payload_generator/delta_diff_generator.h"
2914158570d3995008dc93a628004118b87a6bca01Alex Deymo#include "update_engine/payload_generator/delta_diff_utils.h"
3014158570d3995008dc93a628004118b87a6bca01Alex Deymo
31be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymousing chromeos_update_engine::diff_utils::IsAReplaceOperation;
3214158570d3995008dc93a628004118b87a6bca01Alex Deymousing std::string;
3314158570d3995008dc93a628004118b87a6bca01Alex Deymousing std::vector;
3414158570d3995008dc93a628004118b87a6bca01Alex Deymo
3514158570d3995008dc93a628004118b87a6bca01Alex Deymonamespace chromeos_update_engine {
3614158570d3995008dc93a628004118b87a6bca01Alex Deymo
3714158570d3995008dc93a628004118b87a6bca01Alex Deymobool ABGenerator::GenerateOperations(
3814158570d3995008dc93a628004118b87a6bca01Alex Deymo    const PayloadGenerationConfig& config,
39ebdf17d4202c67933764135bfc1cece629829201Sen Jiang    const PartitionConfig& old_part,
40ebdf17d4202c67933764135bfc1cece629829201Sen Jiang    const PartitionConfig& new_part,
418cc502dacbccdab96824d42287f230ce04004784Sen Jiang    BlobFileWriter* blob_file,
42ebdf17d4202c67933764135bfc1cece629829201Sen Jiang    vector<AnnotatedOperation>* aops) {
43625406cee9a90ac2ed895f480286b7f0e8497f38Sen Jiang  TEST_AND_RETURN_FALSE(old_part.name == new_part.name);
4414158570d3995008dc93a628004118b87a6bca01Alex Deymo
452d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo  ssize_t hard_chunk_blocks = (config.hard_chunk_size == -1 ? -1 :
462d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo                               config.hard_chunk_size / config.block_size);
472d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo  size_t soft_chunk_blocks = config.soft_chunk_size / config.block_size;
4814158570d3995008dc93a628004118b87a6bca01Alex Deymo
49ebdf17d4202c67933764135bfc1cece629829201Sen Jiang  aops->clear();
5038818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo  TEST_AND_RETURN_FALSE(diff_utils::DeltaReadPartition(aops,
5138818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo                                                       old_part,
5238818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo                                                       new_part,
5338818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo                                                       hard_chunk_blocks,
5438818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo                                                       soft_chunk_blocks,
5538818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo                                                       config.version,
5638818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo                                                       blob_file));
57625406cee9a90ac2ed895f480286b7f0e8497f38Sen Jiang  LOG(INFO) << "done reading " << new_part.name;
5814158570d3995008dc93a628004118b87a6bca01Alex Deymo
59be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo  TEST_AND_RETURN_FALSE(
60be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo      FragmentOperations(config.version, aops, new_part.path, blob_file));
61ebdf17d4202c67933764135bfc1cece629829201Sen Jiang  SortOperationsByDestination(aops);
622d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo
632d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo  // Use the soft_chunk_size when merging operations to prevent merging all
642d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo  // the operations into a huge one if there's no hard limit.
652d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo  size_t merge_chunk_blocks = soft_chunk_blocks;
662d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo  if (hard_chunk_blocks != -1 &&
672d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo      static_cast<size_t>(hard_chunk_blocks) < soft_chunk_blocks) {
682d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo    merge_chunk_blocks = hard_chunk_blocks;
692d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo  }
702d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo
71be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo  TEST_AND_RETURN_FALSE(MergeOperations(
72be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo      aops, config.version, merge_chunk_blocks, new_part.path, blob_file));
7382352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang
7438818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo  if (config.version.minor >= kOpSrcHashMinorPayloadVersion)
7582352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    TEST_AND_RETURN_FALSE(AddSourceHash(aops, old_part.path));
7682352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang
7714158570d3995008dc93a628004118b87a6bca01Alex Deymo  return true;
7814158570d3995008dc93a628004118b87a6bca01Alex Deymo}
7914158570d3995008dc93a628004118b87a6bca01Alex Deymo
8014158570d3995008dc93a628004118b87a6bca01Alex Deymovoid ABGenerator::SortOperationsByDestination(
8114158570d3995008dc93a628004118b87a6bca01Alex Deymo    vector<AnnotatedOperation>* aops) {
823b2c7d0e6d859e6fc75c82b3417f87cf5968a49dAlex Deymo  sort(aops->begin(), aops->end(), diff_utils::CompareAopsByDestination);
8314158570d3995008dc93a628004118b87a6bca01Alex Deymo}
8414158570d3995008dc93a628004118b87a6bca01Alex Deymo
85be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymobool ABGenerator::FragmentOperations(const PayloadVersion& version,
86be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo                                     vector<AnnotatedOperation>* aops,
87be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo                                     const string& target_part_path,
88be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo                                     BlobFileWriter* blob_file) {
8914158570d3995008dc93a628004118b87a6bca01Alex Deymo  vector<AnnotatedOperation> fragmented_aops;
9014158570d3995008dc93a628004118b87a6bca01Alex Deymo  for (const AnnotatedOperation& aop : *aops) {
91a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo    if (aop.op.type() == InstallOperation::SOURCE_COPY) {
9214158570d3995008dc93a628004118b87a6bca01Alex Deymo      TEST_AND_RETURN_FALSE(SplitSourceCopy(aop, &fragmented_aops));
93be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo    } else if (IsAReplaceOperation(aop.op.type())) {
94be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo      TEST_AND_RETURN_FALSE(SplitAReplaceOp(
95be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo          version, aop, target_part_path, &fragmented_aops, blob_file));
9614158570d3995008dc93a628004118b87a6bca01Alex Deymo    } else {
9714158570d3995008dc93a628004118b87a6bca01Alex Deymo      fragmented_aops.push_back(aop);
9814158570d3995008dc93a628004118b87a6bca01Alex Deymo    }
9914158570d3995008dc93a628004118b87a6bca01Alex Deymo  }
100be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo  *aops = std::move(fragmented_aops);
10114158570d3995008dc93a628004118b87a6bca01Alex Deymo  return true;
10214158570d3995008dc93a628004118b87a6bca01Alex Deymo}
10314158570d3995008dc93a628004118b87a6bca01Alex Deymo
10414158570d3995008dc93a628004118b87a6bca01Alex Deymobool ABGenerator::SplitSourceCopy(
10514158570d3995008dc93a628004118b87a6bca01Alex Deymo    const AnnotatedOperation& original_aop,
10614158570d3995008dc93a628004118b87a6bca01Alex Deymo    vector<AnnotatedOperation>* result_aops) {
107a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo  InstallOperation original_op = original_aop.op;
108a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo  TEST_AND_RETURN_FALSE(original_op.type() == InstallOperation::SOURCE_COPY);
10914158570d3995008dc93a628004118b87a6bca01Alex Deymo  // Keeps track of the index of curr_src_ext.
11014158570d3995008dc93a628004118b87a6bca01Alex Deymo  int curr_src_ext_index = 0;
11114158570d3995008dc93a628004118b87a6bca01Alex Deymo  Extent curr_src_ext = original_op.src_extents(curr_src_ext_index);
11214158570d3995008dc93a628004118b87a6bca01Alex Deymo  for (int i = 0; i < original_op.dst_extents_size(); i++) {
11314158570d3995008dc93a628004118b87a6bca01Alex Deymo    Extent dst_ext = original_op.dst_extents(i);
11414158570d3995008dc93a628004118b87a6bca01Alex Deymo    // The new operation which will have only one dst extent.
115a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo    InstallOperation new_op;
11614158570d3995008dc93a628004118b87a6bca01Alex Deymo    uint64_t blocks_left = dst_ext.num_blocks();
11714158570d3995008dc93a628004118b87a6bca01Alex Deymo    while (blocks_left > 0) {
11814158570d3995008dc93a628004118b87a6bca01Alex Deymo      if (curr_src_ext.num_blocks() <= blocks_left) {
11914158570d3995008dc93a628004118b87a6bca01Alex Deymo        // If the curr_src_ext is smaller than dst_ext, add it.
12014158570d3995008dc93a628004118b87a6bca01Alex Deymo        blocks_left -= curr_src_ext.num_blocks();
12114158570d3995008dc93a628004118b87a6bca01Alex Deymo        *(new_op.add_src_extents()) = curr_src_ext;
12214158570d3995008dc93a628004118b87a6bca01Alex Deymo        if (curr_src_ext_index + 1 < original_op.src_extents().size()) {
12314158570d3995008dc93a628004118b87a6bca01Alex Deymo          curr_src_ext = original_op.src_extents(++curr_src_ext_index);
12414158570d3995008dc93a628004118b87a6bca01Alex Deymo        } else {
12514158570d3995008dc93a628004118b87a6bca01Alex Deymo          break;
12614158570d3995008dc93a628004118b87a6bca01Alex Deymo        }
12714158570d3995008dc93a628004118b87a6bca01Alex Deymo      } else {
12814158570d3995008dc93a628004118b87a6bca01Alex Deymo        // Split src_exts that are bigger than the dst_ext we're dealing with.
12914158570d3995008dc93a628004118b87a6bca01Alex Deymo        Extent first_ext;
13014158570d3995008dc93a628004118b87a6bca01Alex Deymo        first_ext.set_num_blocks(blocks_left);
13114158570d3995008dc93a628004118b87a6bca01Alex Deymo        first_ext.set_start_block(curr_src_ext.start_block());
13214158570d3995008dc93a628004118b87a6bca01Alex Deymo        *(new_op.add_src_extents()) = first_ext;
13314158570d3995008dc93a628004118b87a6bca01Alex Deymo        // Keep the second half of the split op.
13414158570d3995008dc93a628004118b87a6bca01Alex Deymo        curr_src_ext.set_num_blocks(curr_src_ext.num_blocks() - blocks_left);
13514158570d3995008dc93a628004118b87a6bca01Alex Deymo        curr_src_ext.set_start_block(curr_src_ext.start_block() + blocks_left);
13614158570d3995008dc93a628004118b87a6bca01Alex Deymo        blocks_left -= first_ext.num_blocks();
13714158570d3995008dc93a628004118b87a6bca01Alex Deymo      }
13814158570d3995008dc93a628004118b87a6bca01Alex Deymo    }
13914158570d3995008dc93a628004118b87a6bca01Alex Deymo    // Fix up our new operation and add it to the results.
140a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo    new_op.set_type(InstallOperation::SOURCE_COPY);
14114158570d3995008dc93a628004118b87a6bca01Alex Deymo    *(new_op.add_dst_extents()) = dst_ext;
14214158570d3995008dc93a628004118b87a6bca01Alex Deymo    new_op.set_src_length(dst_ext.num_blocks() * kBlockSize);
14314158570d3995008dc93a628004118b87a6bca01Alex Deymo    new_op.set_dst_length(dst_ext.num_blocks() * kBlockSize);
14414158570d3995008dc93a628004118b87a6bca01Alex Deymo
14514158570d3995008dc93a628004118b87a6bca01Alex Deymo    AnnotatedOperation new_aop;
14614158570d3995008dc93a628004118b87a6bca01Alex Deymo    new_aop.op = new_op;
14714158570d3995008dc93a628004118b87a6bca01Alex Deymo    new_aop.name = base::StringPrintf("%s:%d", original_aop.name.c_str(), i);
14814158570d3995008dc93a628004118b87a6bca01Alex Deymo    result_aops->push_back(new_aop);
14914158570d3995008dc93a628004118b87a6bca01Alex Deymo  }
15014158570d3995008dc93a628004118b87a6bca01Alex Deymo  if (curr_src_ext_index != original_op.src_extents().size() - 1) {
15114158570d3995008dc93a628004118b87a6bca01Alex Deymo    LOG(FATAL) << "Incorrectly split SOURCE_COPY operation. Did not use all "
15214158570d3995008dc93a628004118b87a6bca01Alex Deymo               << "source extents.";
15314158570d3995008dc93a628004118b87a6bca01Alex Deymo  }
15414158570d3995008dc93a628004118b87a6bca01Alex Deymo  return true;
15514158570d3995008dc93a628004118b87a6bca01Alex Deymo}
15614158570d3995008dc93a628004118b87a6bca01Alex Deymo
157be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymobool ABGenerator::SplitAReplaceOp(const PayloadVersion& version,
158be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo                                  const AnnotatedOperation& original_aop,
159be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo                                  const string& target_part_path,
160be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo                                  vector<AnnotatedOperation>* result_aops,
161be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo                                  BlobFileWriter* blob_file) {
162a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo  InstallOperation original_op = original_aop.op;
163be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo  TEST_AND_RETURN_FALSE(IsAReplaceOperation(original_op.type()));
164a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo  const bool is_replace = original_op.type() == InstallOperation::REPLACE;
16514158570d3995008dc93a628004118b87a6bca01Alex Deymo
16614158570d3995008dc93a628004118b87a6bca01Alex Deymo  uint32_t data_offset = original_op.data_offset();
16714158570d3995008dc93a628004118b87a6bca01Alex Deymo  for (int i = 0; i < original_op.dst_extents_size(); i++) {
16814158570d3995008dc93a628004118b87a6bca01Alex Deymo    Extent dst_ext = original_op.dst_extents(i);
16914158570d3995008dc93a628004118b87a6bca01Alex Deymo    // Make a new operation with only one dst extent.
170a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo    InstallOperation new_op;
17114158570d3995008dc93a628004118b87a6bca01Alex Deymo    *(new_op.add_dst_extents()) = dst_ext;
17214158570d3995008dc93a628004118b87a6bca01Alex Deymo    uint32_t data_size = dst_ext.num_blocks() * kBlockSize;
17314158570d3995008dc93a628004118b87a6bca01Alex Deymo    new_op.set_dst_length(data_size);
17414158570d3995008dc93a628004118b87a6bca01Alex Deymo    // If this is a REPLACE, attempt to reuse portions of the existing blob.
17514158570d3995008dc93a628004118b87a6bca01Alex Deymo    if (is_replace) {
176a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo      new_op.set_type(InstallOperation::REPLACE);
17714158570d3995008dc93a628004118b87a6bca01Alex Deymo      new_op.set_data_length(data_size);
17814158570d3995008dc93a628004118b87a6bca01Alex Deymo      new_op.set_data_offset(data_offset);
17914158570d3995008dc93a628004118b87a6bca01Alex Deymo      data_offset += data_size;
18014158570d3995008dc93a628004118b87a6bca01Alex Deymo    }
18114158570d3995008dc93a628004118b87a6bca01Alex Deymo
18214158570d3995008dc93a628004118b87a6bca01Alex Deymo    AnnotatedOperation new_aop;
18314158570d3995008dc93a628004118b87a6bca01Alex Deymo    new_aop.op = new_op;
18414158570d3995008dc93a628004118b87a6bca01Alex Deymo    new_aop.name = base::StringPrintf("%s:%d", original_aop.name.c_str(), i);
185be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo    TEST_AND_RETURN_FALSE(
186be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo        AddDataAndSetType(&new_aop, version, target_part_path, blob_file));
18714158570d3995008dc93a628004118b87a6bca01Alex Deymo
18814158570d3995008dc93a628004118b87a6bca01Alex Deymo    result_aops->push_back(new_aop);
18914158570d3995008dc93a628004118b87a6bca01Alex Deymo  }
19014158570d3995008dc93a628004118b87a6bca01Alex Deymo  return true;
19114158570d3995008dc93a628004118b87a6bca01Alex Deymo}
19214158570d3995008dc93a628004118b87a6bca01Alex Deymo
19314158570d3995008dc93a628004118b87a6bca01Alex Deymobool ABGenerator::MergeOperations(vector<AnnotatedOperation>* aops,
194be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo                                  const PayloadVersion& version,
1952d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo                                  size_t chunk_blocks,
19614158570d3995008dc93a628004118b87a6bca01Alex Deymo                                  const string& target_part_path,
1978cc502dacbccdab96824d42287f230ce04004784Sen Jiang                                  BlobFileWriter* blob_file) {
19814158570d3995008dc93a628004118b87a6bca01Alex Deymo  vector<AnnotatedOperation> new_aops;
19914158570d3995008dc93a628004118b87a6bca01Alex Deymo  for (const AnnotatedOperation& curr_aop : *aops) {
20014158570d3995008dc93a628004118b87a6bca01Alex Deymo    if (new_aops.empty()) {
20114158570d3995008dc93a628004118b87a6bca01Alex Deymo      new_aops.push_back(curr_aop);
20214158570d3995008dc93a628004118b87a6bca01Alex Deymo      continue;
20314158570d3995008dc93a628004118b87a6bca01Alex Deymo    }
20414158570d3995008dc93a628004118b87a6bca01Alex Deymo    AnnotatedOperation& last_aop = new_aops.back();
205be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo    bool last_is_a_replace = IsAReplaceOperation(last_aop.op.type());
20614158570d3995008dc93a628004118b87a6bca01Alex Deymo
20714158570d3995008dc93a628004118b87a6bca01Alex Deymo    if (last_aop.op.dst_extents_size() <= 0 ||
20814158570d3995008dc93a628004118b87a6bca01Alex Deymo        curr_aop.op.dst_extents_size() <= 0) {
20914158570d3995008dc93a628004118b87a6bca01Alex Deymo      new_aops.push_back(curr_aop);
21014158570d3995008dc93a628004118b87a6bca01Alex Deymo      continue;
21114158570d3995008dc93a628004118b87a6bca01Alex Deymo    }
21214158570d3995008dc93a628004118b87a6bca01Alex Deymo    uint32_t last_dst_idx = last_aop.op.dst_extents_size() - 1;
21314158570d3995008dc93a628004118b87a6bca01Alex Deymo    uint32_t last_end_block =
21414158570d3995008dc93a628004118b87a6bca01Alex Deymo        last_aop.op.dst_extents(last_dst_idx).start_block() +
21514158570d3995008dc93a628004118b87a6bca01Alex Deymo        last_aop.op.dst_extents(last_dst_idx).num_blocks();
21614158570d3995008dc93a628004118b87a6bca01Alex Deymo    uint32_t curr_start_block = curr_aop.op.dst_extents(0).start_block();
21714158570d3995008dc93a628004118b87a6bca01Alex Deymo    uint32_t combined_block_count =
21814158570d3995008dc93a628004118b87a6bca01Alex Deymo        last_aop.op.dst_extents(last_dst_idx).num_blocks() +
21914158570d3995008dc93a628004118b87a6bca01Alex Deymo        curr_aop.op.dst_extents(0).num_blocks();
220be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo    bool is_a_replace = IsAReplaceOperation(curr_aop.op.type());
221be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo
222be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo    bool is_delta_op = curr_aop.op.type() == InstallOperation::SOURCE_COPY;
223be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo    if (((is_delta_op && (last_aop.op.type() == curr_aop.op.type())) ||
224be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo         (is_a_replace && last_is_a_replace)) &&
22514158570d3995008dc93a628004118b87a6bca01Alex Deymo        last_end_block == curr_start_block &&
2262d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo        combined_block_count <= chunk_blocks) {
22714158570d3995008dc93a628004118b87a6bca01Alex Deymo      // If the operations have the same type (which is a type that we can
22814158570d3995008dc93a628004118b87a6bca01Alex Deymo      // merge), are contiguous, are fragmented to have one destination extent,
22914158570d3995008dc93a628004118b87a6bca01Alex Deymo      // and their combined block count would be less than chunk size, merge
23014158570d3995008dc93a628004118b87a6bca01Alex Deymo      // them.
23114158570d3995008dc93a628004118b87a6bca01Alex Deymo      last_aop.name = base::StringPrintf("%s,%s",
23214158570d3995008dc93a628004118b87a6bca01Alex Deymo                                         last_aop.name.c_str(),
23314158570d3995008dc93a628004118b87a6bca01Alex Deymo                                         curr_aop.name.c_str());
23414158570d3995008dc93a628004118b87a6bca01Alex Deymo
235be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo      if (is_delta_op) {
236be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo        ExtendExtents(last_aop.op.mutable_src_extents(),
237be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo                      curr_aop.op.src_extents());
238be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo        if (curr_aop.op.src_length() > 0)
239be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo          last_aop.op.set_src_length(last_aop.op.src_length() +
240be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo                                     curr_aop.op.src_length());
241be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo      }
24214158570d3995008dc93a628004118b87a6bca01Alex Deymo      ExtendExtents(last_aop.op.mutable_dst_extents(),
24314158570d3995008dc93a628004118b87a6bca01Alex Deymo                    curr_aop.op.dst_extents());
24414158570d3995008dc93a628004118b87a6bca01Alex Deymo      if (curr_aop.op.dst_length() > 0)
24514158570d3995008dc93a628004118b87a6bca01Alex Deymo        last_aop.op.set_dst_length(last_aop.op.dst_length() +
24614158570d3995008dc93a628004118b87a6bca01Alex Deymo                                   curr_aop.op.dst_length());
24714158570d3995008dc93a628004118b87a6bca01Alex Deymo      // Set the data length to zero so we know to add the blob later.
248be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo      if (is_a_replace)
24914158570d3995008dc93a628004118b87a6bca01Alex Deymo        last_aop.op.set_data_length(0);
25014158570d3995008dc93a628004118b87a6bca01Alex Deymo    } else {
25114158570d3995008dc93a628004118b87a6bca01Alex Deymo      // Otherwise just include the extent as is.
25214158570d3995008dc93a628004118b87a6bca01Alex Deymo      new_aops.push_back(curr_aop);
25314158570d3995008dc93a628004118b87a6bca01Alex Deymo    }
25414158570d3995008dc93a628004118b87a6bca01Alex Deymo  }
25514158570d3995008dc93a628004118b87a6bca01Alex Deymo
256be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo  // Set the blobs for REPLACE/REPLACE_BZ/REPLACE_XZ operations that have been
257be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo  // merged.
25814158570d3995008dc93a628004118b87a6bca01Alex Deymo  for (AnnotatedOperation& curr_aop : new_aops) {
25914158570d3995008dc93a628004118b87a6bca01Alex Deymo    if (curr_aop.op.data_length() == 0 &&
260be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo        IsAReplaceOperation(curr_aop.op.type())) {
261be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo      TEST_AND_RETURN_FALSE(
262be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo          AddDataAndSetType(&curr_aop, version, target_part_path, blob_file));
26314158570d3995008dc93a628004118b87a6bca01Alex Deymo    }
26414158570d3995008dc93a628004118b87a6bca01Alex Deymo  }
26514158570d3995008dc93a628004118b87a6bca01Alex Deymo
26614158570d3995008dc93a628004118b87a6bca01Alex Deymo  *aops = new_aops;
26714158570d3995008dc93a628004118b87a6bca01Alex Deymo  return true;
26814158570d3995008dc93a628004118b87a6bca01Alex Deymo}
26914158570d3995008dc93a628004118b87a6bca01Alex Deymo
27014158570d3995008dc93a628004118b87a6bca01Alex Deymobool ABGenerator::AddDataAndSetType(AnnotatedOperation* aop,
271be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo                                    const PayloadVersion& version,
27214158570d3995008dc93a628004118b87a6bca01Alex Deymo                                    const string& target_part_path,
2738cc502dacbccdab96824d42287f230ce04004784Sen Jiang                                    BlobFileWriter* blob_file) {
274be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo  TEST_AND_RETURN_FALSE(IsAReplaceOperation(aop->op.type()));
27514158570d3995008dc93a628004118b87a6bca01Alex Deymo
2763f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  brillo::Blob data(aop->op.dst_length());
27714158570d3995008dc93a628004118b87a6bca01Alex Deymo  vector<Extent> dst_extents;
27814158570d3995008dc93a628004118b87a6bca01Alex Deymo  ExtentsToVector(aop->op.dst_extents(), &dst_extents);
27914158570d3995008dc93a628004118b87a6bca01Alex Deymo  TEST_AND_RETURN_FALSE(utils::ReadExtents(target_part_path,
28014158570d3995008dc93a628004118b87a6bca01Alex Deymo                                           dst_extents,
28114158570d3995008dc93a628004118b87a6bca01Alex Deymo                                           &data,
28214158570d3995008dc93a628004118b87a6bca01Alex Deymo                                           data.size(),
28314158570d3995008dc93a628004118b87a6bca01Alex Deymo                                           kBlockSize));
28414158570d3995008dc93a628004118b87a6bca01Alex Deymo
285be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo  brillo::Blob blob;
286be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo  InstallOperation_Type op_type;
287be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo  TEST_AND_RETURN_FALSE(
288be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo      diff_utils::GenerateBestFullOperation(data, version, &blob, &op_type));
28914158570d3995008dc93a628004118b87a6bca01Alex Deymo
290be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo  // If the operation doesn't point to a data blob or points to a data blob of
291be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo  // a different type then we add it.
292be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo  if (aop->op.type() != op_type || aop->op.data_length() != blob.size()) {
293be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo    aop->op.set_type(op_type);
294be77e9ed80be653fadd76dfda6ef325160678b27Alex Deymo    aop->SetOperationBlob(blob, blob_file);
29514158570d3995008dc93a628004118b87a6bca01Alex Deymo  }
29614158570d3995008dc93a628004118b87a6bca01Alex Deymo
29714158570d3995008dc93a628004118b87a6bca01Alex Deymo  return true;
29814158570d3995008dc93a628004118b87a6bca01Alex Deymo}
29914158570d3995008dc93a628004118b87a6bca01Alex Deymo
30082352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiangbool ABGenerator::AddSourceHash(vector<AnnotatedOperation>* aops,
30182352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang                                const string& source_part_path) {
30282352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang  for (AnnotatedOperation& aop : *aops) {
30382352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    if (aop.op.src_extents_size() == 0)
30482352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang      continue;
30582352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang
30682352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    vector<Extent> src_extents;
30782352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    ExtentsToVector(aop.op.src_extents(), &src_extents);
30882352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    brillo::Blob src_data, src_hash;
30982352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    uint64_t src_length =
31082352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang        aop.op.has_src_length()
31182352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang            ? aop.op.src_length()
31282352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang            : BlocksInExtents(aop.op.src_extents()) * kBlockSize;
31382352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    TEST_AND_RETURN_FALSE(utils::ReadExtents(
31482352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang        source_part_path, src_extents, &src_data, src_length, kBlockSize));
31539910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo    TEST_AND_RETURN_FALSE(HashCalculator::RawHashOfData(src_data, &src_hash));
31682352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    aop.op.set_src_sha256_hash(src_hash.data(), src_hash.size());
31782352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang  }
31882352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang  return true;
31982352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang}
32082352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang
32114158570d3995008dc93a628004118b87a6bca01Alex Deymo}  // namespace chromeos_update_engine
322