Support IsDeltaPayload per <package>.

Mixed full and delta payloads are now supported for multi-payload.

Bug: 36252799
Test: update_engine_unittests
Change-Id: Ic519f8399579c714a65ba9f9f948a389fcc249ed
(cherry picked from commit 4928112f8635f7a5b583171640aee2bda690ba34)
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index ab5e275..94c5c60 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -340,7 +340,7 @@
   const InstallPlan::Partition& install_part =
       install_plan_->partitions[num_previous_partitions + current_partition_];
   // Open source fds if we have a delta payload with minor version >= 2.
-  if (install_plan_->payload_type == InstallPayloadType::kDelta &&
+  if (payload_->type == InstallPayloadType::kDelta &&
       GetMinorVersion() != kInPlaceMinorPayloadVersion) {
     source_path_ = install_part.source_path;
     int err;
@@ -431,7 +431,7 @@
   if (manifest_.has_minor_version()) {
     return manifest_.minor_version();
   } else {
-    return install_plan_->payload_type == InstallPayloadType::kDelta
+    return payload_->type == InstallPayloadType::kDelta
                ? kSupportedMinorPayloadVersion
                : kFullPayloadMinorVersion;
   }
@@ -1427,14 +1427,14 @@
   InstallPayloadType actual_payload_type =
       has_old_fields ? InstallPayloadType::kDelta : InstallPayloadType::kFull;
 
-  if (install_plan_->payload_type == InstallPayloadType::kUnknown) {
+  if (payload_->type == InstallPayloadType::kUnknown) {
     LOG(INFO) << "Detected a '"
               << InstallPayloadTypeToString(actual_payload_type)
               << "' payload.";
-    install_plan_->payload_type = actual_payload_type;
-  } else if (install_plan_->payload_type != actual_payload_type) {
+    payload_->type = actual_payload_type;
+  } else if (payload_->type != actual_payload_type) {
     LOG(ERROR) << "InstallPlan expected a '"
-               << InstallPayloadTypeToString(install_plan_->payload_type)
+               << InstallPayloadTypeToString(payload_->type)
                << "' payload but the downloaded manifest contains a '"
                << InstallPayloadTypeToString(actual_payload_type)
                << "' payload.";
diff --git a/payload_consumer/delta_performer_integration_test.cc b/payload_consumer/delta_performer_integration_test.cc
index a3f653b..bc67d93 100644
--- a/payload_consumer/delta_performer_integration_test.cc
+++ b/payload_consumer/delta_performer_integration_test.cc
@@ -719,12 +719,11 @@
 
   // Update the A image in place.
   InstallPlan* install_plan = &state->install_plan;
-  install_plan->payloads.resize(1);
   install_plan->hash_checks_mandatory = hash_checks_mandatory;
-  install_plan->payloads[0].metadata_size = state->metadata_size;
-  install_plan->payload_type = (full_kernel && full_rootfs)
-                                   ? InstallPayloadType::kFull
-                                   : InstallPayloadType::kDelta;
+  install_plan->payloads = {{.metadata_size = state->metadata_size,
+                             .type = (full_kernel && full_rootfs)
+                                         ? InstallPayloadType::kFull
+                                         : InstallPayloadType::kDelta}};
   install_plan->source_slot = 0;
   install_plan->target_slot = 1;
 
diff --git a/payload_consumer/delta_performer_unittest.cc b/payload_consumer/delta_performer_unittest.cc
index 3af13ec..1e06e1a 100644
--- a/payload_consumer/delta_performer_unittest.cc
+++ b/payload_consumer/delta_performer_unittest.cc
@@ -103,7 +103,7 @@
                              uint64_t major_version,
                              InstallPayloadType payload_type,
                              ErrorCode expected) {
-    install_plan_.payload_type = payload_type;
+    payload_.type = payload_type;
 
     // The Manifest we are validating.
     performer_.manifest_.CopyFrom(manifest);
@@ -338,7 +338,7 @@
 };
 
 TEST_F(DeltaPerformerTest, FullPayloadWriteTest) {
-  install_plan_.payload_type = InstallPayloadType::kFull;
+  payload_.type = InstallPayloadType::kFull;
   brillo::Blob expected_data = brillo::Blob(std::begin(kRandomString),
                                             std::end(kRandomString));
   expected_data.resize(4096);  // block size
@@ -357,7 +357,7 @@
 }
 
 TEST_F(DeltaPerformerTest, ShouldCancelTest) {
-  install_plan_.payload_type = InstallPayloadType::kFull;
+  payload_.type = InstallPayloadType::kFull;
   brillo::Blob expected_data = brillo::Blob(std::begin(kRandomString),
                                             std::end(kRandomString));
   expected_data.resize(4096);  // block size
diff --git a/payload_consumer/download_action_unittest.cc b/payload_consumer/download_action_unittest.cc
index 9d85550..7d3ac6c 100644
--- a/payload_consumer/download_action_unittest.cc
+++ b/payload_consumer/download_action_unittest.cc
@@ -141,8 +141,8 @@
 
   uint64_t size = data.size() - 1;
   InstallPlan install_plan;
-  install_plan.payload_type = InstallPayloadType::kDelta;
-  install_plan.payloads.push_back({.size = size});
+  install_plan.payloads.push_back(
+      {.size = size, .type = InstallPayloadType::kDelta});
   // We pull off the first byte from data and seek past it.
   EXPECT_TRUE(HashCalculator::RawHashOfBytes(
       &data[1], data.size() - 1, &install_plan.payloads[0].hash));
diff --git a/payload_consumer/filesystem_verifier_action.cc b/payload_consumer/filesystem_verifier_action.cc
index 4f30582..5edde9e 100644
--- a/payload_consumer/filesystem_verifier_action.cc
+++ b/payload_consumer/filesystem_verifier_action.cc
@@ -204,8 +204,10 @@
       if (partition.target_hash != hasher_->raw_hash()) {
         LOG(ERROR) << "New '" << partition.name
                    << "' partition verification failed.";
-        if (install_plan_.payload_type == InstallPayloadType::kFull)
+        if (partition.source_hash.empty()) {
+          // No need to verify source if it is a full payload.
           return Cleanup(ErrorCode::kNewRootfsVerificationError);
+        }
         // If we have not verified source partition yet, now that the target
         // partition does not match, and it's not a full payload, we need to
         // switch to kVerifySourceHash step to check if it's because the source
diff --git a/payload_consumer/install_plan.cc b/payload_consumer/install_plan.cc
index 5f004bf..d5d745b 100644
--- a/payload_consumer/install_plan.cc
+++ b/payload_consumer/install_plan.cc
@@ -42,7 +42,6 @@
 
 bool InstallPlan::operator==(const InstallPlan& that) const {
   return ((is_resume == that.is_resume) &&
-          (payload_type == that.payload_type) &&
           (download_url == that.download_url) && (payloads == that.payloads) &&
           (source_slot == that.source_slot) &&
           (target_slot == that.target_slot) && (partitions == that.partitions));
@@ -67,15 +66,15 @@
   for (const auto& payload : payloads) {
     payloads_str += base::StringPrintf(
         ", payload: (size: %" PRIu64 ", metadata_size: %" PRIu64
-        ", metadata signature: %s, hash: %s)",
+        ", metadata signature: %s, hash: %s, payload type: %s)",
         payload.size,
         payload.metadata_size,
         payload.metadata_signature.c_str(),
-        base::HexEncode(payload.hash.data(), payload.hash.size()).c_str());
+        base::HexEncode(payload.hash.data(), payload.hash.size()).c_str(),
+        InstallPayloadTypeToString(payload.type).c_str());
   }
 
   LOG(INFO) << "InstallPlan: " << (is_resume ? "resume" : "new_update")
-            << ", payload type: " << InstallPayloadTypeToString(payload_type)
             << ", source_slot: " << BootControlInterface::SlotName(source_slot)
             << ", target_slot: " << BootControlInterface::SlotName(target_slot)
             << ", url: " << download_url << payloads_str << partitions_str
diff --git a/payload_consumer/install_plan.h b/payload_consumer/install_plan.h
index d8d9f57..6dd5a73 100644
--- a/payload_consumer/install_plan.h
+++ b/payload_consumer/install_plan.h
@@ -52,7 +52,6 @@
   bool LoadPartitionsFromSlots(BootControlInterface* boot_control);
 
   bool is_resume{false};
-  InstallPayloadType payload_type{InstallPayloadType::kUnknown};
   std::string download_url;  // url to download from
   std::string version;       // version we are installing.
 
@@ -61,6 +60,7 @@
     uint64_t metadata_size = 0;      // size of the metadata
     std::string metadata_signature;  // signature of the metadata in base64
     brillo::Blob hash;               // SHA256 hash of the payload
+    InstallPayloadType type{InstallPayloadType::kUnknown};
     // Only download manifest and fill in partitions in install plan without
     // apply the payload if true. Will be set by DownloadAction when resuming
     // multi-payload.
@@ -69,7 +69,8 @@
     bool operator==(const Payload& that) const {
       return size == that.size && metadata_size == that.metadata_size &&
              metadata_signature == that.metadata_signature &&
-             hash == that.hash && already_applied == that.already_applied;
+             hash == that.hash && type == that.type &&
+             already_applied == that.already_applied;
     }
   };
   std::vector<Payload> payloads;