Add zucchini support in update_engine
Support zucchini as a diff algorithm in delta generator.
Note we won't update the max support version until the
installation support is in place.
Bug: 197361113
Test: TH, generate a diff package
Change-Id: I92db1e7ab2ac4aef104a715c089b136f138064e9
diff --git a/payload_consumer/payload_constants.cc b/payload_consumer/payload_constants.cc
index d62a0ec..ad20f1e 100644
--- a/payload_consumer/payload_constants.cc
+++ b/payload_consumer/payload_constants.cc
@@ -34,6 +34,7 @@
const uint32_t kPuffdiffMinorPayloadVersion = 5;
const uint32_t kVerityMinorPayloadVersion = 6;
const uint32_t kPartialUpdateMinorPayloadVersion = 7;
+const uint32_t kZucchiniMinorPayloadVersion = 8;
const uint32_t kMinSupportedMinorPayloadVersion = kSourceMinorPayloadVersion;
const uint32_t kMaxSupportedMinorPayloadVersion =
@@ -66,7 +67,8 @@
return "PUFFDIFF";
case InstallOperation::BROTLI_BSDIFF:
return "BROTLI_BSDIFF";
-
+ case InstallOperation::ZUCCHINI:
+ return "ZUCCHINI";
case InstallOperation::BSDIFF:
case InstallOperation::MOVE:
NOTREACHED();
diff --git a/payload_consumer/payload_constants.h b/payload_consumer/payload_constants.h
index 03647ee..28edf4e 100644
--- a/payload_consumer/payload_constants.h
+++ b/payload_consumer/payload_constants.h
@@ -59,6 +59,9 @@
// The minor version that allows partial update, e.g. kernel only update.
extern const uint32_t kPartialUpdateMinorPayloadVersion;
+// The minor version that allows ZUCCHINI operation.
+extern const uint32_t kZucchiniMinorPayloadVersion;
+
// The minimum and maximum supported minor version.
extern const uint32_t kMinSupportedMinorPayloadVersion;
extern const uint32_t kMaxSupportedMinorPayloadVersion;
diff --git a/payload_generator/cow_size_estimator.cc b/payload_generator/cow_size_estimator.cc
index 01e9965..0578ada 100644
--- a/payload_generator/cow_size_estimator.cc
+++ b/payload_generator/cow_size_estimator.cc
@@ -150,6 +150,7 @@
case InstallOperation::BROTLI_BSDIFF:
case InstallOperation::PUFFDIFF:
case InstallOperation::BSDIFF:
+ case InstallOperation::ZUCCHINI:
// We might do something special by adding CowBsdiff to CowWriter.
// For now proceed the same way as normal REPLACE operation.
TEST_AND_RETURN_FALSE(
diff --git a/payload_generator/delta_diff_utils.cc b/payload_generator/delta_diff_utils.cc
index 7d36bec..46bf70e 100644
--- a/payload_generator/delta_diff_utils.cc
+++ b/payload_generator/delta_diff_utils.cc
@@ -47,7 +47,11 @@
#include <bsdiff/control_entry.h>
#include <bsdiff/patch_reader.h>
#include <bsdiff/patch_writer_factory.h>
+#include <puffin/brotli_util.h>
#include <puffin/utils.h>
+#include <zucchini/buffer_view.h>
+#include <zucchini/patch_writer.h>
+#include <zucchini/zucchini.h>
#include "update_engine/common/hash_calculator.h"
#include "update_engine/common/subprocess.h"
@@ -84,6 +88,10 @@
// memory intensive, so we limit these operations to 150 MiB.
const uint64_t kMaxPuffdiffDestinationSize = 150 * 1024 * 1024; // bytes
+// The maximum destination size allowed for zucchini. We are conservative here
+// as zucchini tends to use more peak memory.
+const uint64_t kMaxZucchiniDestinationSize = 150 * 1024 * 1024; // bytes
+
const int kBrotliCompressionQuality = 11;
// Storing a diff operation has more overhead over replace operation in the
@@ -181,6 +189,190 @@
} // namespace
namespace diff_utils {
+bool BestDiffGenerator::GenerateBestDiffOperation(AnnotatedOperation* aop,
+ brillo::Blob* data_blob) {
+ std::vector<std::pair<InstallOperation_Type, size_t>> diff_candidates = {
+ {InstallOperation::SOURCE_BSDIFF, kMaxBsdiffDestinationSize},
+ {InstallOperation::PUFFDIFF, kMaxPuffdiffDestinationSize},
+ {InstallOperation::ZUCCHINI, kMaxZucchiniDestinationSize},
+ };
+
+ return GenerateBestDiffOperation(diff_candidates, aop, data_blob);
+}
+
+bool BestDiffGenerator::GenerateBestDiffOperation(
+ const std::vector<std::pair<InstallOperation_Type, size_t>>&
+ diff_candidates,
+ AnnotatedOperation* aop,
+ brillo::Blob* data_blob) {
+ CHECK(aop);
+ CHECK(data_blob);
+
+ const auto& version = config_.version;
+ uint64_t input_bytes = utils::BlocksInExtents(src_extents_) * kBlockSize;
+
+ for (auto [op_type, limit] : diff_candidates) {
+ if (!version.OperationAllowed(op_type)) {
+ continue;
+ }
+
+ // Disable the specific diff algorithm when the data is too big.
+ if (input_bytes > limit) {
+ LOG(INFO) << op_type << " ignored, data too big: " << input_bytes
+ << " bytes";
+ continue;
+ }
+
+ // Prefer BROTLI_BSDIFF as it gives smaller patch size.
+ if (op_type == InstallOperation::SOURCE_BSDIFF &&
+ version.OperationAllowed(InstallOperation::BROTLI_BSDIFF)) {
+ op_type = InstallOperation::BROTLI_BSDIFF;
+ }
+
+ switch (op_type) {
+ case InstallOperation::SOURCE_BSDIFF:
+ case InstallOperation::BROTLI_BSDIFF:
+ TEST_AND_RETURN_FALSE(
+ TryBsdiffAndUpdateOperation(op_type, aop, data_blob));
+ break;
+ case InstallOperation::PUFFDIFF:
+ TEST_AND_RETURN_FALSE(TryPuffdiffAndUpdateOperation(aop, data_blob));
+ break;
+ case InstallOperation::ZUCCHINI:
+ TEST_AND_RETURN_FALSE(TryZucchiniAndUpdateOperation(aop, data_blob));
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ return true;
+}
+
+bool BestDiffGenerator::TryBsdiffAndUpdateOperation(
+ InstallOperation_Type operation_type,
+ AnnotatedOperation* aop,
+ brillo::Blob* data_blob) {
+ base::FilePath patch;
+ TEST_AND_RETURN_FALSE(base::CreateTemporaryFile(&patch));
+ ScopedPathUnlinker unlinker(patch.value());
+
+ std::unique_ptr<bsdiff::PatchWriterInterface> bsdiff_patch_writer;
+ if (operation_type == InstallOperation::BROTLI_BSDIFF) {
+ bsdiff_patch_writer =
+ bsdiff::CreateBSDF2PatchWriter(patch.value(),
+ bsdiff::CompressorType::kBrotli,
+ kBrotliCompressionQuality);
+ } else {
+ bsdiff_patch_writer = bsdiff::CreateBsdiffPatchWriter(patch.value());
+ }
+
+ brillo::Blob bsdiff_delta;
+ TEST_AND_RETURN_FALSE(0 == bsdiff::bsdiff(old_data_.data(),
+ old_data_.size(),
+ new_data_.data(),
+ new_data_.size(),
+ bsdiff_patch_writer.get(),
+ nullptr));
+
+ TEST_AND_RETURN_FALSE(utils::ReadFile(patch.value(), &bsdiff_delta));
+ TEST_AND_RETURN_FALSE(!bsdiff_delta.empty());
+
+ InstallOperation& operation = aop->op;
+ if (IsDiffOperationBetter(operation,
+ data_blob->size(),
+ bsdiff_delta.size(),
+ src_extents_.size())) {
+ if (config_.enable_vabc_xor) {
+ StoreExtents(src_extents_, operation.mutable_src_extents());
+ diff_utils::PopulateXorOps(aop, bsdiff_delta);
+ }
+ operation.set_type(operation_type);
+ *data_blob = std::move(bsdiff_delta);
+ }
+ return true;
+}
+
+bool BestDiffGenerator::TryPuffdiffAndUpdateOperation(AnnotatedOperation* aop,
+ brillo::Blob* data_blob) {
+ // Find all deflate positions inside the given extents and then put all
+ // deflates together because we have already read all the extents into
+ // one buffer.
+ vector<puffin::BitExtent> src_deflates;
+ TEST_AND_RETURN_FALSE(deflate_utils::FindAndCompactDeflates(
+ src_extents_, old_deflates_, &src_deflates));
+
+ vector<puffin::BitExtent> dst_deflates;
+ TEST_AND_RETURN_FALSE(deflate_utils::FindAndCompactDeflates(
+ dst_extents_, new_deflates_, &dst_deflates));
+
+ puffin::RemoveEqualBitExtents(
+ old_data_, new_data_, &src_deflates, &dst_deflates);
+
+ // See crbug.com/915559.
+ if (config_.version.minor <= kPuffdiffMinorPayloadVersion) {
+ TEST_AND_RETURN_FALSE(
+ puffin::RemoveDeflatesWithBadDistanceCaches(old_data_, &src_deflates));
+
+ TEST_AND_RETURN_FALSE(
+ puffin::RemoveDeflatesWithBadDistanceCaches(new_data_, &dst_deflates));
+ }
+
+ // Only Puffdiff if both files have at least one deflate left.
+ if (!src_deflates.empty() && !dst_deflates.empty()) {
+ brillo::Blob puffdiff_delta;
+ ScopedTempFile temp_file("puffdiff-delta.XXXXXX");
+ // Perform PuffDiff operation.
+ TEST_AND_RETURN_FALSE(puffin::PuffDiff(old_data_,
+ new_data_,
+ src_deflates,
+ dst_deflates,
+ temp_file.path(),
+ &puffdiff_delta));
+ TEST_AND_RETURN_FALSE(!puffdiff_delta.empty());
+
+ InstallOperation& operation = aop->op;
+ if (IsDiffOperationBetter(operation,
+ data_blob->size(),
+ puffdiff_delta.size(),
+ src_extents_.size())) {
+ operation.set_type(InstallOperation::PUFFDIFF);
+ *data_blob = std::move(puffdiff_delta);
+ }
+ }
+ return true;
+}
+
+bool BestDiffGenerator::TryZucchiniAndUpdateOperation(AnnotatedOperation* aop,
+ brillo::Blob* data_blob) {
+ zucchini::ConstBufferView src_bytes(old_data_.data(), old_data_.size());
+ zucchini::ConstBufferView dst_bytes(new_data_.data(), new_data_.size());
+
+ zucchini::EnsemblePatchWriter patch_writer(src_bytes, dst_bytes);
+ auto status = zucchini::GenerateBuffer(src_bytes, dst_bytes, &patch_writer);
+ TEST_AND_RETURN_FALSE(status == zucchini::status::kStatusSuccess);
+
+ brillo::Blob zucchini_delta(patch_writer.SerializedSize());
+ patch_writer.SerializeInto({zucchini_delta.data(), zucchini_delta.size()});
+
+ // Compress the delta with brotli.
+ // TODO(197361113) support compressing the delta with different algorithms,
+ // similar to the usage in puffin.
+ brillo::Blob compressed_delta;
+ TEST_AND_RETURN_FALSE(puffin::BrotliEncode(
+ zucchini_delta.data(), zucchini_delta.size(), &compressed_delta));
+
+ InstallOperation& operation = aop->op;
+ if (IsDiffOperationBetter(operation,
+ data_blob->size(),
+ zucchini_delta.size(),
+ src_extents_.size())) {
+ operation.set_type(InstallOperation::ZUCCHINI);
+ *data_blob = std::move(zucchini_delta);
+ }
+
+ return true;
+}
// This class encapsulates a file delta processing thread work. The
// processor computes the delta between the source and target files;
diff --git a/payload_generator/delta_diff_utils.h b/payload_generator/delta_diff_utils.h
index f284530..b335e2a 100644
--- a/payload_generator/delta_diff_utils.h
+++ b/payload_generator/delta_diff_utils.h
@@ -19,6 +19,7 @@
#include <map>
#include <string>
+#include <utility>
#include <vector>
#include <brillo/secure_blob.h>
@@ -99,16 +100,17 @@
// fills in |out_op|. If there's no change in old and new files, it creates a
// MOVE or SOURCE_COPY operation. If there is a change, the smallest of the
// operations allowed in the given |version| (REPLACE, REPLACE_BZ, BSDIFF,
-// SOURCE_BSDIFF, or PUFFDIFF) wins.
+// SOURCE_BSDIFF, PUFFDIFF or ZUCCHINI) wins.
// |new_extents| must not be empty. |old_deflates| and |new_deflates| are all
// the deflate locations in |old_part| and |new_part|. Returns true on success.
+// TODO(197361113) Move logic to calculate deflates inside puffin.
bool ReadExtentsToDiff(const std::string& old_part,
const std::string& new_part,
const std::vector<Extent>& old_extents,
const std::vector<Extent>& new_extents,
const std::vector<puffin::BitExtent>& old_deflates,
const std::vector<puffin::BitExtent>& new_deflates,
- const PayloadGenerationConfig& version,
+ const PayloadGenerationConfig& config,
brillo::Blob* out_data,
AnnotatedOperation* out_op);
@@ -158,6 +160,55 @@
return PopulateXorOps(aop, patch_data.data(), patch_data.size());
}
+// A utility class that tries different algorithms and pick the patch with the
+// smallest size.
+class BestDiffGenerator {
+ public:
+ BestDiffGenerator(const brillo::Blob& old_data,
+ const brillo::Blob& new_data,
+ const std::vector<Extent>& src_extents,
+ const std::vector<Extent>& dst_extents,
+ const std::vector<puffin::BitExtent>& old_deflates,
+ const std::vector<puffin::BitExtent>& new_deflates,
+ const PayloadGenerationConfig& config)
+ : old_data_(old_data),
+ new_data_(new_data),
+ src_extents_(src_extents),
+ dst_extents_(dst_extents),
+ old_deflates_(old_deflates),
+ new_deflates_(new_deflates),
+ config_(config) {}
+
+ // Tries different algorithms and compares their patch sizes with the
+ // compressed full operation data in |data_blob|. If the size is smaller,
+ // updates the operation type in |aop| and bytes in |data_blob|.
+ bool GenerateBestDiffOperation(AnnotatedOperation* aop,
+ brillo::Blob* data_blob);
+
+ bool GenerateBestDiffOperation(
+ const std::vector<std::pair<InstallOperation_Type, size_t>>&
+ diff_candidates,
+ AnnotatedOperation* aop,
+ brillo::Blob* data_blob);
+
+ private:
+ bool TryBsdiffAndUpdateOperation(InstallOperation_Type operation_type,
+ AnnotatedOperation* aop,
+ brillo::Blob* data_blob);
+ bool TryPuffdiffAndUpdateOperation(AnnotatedOperation* aop,
+ brillo::Blob* data_blob);
+ bool TryZucchiniAndUpdateOperation(AnnotatedOperation* aop,
+ brillo::Blob* data_blob);
+
+ const brillo::Blob& old_data_;
+ const brillo::Blob& new_data_;
+ const std::vector<Extent>& src_extents_;
+ const std::vector<Extent>& dst_extents_;
+ const std::vector<puffin::BitExtent>& old_deflates_;
+ const std::vector<puffin::BitExtent>& new_deflates_;
+ const PayloadGenerationConfig& config_;
+};
+
} // namespace diff_utils
} // namespace chromeos_update_engine
diff --git a/payload_generator/delta_diff_utils_unittest.cc b/payload_generator/delta_diff_utils_unittest.cc
index 5e7d6f0..ede6408 100644
--- a/payload_generator/delta_diff_utils_unittest.cc
+++ b/payload_generator/delta_diff_utils_unittest.cc
@@ -306,6 +306,123 @@
ASSERT_EQ(InstallOperation::SOURCE_BSDIFF, op.type());
}
+TEST_F(DeltaDiffUtilsTest, BrotliBsdiffTest) {
+ // Makes sure SOURCE_BSDIFF operations are emitted whenever src_ops_allowed
+ // is true. It is the same setup as BsdiffSmallTest, which checks
+ // that the operation is well-formed.
+ brillo::Blob data_blob(kBlockSize);
+ test_utils::FillWithData(&data_blob);
+
+ // The old file is on a different block than the new one.
+ vector<Extent> old_extents = {ExtentForRange(1, 1)};
+ vector<Extent> new_extents = {ExtentForRange(2, 1)};
+
+ ASSERT_TRUE(WriteExtents(old_part_.path, old_extents, kBlockSize, data_blob));
+ // Modify one byte in the new file.
+ data_blob[0]++;
+ ASSERT_TRUE(WriteExtents(new_part_.path, new_extents, kBlockSize, data_blob));
+
+ brillo::Blob data;
+ AnnotatedOperation aop;
+ ASSERT_TRUE(diff_utils::ReadExtentsToDiff(
+ old_part_.path,
+ new_part_.path,
+ old_extents,
+ new_extents,
+ {}, // old_deflates
+ {}, // new_deflates
+ {.version = PayloadVersion(kBrilloMajorPayloadVersion,
+ kBrotliBsdiffMinorPayloadVersion)},
+ &data,
+ &aop));
+ auto& op = aop.op;
+ ASSERT_FALSE(data.empty());
+ ASSERT_TRUE(op.has_type());
+ ASSERT_EQ(InstallOperation::BROTLI_BSDIFF, op.type());
+}
+
+TEST_F(DeltaDiffUtilsTest, GenerateBestDiffOperation_Zucchini) {
+ // Makes sure SOURCE_BSDIFF operations are emitted whenever src_ops_allowed
+ // is true. It is the same setup as BsdiffSmallTest, which checks
+ // that the operation is well-formed.
+ brillo::Blob dst_data_blob(kBlockSize);
+ test_utils::FillWithData(&dst_data_blob);
+
+ // The old file is on a different block than the new one.
+ vector<Extent> old_extents = {ExtentForRange(1, 1)};
+ vector<Extent> new_extents = {ExtentForRange(2, 1)};
+
+ ASSERT_TRUE(
+ WriteExtents(old_part_.path, old_extents, kBlockSize, dst_data_blob));
+ // Modify one byte in the new file.
+ brillo::Blob src_data_blob = dst_data_blob;
+ src_data_blob[0]++;
+ ASSERT_TRUE(
+ WriteExtents(new_part_.path, new_extents, kBlockSize, src_data_blob));
+
+ brillo::Blob data = dst_data_blob; // Fake the full operation
+ AnnotatedOperation aop;
+
+ diff_utils::BestDiffGenerator best_diff_generator(
+ src_data_blob,
+ dst_data_blob,
+ old_extents,
+ new_extents,
+ {},
+ {},
+ {.version = PayloadVersion(kBrilloMajorPayloadVersion,
+ kZucchiniMinorPayloadVersion)});
+ ASSERT_TRUE(best_diff_generator.GenerateBestDiffOperation(
+ {{InstallOperation::ZUCCHINI, 1024 * 1024}}, &aop, &data));
+
+ auto& op = aop.op;
+ ASSERT_FALSE(data.empty());
+ ASSERT_TRUE(op.has_type());
+ ASSERT_EQ(InstallOperation::ZUCCHINI, op.type());
+}
+
+TEST_F(DeltaDiffUtilsTest, GenerateBestDiffOperation_FullOperationBetter) {
+ // Makes sure SOURCE_BSDIFF operations are emitted whenever src_ops_allowed
+ // is true. It is the same setup as BsdiffSmallTest, which checks
+ // that the operation is well-formed.
+ brillo::Blob dst_data_blob(kBlockSize);
+ test_utils::FillWithData(&dst_data_blob);
+
+ // The old file is on a different block than the new one.
+ vector<Extent> old_extents = {ExtentForRange(1, 1)};
+ vector<Extent> new_extents = {ExtentForRange(2, 1)};
+
+ ASSERT_TRUE(
+ WriteExtents(old_part_.path, old_extents, kBlockSize, dst_data_blob));
+ // Modify one byte in the new file.
+ brillo::Blob src_data_blob = dst_data_blob;
+ src_data_blob[0]++;
+ ASSERT_TRUE(
+ WriteExtents(new_part_.path, new_extents, kBlockSize, src_data_blob));
+
+ brillo::Blob data(1);
+ test_utils::FillWithData(&data); // Fake the full operation
+ AnnotatedOperation aop;
+ aop.op.set_type(InstallOperation::REPLACE_XZ);
+
+ diff_utils::BestDiffGenerator best_diff_generator(
+ src_data_blob,
+ dst_data_blob,
+ old_extents,
+ new_extents,
+ {},
+ {},
+ {.version = PayloadVersion(kBrilloMajorPayloadVersion,
+ kZucchiniMinorPayloadVersion)});
+ ASSERT_TRUE(best_diff_generator.GenerateBestDiffOperation(
+ {{InstallOperation::ZUCCHINI, 1024 * 1024}}, &aop, &data));
+
+ auto& op = aop.op;
+ ASSERT_EQ(1u, data.size());
+ ASSERT_TRUE(op.has_type());
+ ASSERT_EQ(InstallOperation::REPLACE_XZ, op.type());
+}
+
TEST_F(DeltaDiffUtilsTest, PreferReplaceTest) {
brillo::Blob data_blob(kBlockSize);
vector<Extent> extents = {ExtentForRange(1, 1)};
diff --git a/payload_generator/payload_generation_config.cc b/payload_generator/payload_generation_config.cc
index 2cd2ebc..7484755 100644
--- a/payload_generator/payload_generation_config.cc
+++ b/payload_generator/payload_generation_config.cc
@@ -238,7 +238,8 @@
minor == kBrotliBsdiffMinorPayloadVersion ||
minor == kPuffdiffMinorPayloadVersion ||
minor == kVerityMinorPayloadVersion ||
- minor == kPartialUpdateMinorPayloadVersion);
+ minor == kPartialUpdateMinorPayloadVersion ||
+ minor == kZucchiniMinorPayloadVersion);
return true;
}
@@ -270,6 +271,9 @@
case InstallOperation::PUFFDIFF:
return minor >= kPuffdiffMinorPayloadVersion;
+ case InstallOperation::ZUCCHINI:
+ return minor >= kZucchiniMinorPayloadVersion;
+
case InstallOperation::MOVE:
case InstallOperation::BSDIFF:
NOTREACHED();
diff --git a/scripts/update_payload/common.py b/scripts/update_payload/common.py
index b934cf8..7c6ec8f 100644
--- a/scripts/update_payload/common.py
+++ b/scripts/update_payload/common.py
@@ -62,8 +62,9 @@
REPLACE_XZ = _CLASS.REPLACE_XZ
PUFFDIFF = _CLASS.PUFFDIFF
BROTLI_BSDIFF = _CLASS.BROTLI_BSDIFF
+ ZUCCHINI = _CLASS.ZUCCHINI
ALL = (REPLACE, REPLACE_BZ, SOURCE_COPY, SOURCE_BSDIFF, ZERO,
- DISCARD, REPLACE_XZ, PUFFDIFF, BROTLI_BSDIFF)
+ DISCARD, REPLACE_XZ, PUFFDIFF, BROTLI_BSDIFF, ZUCCHINI)
NAMES = {
REPLACE: 'REPLACE',
REPLACE_BZ: 'REPLACE_BZ',
@@ -74,6 +75,7 @@
REPLACE_XZ: 'REPLACE_XZ',
PUFFDIFF: 'PUFFDIFF',
BROTLI_BSDIFF: 'BROTLI_BSDIFF',
+ ZUCCHINI: 'ZUCCHINI',
}
def __init__(self):
diff --git a/scripts/update_payload/update_metadata_pb2.py b/scripts/update_payload/update_metadata_pb2.py
index a8f1bff..b62a67a 100644
--- a/scripts/update_payload/update_metadata_pb2.py
+++ b/scripts/update_payload/update_metadata_pb2.py
@@ -20,7 +20,7 @@
package='chromeos_update_engine',
syntax='proto2',
serialized_options=_b('H\003'),
- serialized_pb=_b('\n\x15update_metadata.proto\x12\x16\x63hromeos_update_engine\"1\n\x06\x45xtent\x12\x13\n\x0bstart_block\x18\x01 \x01(\x04\x12\x12\n\nnum_blocks\x18\x02 \x01(\x04\"\x9f\x01\n\nSignatures\x12@\n\nsignatures\x18\x01 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x1aO\n\tSignature\x12\x13\n\x07version\x18\x01 \x01(\rB\x02\x18\x01\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x1f\n\x17unpadded_signature_size\x18\x03 \x01(\x07\"+\n\rPartitionInfo\x12\x0c\n\x04size\x18\x01 \x01(\x04\x12\x0c\n\x04hash\x18\x02 \x01(\x0c\"\x8f\x01\n\tImageInfo\x12\x11\n\x05\x62oard\x18\x01 \x01(\tB\x02\x18\x01\x12\x0f\n\x03key\x18\x02 \x01(\tB\x02\x18\x01\x12\x13\n\x07\x63hannel\x18\x03 \x01(\tB\x02\x18\x01\x12\x13\n\x07version\x18\x04 \x01(\tB\x02\x18\x01\x12\x19\n\rbuild_channel\x18\x05 \x01(\tB\x02\x18\x01\x12\x19\n\rbuild_version\x18\x06 \x01(\tB\x02\x18\x01\"\xee\x03\n\x10InstallOperation\x12;\n\x04type\x18\x01 \x02(\x0e\x32-.chromeos_update_engine.InstallOperation.Type\x12\x13\n\x0b\x64\x61ta_offset\x18\x02 \x01(\x04\x12\x13\n\x0b\x64\x61ta_length\x18\x03 \x01(\x04\x12\x33\n\x0bsrc_extents\x18\x04 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_length\x18\x05 \x01(\x04\x12\x33\n\x0b\x64st_extents\x18\x06 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\ndst_length\x18\x07 \x01(\x04\x12\x18\n\x10\x64\x61ta_sha256_hash\x18\x08 \x01(\x0c\x12\x17\n\x0fsrc_sha256_hash\x18\t \x01(\x0c\"\xad\x01\n\x04Type\x12\x0b\n\x07REPLACE\x10\x00\x12\x0e\n\nREPLACE_BZ\x10\x01\x12\x0c\n\x04MOVE\x10\x02\x1a\x02\x08\x01\x12\x0e\n\x06\x42SDIFF\x10\x03\x1a\x02\x08\x01\x12\x0f\n\x0bSOURCE_COPY\x10\x04\x12\x11\n\rSOURCE_BSDIFF\x10\x05\x12\x0e\n\nREPLACE_XZ\x10\x08\x12\x08\n\x04ZERO\x10\x06\x12\x0b\n\x07\x44ISCARD\x10\x07\x12\x11\n\rBROTLI_BSDIFF\x10\n\x12\x0c\n\x08PUFFDIFF\x10\t\"\x81\x02\n\x11\x43owMergeOperation\x12<\n\x04type\x18\x01 \x01(\x0e\x32..chromeos_update_engine.CowMergeOperation.Type\x12\x32\n\nsrc_extent\x18\x02 \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\ndst_extent\x18\x03 \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_offset\x18\x04 \x01(\x04\"2\n\x04Type\x12\x0c\n\x08\x43OW_COPY\x10\x00\x12\x0b\n\x07\x43OW_XOR\x10\x01\x12\x0f\n\x0b\x43OW_REPLACE\x10\x02\"\xc8\x06\n\x0fPartitionUpdate\x12\x16\n\x0epartition_name\x18\x01 \x02(\t\x12\x17\n\x0frun_postinstall\x18\x02 \x01(\x08\x12\x18\n\x10postinstall_path\x18\x03 \x01(\t\x12\x17\n\x0f\x66ilesystem_type\x18\x04 \x01(\t\x12M\n\x17new_partition_signature\x18\x05 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x12\x41\n\x12old_partition_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x41\n\x12new_partition_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12<\n\noperations\x18\x08 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x1c\n\x14postinstall_optional\x18\t \x01(\x08\x12=\n\x15hash_tree_data_extent\x18\n \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x38\n\x10hash_tree_extent\x18\x0b \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x1b\n\x13hash_tree_algorithm\x18\x0c \x01(\t\x12\x16\n\x0ehash_tree_salt\x18\r \x01(\x0c\x12\x37\n\x0f\x66\x65\x63_data_extent\x18\x0e \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\nfec_extent\x18\x0f \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x14\n\tfec_roots\x18\x10 \x01(\r:\x01\x32\x12\x0f\n\x07version\x18\x11 \x01(\t\x12\x43\n\x10merge_operations\x18\x12 \x03(\x0b\x32).chromeos_update_engine.CowMergeOperation\x12\x19\n\x11\x65stimate_cow_size\x18\x13 \x01(\x04\"L\n\x15\x44ynamicPartitionGroup\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04size\x18\x02 \x01(\x04\x12\x17\n\x0fpartition_names\x18\x03 \x03(\t\"\xd5\x01\n\x18\x44ynamicPartitionMetadata\x12=\n\x06groups\x18\x01 \x03(\x0b\x32-.chromeos_update_engine.DynamicPartitionGroup\x12\x18\n\x10snapshot_enabled\x18\x02 \x01(\x08\x12\x14\n\x0cvabc_enabled\x18\x03 \x01(\x08\x12\x1e\n\x16vabc_compression_param\x18\x04 \x01(\t\x12\x13\n\x0b\x63ow_version\x18\x05 \x01(\r\x12\x15\n\rvabc_optional\x18\x06 \x01(\x08\"c\n\x08\x41pexInfo\x12\x14\n\x0cpackage_name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\x03\x12\x15\n\ris_compressed\x18\x03 \x01(\x08\x12\x19\n\x11\x64\x65\x63ompressed_size\x18\x04 \x01(\x03\"C\n\x0c\x41pexMetadata\x12\x33\n\tapex_info\x18\x01 \x03(\x0b\x32 .chromeos_update_engine.ApexInfo\"\x9e\x07\n\x14\x44\x65ltaArchiveManifest\x12H\n\x12install_operations\x18\x01 \x03(\x0b\x32(.chromeos_update_engine.InstallOperationB\x02\x18\x01\x12O\n\x19kernel_install_operations\x18\x02 \x03(\x0b\x32(.chromeos_update_engine.InstallOperationB\x02\x18\x01\x12\x18\n\nblock_size\x18\x03 \x01(\r:\x04\x34\x30\x39\x36\x12\x19\n\x11signatures_offset\x18\x04 \x01(\x04\x12\x17\n\x0fsignatures_size\x18\x05 \x01(\x04\x12\x42\n\x0fold_kernel_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fnew_kernel_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fold_rootfs_info\x18\x08 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fnew_rootfs_info\x18\t \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12=\n\x0eold_image_info\x18\n \x01(\x0b\x32!.chromeos_update_engine.ImageInfoB\x02\x18\x01\x12=\n\x0enew_image_info\x18\x0b \x01(\x0b\x32!.chromeos_update_engine.ImageInfoB\x02\x18\x01\x12\x18\n\rminor_version\x18\x0c \x01(\r:\x01\x30\x12;\n\npartitions\x18\r \x03(\x0b\x32\'.chromeos_update_engine.PartitionUpdate\x12\x15\n\rmax_timestamp\x18\x0e \x01(\x03\x12T\n\x1a\x64ynamic_partition_metadata\x18\x0f \x01(\x0b\x32\x30.chromeos_update_engine.DynamicPartitionMetadata\x12\x16\n\x0epartial_update\x18\x10 \x01(\x08\x12\x33\n\tapex_info\x18\x11 \x03(\x0b\x32 .chromeos_update_engine.ApexInfoB\x02H\x03')
+ serialized_pb=_b('\n\x15update_metadata.proto\x12\x16\x63hromeos_update_engine\"1\n\x06\x45xtent\x12\x13\n\x0bstart_block\x18\x01 \x01(\x04\x12\x12\n\nnum_blocks\x18\x02 \x01(\x04\"\x9f\x01\n\nSignatures\x12@\n\nsignatures\x18\x01 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x1aO\n\tSignature\x12\x13\n\x07version\x18\x01 \x01(\rB\x02\x18\x01\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x1f\n\x17unpadded_signature_size\x18\x03 \x01(\x07\"+\n\rPartitionInfo\x12\x0c\n\x04size\x18\x01 \x01(\x04\x12\x0c\n\x04hash\x18\x02 \x01(\x0c\"\x8f\x01\n\tImageInfo\x12\x11\n\x05\x62oard\x18\x01 \x01(\tB\x02\x18\x01\x12\x0f\n\x03key\x18\x02 \x01(\tB\x02\x18\x01\x12\x13\n\x07\x63hannel\x18\x03 \x01(\tB\x02\x18\x01\x12\x13\n\x07version\x18\x04 \x01(\tB\x02\x18\x01\x12\x19\n\rbuild_channel\x18\x05 \x01(\tB\x02\x18\x01\x12\x19\n\rbuild_version\x18\x06 \x01(\tB\x02\x18\x01\"\xfc\x03\n\x10InstallOperation\x12;\n\x04type\x18\x01 \x02(\x0e\x32-.chromeos_update_engine.InstallOperation.Type\x12\x13\n\x0b\x64\x61ta_offset\x18\x02 \x01(\x04\x12\x13\n\x0b\x64\x61ta_length\x18\x03 \x01(\x04\x12\x33\n\x0bsrc_extents\x18\x04 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_length\x18\x05 \x01(\x04\x12\x33\n\x0b\x64st_extents\x18\x06 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\ndst_length\x18\x07 \x01(\x04\x12\x18\n\x10\x64\x61ta_sha256_hash\x18\x08 \x01(\x0c\x12\x17\n\x0fsrc_sha256_hash\x18\t \x01(\x0c\"\xbb\x01\n\x04Type\x12\x0b\n\x07REPLACE\x10\x00\x12\x0e\n\nREPLACE_BZ\x10\x01\x12\x0c\n\x04MOVE\x10\x02\x1a\x02\x08\x01\x12\x0e\n\x06\x42SDIFF\x10\x03\x1a\x02\x08\x01\x12\x0f\n\x0bSOURCE_COPY\x10\x04\x12\x11\n\rSOURCE_BSDIFF\x10\x05\x12\x0e\n\nREPLACE_XZ\x10\x08\x12\x08\n\x04ZERO\x10\x06\x12\x0b\n\x07\x44ISCARD\x10\x07\x12\x11\n\rBROTLI_BSDIFF\x10\n\x12\x0c\n\x08PUFFDIFF\x10\t\x12\x0c\n\x08ZUCCHINI\x10\x0b\"\x81\x02\n\x11\x43owMergeOperation\x12<\n\x04type\x18\x01 \x01(\x0e\x32..chromeos_update_engine.CowMergeOperation.Type\x12\x32\n\nsrc_extent\x18\x02 \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\ndst_extent\x18\x03 \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_offset\x18\x04 \x01(\r\"2\n\x04Type\x12\x0c\n\x08\x43OW_COPY\x10\x00\x12\x0b\n\x07\x43OW_XOR\x10\x01\x12\x0f\n\x0b\x43OW_REPLACE\x10\x02\"\xc8\x06\n\x0fPartitionUpdate\x12\x16\n\x0epartition_name\x18\x01 \x02(\t\x12\x17\n\x0frun_postinstall\x18\x02 \x01(\x08\x12\x18\n\x10postinstall_path\x18\x03 \x01(\t\x12\x17\n\x0f\x66ilesystem_type\x18\x04 \x01(\t\x12M\n\x17new_partition_signature\x18\x05 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x12\x41\n\x12old_partition_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x41\n\x12new_partition_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12<\n\noperations\x18\x08 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x1c\n\x14postinstall_optional\x18\t \x01(\x08\x12=\n\x15hash_tree_data_extent\x18\n \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x38\n\x10hash_tree_extent\x18\x0b \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x1b\n\x13hash_tree_algorithm\x18\x0c \x01(\t\x12\x16\n\x0ehash_tree_salt\x18\r \x01(\x0c\x12\x37\n\x0f\x66\x65\x63_data_extent\x18\x0e \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\nfec_extent\x18\x0f \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x14\n\tfec_roots\x18\x10 \x01(\r:\x01\x32\x12\x0f\n\x07version\x18\x11 \x01(\t\x12\x43\n\x10merge_operations\x18\x12 \x03(\x0b\x32).chromeos_update_engine.CowMergeOperation\x12\x19\n\x11\x65stimate_cow_size\x18\x13 \x01(\x04\"L\n\x15\x44ynamicPartitionGroup\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04size\x18\x02 \x01(\x04\x12\x17\n\x0fpartition_names\x18\x03 \x03(\t\"\xbe\x01\n\x18\x44ynamicPartitionMetadata\x12=\n\x06groups\x18\x01 \x03(\x0b\x32-.chromeos_update_engine.DynamicPartitionGroup\x12\x18\n\x10snapshot_enabled\x18\x02 \x01(\x08\x12\x14\n\x0cvabc_enabled\x18\x03 \x01(\x08\x12\x1e\n\x16vabc_compression_param\x18\x04 \x01(\t\x12\x13\n\x0b\x63ow_version\x18\x05 \x01(\r\"c\n\x08\x41pexInfo\x12\x14\n\x0cpackage_name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\x03\x12\x15\n\ris_compressed\x18\x03 \x01(\x08\x12\x19\n\x11\x64\x65\x63ompressed_size\x18\x04 \x01(\x03\"C\n\x0c\x41pexMetadata\x12\x33\n\tapex_info\x18\x01 \x03(\x0b\x32 .chromeos_update_engine.ApexInfo\"\x9e\x07\n\x14\x44\x65ltaArchiveManifest\x12H\n\x12install_operations\x18\x01 \x03(\x0b\x32(.chromeos_update_engine.InstallOperationB\x02\x18\x01\x12O\n\x19kernel_install_operations\x18\x02 \x03(\x0b\x32(.chromeos_update_engine.InstallOperationB\x02\x18\x01\x12\x18\n\nblock_size\x18\x03 \x01(\r:\x04\x34\x30\x39\x36\x12\x19\n\x11signatures_offset\x18\x04 \x01(\x04\x12\x17\n\x0fsignatures_size\x18\x05 \x01(\x04\x12\x42\n\x0fold_kernel_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fnew_kernel_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fold_rootfs_info\x18\x08 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fnew_rootfs_info\x18\t \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12=\n\x0eold_image_info\x18\n \x01(\x0b\x32!.chromeos_update_engine.ImageInfoB\x02\x18\x01\x12=\n\x0enew_image_info\x18\x0b \x01(\x0b\x32!.chromeos_update_engine.ImageInfoB\x02\x18\x01\x12\x18\n\rminor_version\x18\x0c \x01(\r:\x01\x30\x12;\n\npartitions\x18\r \x03(\x0b\x32\'.chromeos_update_engine.PartitionUpdate\x12\x15\n\rmax_timestamp\x18\x0e \x01(\x03\x12T\n\x1a\x64ynamic_partition_metadata\x18\x0f \x01(\x0b\x32\x30.chromeos_update_engine.DynamicPartitionMetadata\x12\x16\n\x0epartial_update\x18\x10 \x01(\x08\x12\x33\n\tapex_info\x18\x11 \x03(\x0b\x32 .chromeos_update_engine.ApexInfoB\x02H\x03')
)
@@ -75,11 +75,15 @@
name='PUFFDIFF', index=10, number=9,
serialized_options=None,
type=None),
+ _descriptor.EnumValueDescriptor(
+ name='ZUCCHINI', index=11, number=11,
+ serialized_options=None,
+ type=None),
],
containing_type=None,
serialized_options=None,
serialized_start=775,
- serialized_end=948,
+ serialized_end=962,
)
_sym_db.RegisterEnumDescriptor(_INSTALLOPERATION_TYPE)
@@ -104,8 +108,8 @@
],
containing_type=None,
serialized_options=None,
- serialized_start=1158,
- serialized_end=1208,
+ serialized_start=1172,
+ serialized_end=1222,
)
_sym_db.RegisterEnumDescriptor(_COWMERGEOPERATION_TYPE)
@@ -411,7 +415,7 @@
oneofs=[
],
serialized_start=454,
- serialized_end=948,
+ serialized_end=962,
)
@@ -445,7 +449,7 @@
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='src_offset', full_name='chromeos_update_engine.CowMergeOperation.src_offset', index=3,
- number=4, type=4, cpp_type=4, label=1,
+ number=4, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
@@ -463,8 +467,8 @@
extension_ranges=[],
oneofs=[
],
- serialized_start=951,
- serialized_end=1208,
+ serialized_start=965,
+ serialized_end=1222,
)
@@ -620,8 +624,8 @@
extension_ranges=[],
oneofs=[
],
- serialized_start=1211,
- serialized_end=2051,
+ serialized_start=1225,
+ serialized_end=2065,
)
@@ -665,8 +669,8 @@
extension_ranges=[],
oneofs=[
],
- serialized_start=2053,
- serialized_end=2129,
+ serialized_start=2067,
+ serialized_end=2143,
)
@@ -712,13 +716,6 @@
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
- _descriptor.FieldDescriptor(
- name='vabc_optional', full_name='chromeos_update_engine.DynamicPartitionMetadata.vabc_optional', index=5,
- number=6, type=8, cpp_type=7, label=1,
- has_default_value=False, default_value=False,
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
@@ -731,8 +728,8 @@
extension_ranges=[],
oneofs=[
],
- serialized_start=2132,
- serialized_end=2345,
+ serialized_start=2146,
+ serialized_end=2336,
)
@@ -783,8 +780,8 @@
extension_ranges=[],
oneofs=[
],
- serialized_start=2347,
- serialized_end=2446,
+ serialized_start=2338,
+ serialized_end=2437,
)
@@ -814,8 +811,8 @@
extension_ranges=[],
oneofs=[
],
- serialized_start=2448,
- serialized_end=2515,
+ serialized_start=2439,
+ serialized_end=2506,
)
@@ -957,8 +954,8 @@
extension_ranges=[],
oneofs=[
],
- serialized_start=2518,
- serialized_end=3444,
+ serialized_start=2509,
+ serialized_end=3435,
)
_SIGNATURES_SIGNATURE.containing_type = _SIGNATURES
diff --git a/update_metadata.proto b/update_metadata.proto
index 533f6f0..6164a4d 100644
--- a/update_metadata.proto
+++ b/update_metadata.proto
@@ -187,6 +187,9 @@
// On minor version 5 or newer, these operations are supported:
PUFFDIFF = 9; // The data is in puffdiff format.
+
+ // On minor version 8 or newer, these operations are supported:
+ ZUCCHINI = 11;
}
required Type type = 1;