update_engine resize dynamic partitions during OTA.

update_engine uses device mapper to resize dynamic partitions
before opening the devices to apply the update.

* DeltaPerformer calls BootControlInterface::InitPartitionMetadata
  when parsing the update manifest. The implementation for
  BootControlAndroid::InitPartitionMetadata does the following
  if sizes for dynamic partitions are incorrect (assuming updating
  from slot A to B):
  * Load metadata from metadata slot A
  * Delete all extents of partitions at slot B (with _b suffix)
  * Add extents for partitions at slot B
  * Write metadata to metadata slot B
  * Re-map all partitions at slot B using metadata slot B with
    force_writable = true
* BootControlAndroid::GetPartitionDevice() checks device-mapper
  before returning static partitions.
* PostinstallRunnerAction::Cleanup calls BootControlInterface::Cleanup
  which unmaps all partitions at slot B.

A partition "foo" is considered dynamic if foo_a exists as a dynamic
partition OR foo_b does NOT exist as a static partition.

Bug: 110717529

Test: manual ota
Test: update_engine_unittests --gtest_filter=*BootControlAndroid*
Change-Id: I50f410b486a874242663624801c3694151bdda18
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index e700255..30fe763 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -21,6 +21,7 @@
 
 #include <algorithm>
 #include <cstring>
+#include <map>
 #include <memory>
 #include <string>
 #include <utility>
@@ -639,9 +640,11 @@
       return false;
     }
 
-    if (!OpenCurrentPartition()) {
-      *error = ErrorCode::kInstallDeviceOpenError;
-      return false;
+    if (next_operation_num_ < acc_num_operations_[current_partition_]) {
+      if (!OpenCurrentPartition()) {
+        *error = ErrorCode::kInstallDeviceOpenError;
+        return false;
+      }
     }
 
     if (next_operation_num_ > 0)
@@ -658,9 +661,12 @@
 
     // We know there are more operations to perform because we didn't reach the
     // |num_total_operations_| limit yet.
-    while (next_operation_num_ >= acc_num_operations_[current_partition_]) {
+    if (next_operation_num_ >= acc_num_operations_[current_partition_]) {
       CloseCurrentPartition();
-      current_partition_++;
+      // Skip until there are operations for current_partition_.
+      while (next_operation_num_ >= acc_num_operations_[current_partition_]) {
+        current_partition_++;
+      }
       if (!OpenCurrentPartition()) {
         *error = ErrorCode::kInstallDeviceOpenError;
         return false;
@@ -912,6 +918,20 @@
     install_plan_->partitions.push_back(install_part);
   }
 
+  if (install_plan_->target_slot != BootControlInterface::kInvalidSlot) {
+    BootControlInterface::PartitionSizes partition_sizes;
+    for (const InstallPlan::Partition& partition : install_plan_->partitions) {
+      partition_sizes.emplace(partition.name, partition.target_size);
+    }
+    if (!boot_control_->InitPartitionMetadata(install_plan_->target_slot,
+                                              partition_sizes)) {
+      LOG(ERROR) << "Unable to initialize partition metadata for slot "
+                 << BootControlInterface::SlotName(install_plan_->target_slot);
+      *error = ErrorCode::kInstallDeviceOpenError;
+      return false;
+    }
+  }
+
   if (!install_plan_->LoadPartitionsFromSlots(boot_control_)) {
     LOG(ERROR) << "Unable to determine all the partition devices.";
     *error = ErrorCode::kInstallDeviceOpenError;
diff --git a/payload_consumer/filesystem_verifier_action.cc b/payload_consumer/filesystem_verifier_action.cc
index a5e1e61..d74d81d 100644
--- a/payload_consumer/filesystem_verifier_action.cc
+++ b/payload_consumer/filesystem_verifier_action.cc
@@ -98,13 +98,25 @@
       partition_size_ = partition.target_size;
       break;
   }
-  LOG(INFO) << "Hashing partition " << partition_index_ << " ("
-            << partition.name << ") on device " << part_path;
+
   if (part_path.empty()) {
+    if (partition_size_ == 0) {
+      LOG(INFO) << "Skip hashing partition " << partition_index_ << " ("
+                << partition.name << ") because size is 0.";
+      partition_index_++;
+      StartPartitionHashing();
+      return;
+    }
+    LOG(ERROR) << "Cannot hash partition " << partition_index_ << " ("
+               << partition.name
+               << ") because its device path cannot be determined.";
     Cleanup(ErrorCode::kFilesystemVerifierError);
     return;
   }
 
+  LOG(INFO) << "Hashing partition " << partition_index_ << " ("
+            << partition.name << ") on device " << part_path;
+
   brillo::ErrorPtr error;
   src_stream_ = brillo::FileStream::Open(
       base::FilePath(part_path),
diff --git a/payload_consumer/install_plan.cc b/payload_consumer/install_plan.cc
index 45112d6..561e294 100644
--- a/payload_consumer/install_plan.cc
+++ b/payload_consumer/install_plan.cc
@@ -103,7 +103,8 @@
       partition.source_path.clear();
     }
 
-    if (target_slot != BootControlInterface::kInvalidSlot) {
+    if (target_slot != BootControlInterface::kInvalidSlot &&
+        partition.target_size > 0) {
       result = boot_control->GetPartitionDevice(
           partition.name, target_slot, &partition.target_path) && result;
     } else {