Support generation of partial updates
Add a new minor version kPartialUpdateMinorPayloadVersion for
partial updates. Also, we always treat the partial update as a
delta update in payload consumer, so new update_engine can
perform minor version check correctly.
Conceptually, partial update is indeed a delta update; because we
need to copy | use the untouched partitions. Since the payload for
the partial update doesn't carry old partition info, old update
engines will treat them as full update. So old UE will also fail
the minor version check correctly; because we always expect
kFullPayloadMinorVersion for full updates.
Bug: 157778739
Test: generate & apply partial full|incremental updates, generate
regular updates, unittests pass
Change-Id: I7f8365cf99098269150dd08e028120354944f3c6
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index 68f38df..d8f0ef5 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -1579,9 +1579,12 @@
});
// The presence of an old partition hash is the sole indicator for a delta
- // update.
+ // update. Also, always treat the partial update as delta so that we can
+ // perform the minor version check correctly.
InstallPayloadType actual_payload_type =
- has_old_fields ? InstallPayloadType::kDelta : InstallPayloadType::kFull;
+ (has_old_fields || manifest_.partial_update())
+ ? InstallPayloadType::kDelta
+ : InstallPayloadType::kFull;
if (payload_->type == InstallPayloadType::kUnknown) {
LOG(INFO) << "Detected a '"
diff --git a/payload_consumer/payload_constants.cc b/payload_consumer/payload_constants.cc
index 1c987bd..28404fe 100644
--- a/payload_consumer/payload_constants.cc
+++ b/payload_consumer/payload_constants.cc
@@ -33,6 +33,7 @@
const uint32_t kBrotliBsdiffMinorPayloadVersion = 4;
const uint32_t kPuffdiffMinorPayloadVersion = 5;
const uint32_t kVerityMinorPayloadVersion = 6;
+const uint32_t kPartialUpdateMinorPayloadVersion = 7;
const uint32_t kMinSupportedMinorPayloadVersion = kSourceMinorPayloadVersion;
const uint32_t kMaxSupportedMinorPayloadVersion = kVerityMinorPayloadVersion;
diff --git a/payload_consumer/payload_constants.h b/payload_consumer/payload_constants.h
index 5c2d17c..03647ee 100644
--- a/payload_consumer/payload_constants.h
+++ b/payload_consumer/payload_constants.h
@@ -56,6 +56,9 @@
// The minor version that allows Verity hash tree and FEC generation.
extern const uint32_t kVerityMinorPayloadVersion;
+// The minor version that allows partial update, e.g. kernel only update.
+extern const uint32_t kPartialUpdateMinorPayloadVersion;
+
// The minimum and maximum supported minor version.
extern const uint32_t kMinSupportedMinorPayloadVersion;
extern const uint32_t kMaxSupportedMinorPayloadVersion;
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index eb00333..18cff4b 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -445,6 +445,10 @@
out_maximum_signature_size_file,
"",
"Path to the output maximum signature size given a private key.");
+ DEFINE_bool(is_partial_update,
+ false,
+ "The payload only targets a subset of partitions on the device,"
+ "e.g. generic kernel image update.");
brillo::FlagHelper::Init(
argc,
@@ -629,6 +633,10 @@
CHECK(payload_config.target.ValidateDynamicPartitionMetadata());
}
+ if (FLAGS_is_partial_update) {
+ payload_config.is_partial_update = true;
+ }
+
CHECK(!FLAGS_out_file.empty());
// Ignore failures. These are optional arguments.
@@ -702,7 +710,8 @@
payload_config.max_timestamp = FLAGS_max_timestamp;
- if (payload_config.version.minor >= kVerityMinorPayloadVersion)
+ if (payload_config.is_delta &&
+ payload_config.version.minor >= kVerityMinorPayloadVersion)
CHECK(payload_config.target.LoadVerityConfig());
LOG(INFO) << "Generating " << (payload_config.is_delta ? "delta" : "full")
diff --git a/payload_generator/payload_file.cc b/payload_generator/payload_file.cc
index 69325d7..940e9bd 100644
--- a/payload_generator/payload_file.cc
+++ b/payload_generator/payload_file.cc
@@ -78,6 +78,9 @@
*(manifest_.mutable_dynamic_partition_metadata()) =
*(config.target.dynamic_partition_metadata);
+ if (config.is_partial_update) {
+ manifest_.set_partial_update(true);
+ }
return true;
}
diff --git a/payload_generator/payload_generation_config.cc b/payload_generator/payload_generation_config.cc
index b653a03..9c5832d 100644
--- a/payload_generator/payload_generation_config.cc
+++ b/payload_generator/payload_generation_config.cc
@@ -234,7 +234,8 @@
minor == kOpSrcHashMinorPayloadVersion ||
minor == kBrotliBsdiffMinorPayloadVersion ||
minor == kPuffdiffMinorPayloadVersion ||
- minor == kVerityMinorPayloadVersion);
+ minor == kVerityMinorPayloadVersion ||
+ minor == kPartialUpdateMinorPayloadVersion);
return true;
}
@@ -273,13 +274,14 @@
return false;
}
-bool PayloadVersion::IsDelta() const {
+bool PayloadVersion::IsDeltaOrPartial() const {
return minor != kFullPayloadMinorVersion;
}
bool PayloadGenerationConfig::Validate() const {
TEST_AND_RETURN_FALSE(version.Validate());
- TEST_AND_RETURN_FALSE(version.IsDelta() == is_delta);
+ TEST_AND_RETURN_FALSE(version.IsDeltaOrPartial() ==
+ (is_delta || is_partial_update));
if (is_delta) {
for (const PartitionConfig& part : source.partitions) {
if (!part.path.empty()) {
@@ -307,6 +309,10 @@
TEST_AND_RETURN_FALSE(part.verity.IsEmpty());
}
+ if (version.minor < kPartialUpdateMinorPayloadVersion) {
+ TEST_AND_RETURN_FALSE(!is_partial_update);
+ }
+
TEST_AND_RETURN_FALSE(hard_chunk_size == -1 ||
hard_chunk_size % block_size == 0);
TEST_AND_RETURN_FALSE(soft_chunk_size % block_size == 0);
diff --git a/payload_generator/payload_generation_config.h b/payload_generator/payload_generation_config.h
index af6f181..9abb97f 100644
--- a/payload_generator/payload_generation_config.h
+++ b/payload_generator/payload_generation_config.h
@@ -170,8 +170,8 @@
// Return whether the passed |operation| is allowed by this payload.
bool OperationAllowed(InstallOperation::Type operation) const;
- // Whether this payload version is a delta payload.
- bool IsDelta() const;
+ // Whether this payload version is a delta or partial payload.
+ bool IsDeltaOrPartial() const;
// The major version of the payload.
uint64_t major;
@@ -198,6 +198,10 @@
// Whether the requested payload is a delta payload.
bool is_delta = false;
+ // Whether the requested payload is a partial payload, i.e. only update a
+ // subset of partitions on device.
+ bool is_partial_update = false;
+
// The major/minor version of the payload.
PayloadVersion version;
diff --git a/scripts/brillo_update_payload b/scripts/brillo_update_payload
index d9c18ff..63b6d24 100755
--- a/scripts/brillo_update_payload
+++ b/scripts/brillo_update_payload
@@ -189,6 +189,9 @@
DEFINE_string disable_fec_computation "" \
"Optional: Disables the on device fec data computation for incremental \
update. This feature is enabled by default."
+ DEFINE_string is_partial_update "" \
+ "Optional: True if the payload is for partial update. i.e. it only updates \
+a subset of partitions on device."
fi
if [[ "${COMMAND}" == "hash" || "${COMMAND}" == "sign" ]]; then
DEFINE_string unsigned_payload "" "Path to the input unsigned payload."
@@ -654,21 +657,33 @@
--new_mapfiles="${new_mapfiles}"
)
+ if [[ "${FLAGS_is_partial_update}" == "true" ]]; then
+ GENERATOR_ARGS+=( --is_partial_update="true" )
+ # Need at least minor version 7 for partial update, so generate with minor
+ # version 7 if we don't have a source image. Let the delta_generator to fail
+ # the other incompatiable minor versions.
+ if [[ -z "${FORCE_MINOR_VERSION}" ]]; then
+ FORCE_MINOR_VERSION="7"
+ fi
+ fi
+
if [[ "${payload_type}" == "delta" ]]; then
# Source image args:
GENERATOR_ARGS+=(
--old_partitions="${old_partitions}"
--old_mapfiles="${old_mapfiles}"
)
- if [[ -n "${FORCE_MINOR_VERSION}" ]]; then
- GENERATOR_ARGS+=( --minor_version="${FORCE_MINOR_VERSION}" )
- fi
if [[ -n "${FLAGS_disable_fec_computation}" ]]; then
GENERATOR_ARGS+=(
--disable_fec_computation="${FLAGS_disable_fec_computation}" )
fi
fi
+ # minor version is set only for delta or partial payload.
+ if [[ -n "${FORCE_MINOR_VERSION}" ]]; then
+ GENERATOR_ARGS+=( --minor_version="${FORCE_MINOR_VERSION}" )
+ fi
+
if [[ -n "${FORCE_MAJOR_VERSION}" ]]; then
GENERATOR_ARGS+=( --major_version="${FORCE_MAJOR_VERSION}" )
fi