ab_generator.cc revision 38818fbf1f2f937051b5bcc01ff74539a3c9b27d
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
3114158570d3995008dc93a628004118b87a6bca01Alex Deymousing std::string;
3214158570d3995008dc93a628004118b87a6bca01Alex Deymousing std::vector;
3314158570d3995008dc93a628004118b87a6bca01Alex Deymo
3414158570d3995008dc93a628004118b87a6bca01Alex Deymonamespace chromeos_update_engine {
3514158570d3995008dc93a628004118b87a6bca01Alex Deymo
3614158570d3995008dc93a628004118b87a6bca01Alex Deymobool ABGenerator::GenerateOperations(
3714158570d3995008dc93a628004118b87a6bca01Alex Deymo    const PayloadGenerationConfig& config,
38ebdf17d4202c67933764135bfc1cece629829201Sen Jiang    const PartitionConfig& old_part,
39ebdf17d4202c67933764135bfc1cece629829201Sen Jiang    const PartitionConfig& new_part,
408cc502dacbccdab96824d42287f230ce04004784Sen Jiang    BlobFileWriter* blob_file,
41ebdf17d4202c67933764135bfc1cece629829201Sen Jiang    vector<AnnotatedOperation>* aops) {
42625406cee9a90ac2ed895f480286b7f0e8497f38Sen Jiang  TEST_AND_RETURN_FALSE(old_part.name == new_part.name);
4314158570d3995008dc93a628004118b87a6bca01Alex Deymo
442d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo  ssize_t hard_chunk_blocks = (config.hard_chunk_size == -1 ? -1 :
452d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo                               config.hard_chunk_size / config.block_size);
462d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo  size_t soft_chunk_blocks = config.soft_chunk_size / config.block_size;
4714158570d3995008dc93a628004118b87a6bca01Alex Deymo
48ebdf17d4202c67933764135bfc1cece629829201Sen Jiang  aops->clear();
4938818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo  TEST_AND_RETURN_FALSE(diff_utils::DeltaReadPartition(aops,
5038818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo                                                       old_part,
5138818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo                                                       new_part,
5238818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo                                                       hard_chunk_blocks,
5338818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo                                                       soft_chunk_blocks,
5438818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo                                                       config.version,
5538818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo                                                       blob_file));
56625406cee9a90ac2ed895f480286b7f0e8497f38Sen Jiang  LOG(INFO) << "done reading " << new_part.name;
5714158570d3995008dc93a628004118b87a6bca01Alex Deymo
58ebdf17d4202c67933764135bfc1cece629829201Sen Jiang  TEST_AND_RETURN_FALSE(FragmentOperations(aops,
59ebdf17d4202c67933764135bfc1cece629829201Sen Jiang                                           new_part.path,
608cc502dacbccdab96824d42287f230ce04004784Sen Jiang                                           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
71ebdf17d4202c67933764135bfc1cece629829201Sen Jiang  TEST_AND_RETURN_FALSE(MergeOperations(aops,
722d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo                                        merge_chunk_blocks,
73ebdf17d4202c67933764135bfc1cece629829201Sen Jiang                                        new_part.path,
748cc502dacbccdab96824d42287f230ce04004784Sen Jiang                                        blob_file));
7582352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang
7638818fbf1f2f937051b5bcc01ff74539a3c9b27dAlex Deymo  if (config.version.minor >= kOpSrcHashMinorPayloadVersion)
7782352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    TEST_AND_RETURN_FALSE(AddSourceHash(aops, old_part.path));
7882352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang
7914158570d3995008dc93a628004118b87a6bca01Alex Deymo  return true;
8014158570d3995008dc93a628004118b87a6bca01Alex Deymo}
8114158570d3995008dc93a628004118b87a6bca01Alex Deymo
8214158570d3995008dc93a628004118b87a6bca01Alex Deymovoid ABGenerator::SortOperationsByDestination(
8314158570d3995008dc93a628004118b87a6bca01Alex Deymo    vector<AnnotatedOperation>* aops) {
843b2c7d0e6d859e6fc75c82b3417f87cf5968a49dAlex Deymo  sort(aops->begin(), aops->end(), diff_utils::CompareAopsByDestination);
8514158570d3995008dc93a628004118b87a6bca01Alex Deymo}
8614158570d3995008dc93a628004118b87a6bca01Alex Deymo
8714158570d3995008dc93a628004118b87a6bca01Alex Deymobool ABGenerator::FragmentOperations(
8814158570d3995008dc93a628004118b87a6bca01Alex Deymo    vector<AnnotatedOperation>* aops,
8914158570d3995008dc93a628004118b87a6bca01Alex Deymo    const string& target_part_path,
908cc502dacbccdab96824d42287f230ce04004784Sen Jiang    BlobFileWriter* blob_file) {
9114158570d3995008dc93a628004118b87a6bca01Alex Deymo  vector<AnnotatedOperation> fragmented_aops;
9214158570d3995008dc93a628004118b87a6bca01Alex Deymo  for (const AnnotatedOperation& aop : *aops) {
93a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo    if (aop.op.type() == InstallOperation::SOURCE_COPY) {
9414158570d3995008dc93a628004118b87a6bca01Alex Deymo      TEST_AND_RETURN_FALSE(SplitSourceCopy(aop, &fragmented_aops));
95a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo    } else if ((aop.op.type() == InstallOperation::REPLACE) ||
96a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo               (aop.op.type() == InstallOperation::REPLACE_BZ)) {
9714158570d3995008dc93a628004118b87a6bca01Alex Deymo      TEST_AND_RETURN_FALSE(SplitReplaceOrReplaceBz(aop, &fragmented_aops,
988cc502dacbccdab96824d42287f230ce04004784Sen Jiang                                                    target_part_path,
998cc502dacbccdab96824d42287f230ce04004784Sen Jiang                                                    blob_file));
10014158570d3995008dc93a628004118b87a6bca01Alex Deymo    } else {
10114158570d3995008dc93a628004118b87a6bca01Alex Deymo      fragmented_aops.push_back(aop);
10214158570d3995008dc93a628004118b87a6bca01Alex Deymo    }
10314158570d3995008dc93a628004118b87a6bca01Alex Deymo  }
10414158570d3995008dc93a628004118b87a6bca01Alex Deymo  *aops = fragmented_aops;
10514158570d3995008dc93a628004118b87a6bca01Alex Deymo  return true;
10614158570d3995008dc93a628004118b87a6bca01Alex Deymo}
10714158570d3995008dc93a628004118b87a6bca01Alex Deymo
10814158570d3995008dc93a628004118b87a6bca01Alex Deymobool ABGenerator::SplitSourceCopy(
10914158570d3995008dc93a628004118b87a6bca01Alex Deymo    const AnnotatedOperation& original_aop,
11014158570d3995008dc93a628004118b87a6bca01Alex Deymo    vector<AnnotatedOperation>* result_aops) {
111a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo  InstallOperation original_op = original_aop.op;
112a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo  TEST_AND_RETURN_FALSE(original_op.type() == InstallOperation::SOURCE_COPY);
11314158570d3995008dc93a628004118b87a6bca01Alex Deymo  // Keeps track of the index of curr_src_ext.
11414158570d3995008dc93a628004118b87a6bca01Alex Deymo  int curr_src_ext_index = 0;
11514158570d3995008dc93a628004118b87a6bca01Alex Deymo  Extent curr_src_ext = original_op.src_extents(curr_src_ext_index);
11614158570d3995008dc93a628004118b87a6bca01Alex Deymo  for (int i = 0; i < original_op.dst_extents_size(); i++) {
11714158570d3995008dc93a628004118b87a6bca01Alex Deymo    Extent dst_ext = original_op.dst_extents(i);
11814158570d3995008dc93a628004118b87a6bca01Alex Deymo    // The new operation which will have only one dst extent.
119a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo    InstallOperation new_op;
12014158570d3995008dc93a628004118b87a6bca01Alex Deymo    uint64_t blocks_left = dst_ext.num_blocks();
12114158570d3995008dc93a628004118b87a6bca01Alex Deymo    while (blocks_left > 0) {
12214158570d3995008dc93a628004118b87a6bca01Alex Deymo      if (curr_src_ext.num_blocks() <= blocks_left) {
12314158570d3995008dc93a628004118b87a6bca01Alex Deymo        // If the curr_src_ext is smaller than dst_ext, add it.
12414158570d3995008dc93a628004118b87a6bca01Alex Deymo        blocks_left -= curr_src_ext.num_blocks();
12514158570d3995008dc93a628004118b87a6bca01Alex Deymo        *(new_op.add_src_extents()) = curr_src_ext;
12614158570d3995008dc93a628004118b87a6bca01Alex Deymo        if (curr_src_ext_index + 1 < original_op.src_extents().size()) {
12714158570d3995008dc93a628004118b87a6bca01Alex Deymo          curr_src_ext = original_op.src_extents(++curr_src_ext_index);
12814158570d3995008dc93a628004118b87a6bca01Alex Deymo        } else {
12914158570d3995008dc93a628004118b87a6bca01Alex Deymo          break;
13014158570d3995008dc93a628004118b87a6bca01Alex Deymo        }
13114158570d3995008dc93a628004118b87a6bca01Alex Deymo      } else {
13214158570d3995008dc93a628004118b87a6bca01Alex Deymo        // Split src_exts that are bigger than the dst_ext we're dealing with.
13314158570d3995008dc93a628004118b87a6bca01Alex Deymo        Extent first_ext;
13414158570d3995008dc93a628004118b87a6bca01Alex Deymo        first_ext.set_num_blocks(blocks_left);
13514158570d3995008dc93a628004118b87a6bca01Alex Deymo        first_ext.set_start_block(curr_src_ext.start_block());
13614158570d3995008dc93a628004118b87a6bca01Alex Deymo        *(new_op.add_src_extents()) = first_ext;
13714158570d3995008dc93a628004118b87a6bca01Alex Deymo        // Keep the second half of the split op.
13814158570d3995008dc93a628004118b87a6bca01Alex Deymo        curr_src_ext.set_num_blocks(curr_src_ext.num_blocks() - blocks_left);
13914158570d3995008dc93a628004118b87a6bca01Alex Deymo        curr_src_ext.set_start_block(curr_src_ext.start_block() + blocks_left);
14014158570d3995008dc93a628004118b87a6bca01Alex Deymo        blocks_left -= first_ext.num_blocks();
14114158570d3995008dc93a628004118b87a6bca01Alex Deymo      }
14214158570d3995008dc93a628004118b87a6bca01Alex Deymo    }
14314158570d3995008dc93a628004118b87a6bca01Alex Deymo    // Fix up our new operation and add it to the results.
144a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo    new_op.set_type(InstallOperation::SOURCE_COPY);
14514158570d3995008dc93a628004118b87a6bca01Alex Deymo    *(new_op.add_dst_extents()) = dst_ext;
14614158570d3995008dc93a628004118b87a6bca01Alex Deymo    new_op.set_src_length(dst_ext.num_blocks() * kBlockSize);
14714158570d3995008dc93a628004118b87a6bca01Alex Deymo    new_op.set_dst_length(dst_ext.num_blocks() * kBlockSize);
14814158570d3995008dc93a628004118b87a6bca01Alex Deymo
14914158570d3995008dc93a628004118b87a6bca01Alex Deymo    AnnotatedOperation new_aop;
15014158570d3995008dc93a628004118b87a6bca01Alex Deymo    new_aop.op = new_op;
15114158570d3995008dc93a628004118b87a6bca01Alex Deymo    new_aop.name = base::StringPrintf("%s:%d", original_aop.name.c_str(), i);
15214158570d3995008dc93a628004118b87a6bca01Alex Deymo    result_aops->push_back(new_aop);
15314158570d3995008dc93a628004118b87a6bca01Alex Deymo  }
15414158570d3995008dc93a628004118b87a6bca01Alex Deymo  if (curr_src_ext_index != original_op.src_extents().size() - 1) {
15514158570d3995008dc93a628004118b87a6bca01Alex Deymo    LOG(FATAL) << "Incorrectly split SOURCE_COPY operation. Did not use all "
15614158570d3995008dc93a628004118b87a6bca01Alex Deymo               << "source extents.";
15714158570d3995008dc93a628004118b87a6bca01Alex Deymo  }
15814158570d3995008dc93a628004118b87a6bca01Alex Deymo  return true;
15914158570d3995008dc93a628004118b87a6bca01Alex Deymo}
16014158570d3995008dc93a628004118b87a6bca01Alex Deymo
16114158570d3995008dc93a628004118b87a6bca01Alex Deymobool ABGenerator::SplitReplaceOrReplaceBz(
16214158570d3995008dc93a628004118b87a6bca01Alex Deymo    const AnnotatedOperation& original_aop,
16314158570d3995008dc93a628004118b87a6bca01Alex Deymo    vector<AnnotatedOperation>* result_aops,
16414158570d3995008dc93a628004118b87a6bca01Alex Deymo    const string& target_part_path,
1658cc502dacbccdab96824d42287f230ce04004784Sen Jiang    BlobFileWriter* blob_file) {
166a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo  InstallOperation original_op = original_aop.op;
167a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo  const bool is_replace = original_op.type() == InstallOperation::REPLACE;
168a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo  TEST_AND_RETURN_FALSE(is_replace ||
169a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo                        original_op.type() == InstallOperation::REPLACE_BZ);
17014158570d3995008dc93a628004118b87a6bca01Alex Deymo
17114158570d3995008dc93a628004118b87a6bca01Alex Deymo  uint32_t data_offset = original_op.data_offset();
17214158570d3995008dc93a628004118b87a6bca01Alex Deymo  for (int i = 0; i < original_op.dst_extents_size(); i++) {
17314158570d3995008dc93a628004118b87a6bca01Alex Deymo    Extent dst_ext = original_op.dst_extents(i);
17414158570d3995008dc93a628004118b87a6bca01Alex Deymo    // Make a new operation with only one dst extent.
175a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo    InstallOperation new_op;
17614158570d3995008dc93a628004118b87a6bca01Alex Deymo    *(new_op.add_dst_extents()) = dst_ext;
17714158570d3995008dc93a628004118b87a6bca01Alex Deymo    uint32_t data_size = dst_ext.num_blocks() * kBlockSize;
17814158570d3995008dc93a628004118b87a6bca01Alex Deymo    new_op.set_dst_length(data_size);
17914158570d3995008dc93a628004118b87a6bca01Alex Deymo    // If this is a REPLACE, attempt to reuse portions of the existing blob.
18014158570d3995008dc93a628004118b87a6bca01Alex Deymo    if (is_replace) {
181a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo      new_op.set_type(InstallOperation::REPLACE);
18214158570d3995008dc93a628004118b87a6bca01Alex Deymo      new_op.set_data_length(data_size);
18314158570d3995008dc93a628004118b87a6bca01Alex Deymo      new_op.set_data_offset(data_offset);
18414158570d3995008dc93a628004118b87a6bca01Alex Deymo      data_offset += data_size;
18514158570d3995008dc93a628004118b87a6bca01Alex Deymo    }
18614158570d3995008dc93a628004118b87a6bca01Alex Deymo
18714158570d3995008dc93a628004118b87a6bca01Alex Deymo    AnnotatedOperation new_aop;
18814158570d3995008dc93a628004118b87a6bca01Alex Deymo    new_aop.op = new_op;
18914158570d3995008dc93a628004118b87a6bca01Alex Deymo    new_aop.name = base::StringPrintf("%s:%d", original_aop.name.c_str(), i);
1908cc502dacbccdab96824d42287f230ce04004784Sen Jiang    TEST_AND_RETURN_FALSE(AddDataAndSetType(&new_aop, target_part_path,
1918cc502dacbccdab96824d42287f230ce04004784Sen Jiang                                            blob_file));
19214158570d3995008dc93a628004118b87a6bca01Alex Deymo
19314158570d3995008dc93a628004118b87a6bca01Alex Deymo    result_aops->push_back(new_aop);
19414158570d3995008dc93a628004118b87a6bca01Alex Deymo  }
19514158570d3995008dc93a628004118b87a6bca01Alex Deymo  return true;
19614158570d3995008dc93a628004118b87a6bca01Alex Deymo}
19714158570d3995008dc93a628004118b87a6bca01Alex Deymo
19814158570d3995008dc93a628004118b87a6bca01Alex Deymobool ABGenerator::MergeOperations(vector<AnnotatedOperation>* aops,
1992d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo                                  size_t chunk_blocks,
20014158570d3995008dc93a628004118b87a6bca01Alex Deymo                                  const string& target_part_path,
2018cc502dacbccdab96824d42287f230ce04004784Sen Jiang                                  BlobFileWriter* blob_file) {
20214158570d3995008dc93a628004118b87a6bca01Alex Deymo  vector<AnnotatedOperation> new_aops;
20314158570d3995008dc93a628004118b87a6bca01Alex Deymo  for (const AnnotatedOperation& curr_aop : *aops) {
20414158570d3995008dc93a628004118b87a6bca01Alex Deymo    if (new_aops.empty()) {
20514158570d3995008dc93a628004118b87a6bca01Alex Deymo      new_aops.push_back(curr_aop);
20614158570d3995008dc93a628004118b87a6bca01Alex Deymo      continue;
20714158570d3995008dc93a628004118b87a6bca01Alex Deymo    }
20814158570d3995008dc93a628004118b87a6bca01Alex Deymo    AnnotatedOperation& last_aop = new_aops.back();
20914158570d3995008dc93a628004118b87a6bca01Alex Deymo
21014158570d3995008dc93a628004118b87a6bca01Alex Deymo    if (last_aop.op.dst_extents_size() <= 0 ||
21114158570d3995008dc93a628004118b87a6bca01Alex Deymo        curr_aop.op.dst_extents_size() <= 0) {
21214158570d3995008dc93a628004118b87a6bca01Alex Deymo      new_aops.push_back(curr_aop);
21314158570d3995008dc93a628004118b87a6bca01Alex Deymo      continue;
21414158570d3995008dc93a628004118b87a6bca01Alex Deymo    }
21514158570d3995008dc93a628004118b87a6bca01Alex Deymo    uint32_t last_dst_idx = last_aop.op.dst_extents_size() - 1;
21614158570d3995008dc93a628004118b87a6bca01Alex Deymo    uint32_t last_end_block =
21714158570d3995008dc93a628004118b87a6bca01Alex Deymo        last_aop.op.dst_extents(last_dst_idx).start_block() +
21814158570d3995008dc93a628004118b87a6bca01Alex Deymo        last_aop.op.dst_extents(last_dst_idx).num_blocks();
21914158570d3995008dc93a628004118b87a6bca01Alex Deymo    uint32_t curr_start_block = curr_aop.op.dst_extents(0).start_block();
22014158570d3995008dc93a628004118b87a6bca01Alex Deymo    uint32_t combined_block_count =
22114158570d3995008dc93a628004118b87a6bca01Alex Deymo        last_aop.op.dst_extents(last_dst_idx).num_blocks() +
22214158570d3995008dc93a628004118b87a6bca01Alex Deymo        curr_aop.op.dst_extents(0).num_blocks();
223a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo    bool good_op_type = curr_aop.op.type() == InstallOperation::SOURCE_COPY ||
224a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo                        curr_aop.op.type() == InstallOperation::REPLACE ||
225a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo                        curr_aop.op.type() == InstallOperation::REPLACE_BZ;
22614158570d3995008dc93a628004118b87a6bca01Alex Deymo    if (good_op_type &&
22714158570d3995008dc93a628004118b87a6bca01Alex Deymo        last_aop.op.type() == curr_aop.op.type() &&
22814158570d3995008dc93a628004118b87a6bca01Alex Deymo        last_end_block == curr_start_block &&
2292d3b2d635e50c6886e285afb86c3187d9e0bd360Alex Deymo        combined_block_count <= chunk_blocks) {
23014158570d3995008dc93a628004118b87a6bca01Alex Deymo      // If the operations have the same type (which is a type that we can
23114158570d3995008dc93a628004118b87a6bca01Alex Deymo      // merge), are contiguous, are fragmented to have one destination extent,
23214158570d3995008dc93a628004118b87a6bca01Alex Deymo      // and their combined block count would be less than chunk size, merge
23314158570d3995008dc93a628004118b87a6bca01Alex Deymo      // them.
23414158570d3995008dc93a628004118b87a6bca01Alex Deymo      last_aop.name = base::StringPrintf("%s,%s",
23514158570d3995008dc93a628004118b87a6bca01Alex Deymo                                         last_aop.name.c_str(),
23614158570d3995008dc93a628004118b87a6bca01Alex Deymo                                         curr_aop.name.c_str());
23714158570d3995008dc93a628004118b87a6bca01Alex Deymo
23814158570d3995008dc93a628004118b87a6bca01Alex Deymo      ExtendExtents(last_aop.op.mutable_src_extents(),
23914158570d3995008dc93a628004118b87a6bca01Alex Deymo                    curr_aop.op.src_extents());
24014158570d3995008dc93a628004118b87a6bca01Alex Deymo      if (curr_aop.op.src_length() > 0)
24114158570d3995008dc93a628004118b87a6bca01Alex Deymo        last_aop.op.set_src_length(last_aop.op.src_length() +
24214158570d3995008dc93a628004118b87a6bca01Alex Deymo                                   curr_aop.op.src_length());
24314158570d3995008dc93a628004118b87a6bca01Alex Deymo      ExtendExtents(last_aop.op.mutable_dst_extents(),
24414158570d3995008dc93a628004118b87a6bca01Alex Deymo                    curr_aop.op.dst_extents());
24514158570d3995008dc93a628004118b87a6bca01Alex Deymo      if (curr_aop.op.dst_length() > 0)
24614158570d3995008dc93a628004118b87a6bca01Alex Deymo        last_aop.op.set_dst_length(last_aop.op.dst_length() +
24714158570d3995008dc93a628004118b87a6bca01Alex Deymo                                   curr_aop.op.dst_length());
24814158570d3995008dc93a628004118b87a6bca01Alex Deymo      // Set the data length to zero so we know to add the blob later.
249a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo      if (curr_aop.op.type() == InstallOperation::REPLACE ||
250a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo          curr_aop.op.type() == InstallOperation::REPLACE_BZ) {
25114158570d3995008dc93a628004118b87a6bca01Alex Deymo        last_aop.op.set_data_length(0);
25214158570d3995008dc93a628004118b87a6bca01Alex Deymo      }
25314158570d3995008dc93a628004118b87a6bca01Alex Deymo    } else {
25414158570d3995008dc93a628004118b87a6bca01Alex Deymo      // Otherwise just include the extent as is.
25514158570d3995008dc93a628004118b87a6bca01Alex Deymo      new_aops.push_back(curr_aop);
25614158570d3995008dc93a628004118b87a6bca01Alex Deymo    }
25714158570d3995008dc93a628004118b87a6bca01Alex Deymo  }
25814158570d3995008dc93a628004118b87a6bca01Alex Deymo
25914158570d3995008dc93a628004118b87a6bca01Alex Deymo  // Set the blobs for REPLACE/REPLACE_BZ operations that have been merged.
26014158570d3995008dc93a628004118b87a6bca01Alex Deymo  for (AnnotatedOperation& curr_aop : new_aops) {
26114158570d3995008dc93a628004118b87a6bca01Alex Deymo    if (curr_aop.op.data_length() == 0 &&
262a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo        (curr_aop.op.type() == InstallOperation::REPLACE ||
263a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo         curr_aop.op.type() == InstallOperation::REPLACE_BZ)) {
26414158570d3995008dc93a628004118b87a6bca01Alex Deymo      TEST_AND_RETURN_FALSE(AddDataAndSetType(&curr_aop, target_part_path,
2658cc502dacbccdab96824d42287f230ce04004784Sen Jiang                                              blob_file));
26614158570d3995008dc93a628004118b87a6bca01Alex Deymo    }
26714158570d3995008dc93a628004118b87a6bca01Alex Deymo  }
26814158570d3995008dc93a628004118b87a6bca01Alex Deymo
26914158570d3995008dc93a628004118b87a6bca01Alex Deymo  *aops = new_aops;
27014158570d3995008dc93a628004118b87a6bca01Alex Deymo  return true;
27114158570d3995008dc93a628004118b87a6bca01Alex Deymo}
27214158570d3995008dc93a628004118b87a6bca01Alex Deymo
27314158570d3995008dc93a628004118b87a6bca01Alex Deymobool ABGenerator::AddDataAndSetType(AnnotatedOperation* aop,
27414158570d3995008dc93a628004118b87a6bca01Alex Deymo                                    const string& target_part_path,
2758cc502dacbccdab96824d42287f230ce04004784Sen Jiang                                    BlobFileWriter* blob_file) {
276a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo  TEST_AND_RETURN_FALSE(aop->op.type() == InstallOperation::REPLACE ||
277a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo                        aop->op.type() == InstallOperation::REPLACE_BZ);
27814158570d3995008dc93a628004118b87a6bca01Alex Deymo
2793f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  brillo::Blob data(aop->op.dst_length());
28014158570d3995008dc93a628004118b87a6bca01Alex Deymo  vector<Extent> dst_extents;
28114158570d3995008dc93a628004118b87a6bca01Alex Deymo  ExtentsToVector(aop->op.dst_extents(), &dst_extents);
28214158570d3995008dc93a628004118b87a6bca01Alex Deymo  TEST_AND_RETURN_FALSE(utils::ReadExtents(target_part_path,
28314158570d3995008dc93a628004118b87a6bca01Alex Deymo                                           dst_extents,
28414158570d3995008dc93a628004118b87a6bca01Alex Deymo                                           &data,
28514158570d3995008dc93a628004118b87a6bca01Alex Deymo                                           data.size(),
28614158570d3995008dc93a628004118b87a6bca01Alex Deymo                                           kBlockSize));
28714158570d3995008dc93a628004118b87a6bca01Alex Deymo
2883f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  brillo::Blob data_bz;
28914158570d3995008dc93a628004118b87a6bca01Alex Deymo  TEST_AND_RETURN_FALSE(BzipCompress(data, &data_bz));
29014158570d3995008dc93a628004118b87a6bca01Alex Deymo  CHECK(!data_bz.empty());
29114158570d3995008dc93a628004118b87a6bca01Alex Deymo
2923f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  brillo::Blob* data_p = nullptr;
293a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo  InstallOperation_Type new_op_type;
29414158570d3995008dc93a628004118b87a6bca01Alex Deymo  if (data_bz.size() < data.size()) {
295a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo    new_op_type = InstallOperation::REPLACE_BZ;
29614158570d3995008dc93a628004118b87a6bca01Alex Deymo    data_p = &data_bz;
29714158570d3995008dc93a628004118b87a6bca01Alex Deymo  } else {
298a12ee11c78ac6d7c2605921a4006b6a7416e0c35Alex Deymo    new_op_type = InstallOperation::REPLACE;
29914158570d3995008dc93a628004118b87a6bca01Alex Deymo    data_p = &data;
30014158570d3995008dc93a628004118b87a6bca01Alex Deymo  }
30114158570d3995008dc93a628004118b87a6bca01Alex Deymo
3028cc502dacbccdab96824d42287f230ce04004784Sen Jiang  // If the operation doesn't point to a data blob, then we add it.
3038cc502dacbccdab96824d42287f230ce04004784Sen Jiang  if (aop->op.type() != new_op_type ||
3048cc502dacbccdab96824d42287f230ce04004784Sen Jiang      aop->op.data_length() != data_p->size()) {
30514158570d3995008dc93a628004118b87a6bca01Alex Deymo    aop->op.set_type(new_op_type);
3068cc502dacbccdab96824d42287f230ce04004784Sen Jiang    aop->SetOperationBlob(data_p, blob_file);
30714158570d3995008dc93a628004118b87a6bca01Alex Deymo  }
30814158570d3995008dc93a628004118b87a6bca01Alex Deymo
30914158570d3995008dc93a628004118b87a6bca01Alex Deymo  return true;
31014158570d3995008dc93a628004118b87a6bca01Alex Deymo}
31114158570d3995008dc93a628004118b87a6bca01Alex Deymo
31282352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiangbool ABGenerator::AddSourceHash(vector<AnnotatedOperation>* aops,
31382352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang                                const string& source_part_path) {
31482352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang  for (AnnotatedOperation& aop : *aops) {
31582352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    if (aop.op.src_extents_size() == 0)
31682352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang      continue;
31782352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang
31882352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    vector<Extent> src_extents;
31982352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    ExtentsToVector(aop.op.src_extents(), &src_extents);
32082352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    brillo::Blob src_data, src_hash;
32182352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    uint64_t src_length =
32282352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang        aop.op.has_src_length()
32382352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang            ? aop.op.src_length()
32482352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang            : BlocksInExtents(aop.op.src_extents()) * kBlockSize;
32582352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    TEST_AND_RETURN_FALSE(utils::ReadExtents(
32682352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang        source_part_path, src_extents, &src_data, src_length, kBlockSize));
32739910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo    TEST_AND_RETURN_FALSE(HashCalculator::RawHashOfData(src_data, &src_hash));
32882352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang    aop.op.set_src_sha256_hash(src_hash.data(), src_hash.size());
32982352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang  }
33082352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang  return true;
33182352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang}
33282352f97b4621dbf6af8308ff0b0b17b0968b53aSen Jiang
33314158570d3995008dc93a628004118b87a6bca01Alex Deymo}  // namespace chromeos_update_engine
334