Support generation of partial updates am: f5baff4655 am: fd461de2a2

Original change: https://android-review.googlesource.com/c/platform/system/update_engine/+/1354126

Change-Id: I1bced139fb8c17a1d13905f03555b46cef96daf3
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