Support updateable groups.

Adds updateable group support to OTA.

* DeltaPerformer combines partition sizes with
  dynamic_partition_metadata to
  BootControlInterface::PartitionMetadata.

* BootControlAndroid::InitPartitionMetadata:
    * Copy all groups / partitions from source metadata slot
    * Remove all groups / partitions mentioned in the manifest (of the
    target slot)
    * Re-add all groups / partitions mentioned in the manifest.

* BootControlAndroid::InitPartitionMetadata can check
  the incoming PartitionMetadata to see if a partition is dynamic
  or not. The guessing logic is completely removed.

* Because a partition is removed then re-added, there is no need
  for preserving the entry with size 0 to indicate that a partition
  is removed. When update_engine sees a partition in a group "foo" on
  the device, but manifest contains group "foo" without the partition,
  it removes the partition.

* Hence, Removing a partition does NOT require keeping the entry (i.e.
  RemovePartition is used instead of ShrinkPartition(0) ). This makes
  retrofitting dynamic partitions on older devices easier.

The following is now allowed:
- Adding / removing / resizing partitions
- Adding / resizing groups

It is not allowed to remove a group, but a group can always be resized
to zero to deprecate it.

Test: update_engine_unittests
Bug: 117182932

Change-Id: I39d77f1d1d1fc52fc245f3de699635e6a429015e
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index 7dec48f..7a19374 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -944,8 +944,30 @@
   }
 
   BootControlInterface::PartitionMetadata partition_metadata;
-  for (const InstallPlan::Partition& partition : install_plan_->partitions) {
-    partition_metadata.emplace(partition.name, partition.target_size);
+  if (manifest_.has_dynamic_partition_metadata()) {
+    std::map<string, uint64_t> partition_sizes;
+    for (const InstallPlan::Partition& partition : install_plan_->partitions) {
+      partition_sizes.emplace(partition.name, partition.target_size);
+    }
+    for (const auto& group : manifest_.dynamic_partition_metadata().groups()) {
+      BootControlInterface::PartitionMetadata::Group e;
+      e.name = group.name();
+      e.size = group.size();
+      for (const auto& partition_name : group.partition_names()) {
+        auto it = partition_sizes.find(partition_name);
+        if (it == partition_sizes.end()) {
+          // TODO(tbao): Support auto-filling partition info for framework-only
+          // OTA.
+          LOG(ERROR) << "dynamic_partition_metadata contains partition "
+                     << partition_name
+                     << " but it is not part of the manifest. "
+                     << "This is not supported.";
+          return false;
+        }
+        e.partitions.push_back({partition_name, it->second});
+      }
+      partition_metadata.groups.push_back(std::move(e));
+    }
   }
 
   if (!boot_control_->InitPartitionMetadata(install_plan_->target_slot,
@@ -1676,6 +1698,16 @@
     return ErrorCode::kPayloadTimestampError;
   }
 
+  if (major_payload_version_ == kChromeOSMajorPayloadVersion) {
+    if (manifest_.has_dynamic_partition_metadata()) {
+      LOG(ERROR)
+          << "Should not contain dynamic_partition_metadata for major version "
+          << kChromeOSMajorPayloadVersion
+          << ". Please use major version 2 or above.";
+      return ErrorCode::kPayloadMismatchedType;
+    }
+  }
+
   // TODO(garnold) we should be adding more and more manifest checks, such as
   // partition boundaries etc (see chromium-os:37661).