Call InitPartitionMetadata when resuming an update.
am: 3406c772a3

Change-Id: I21a233e57d383f7ceb6f9923b647d634467b6210
diff --git a/boot_control_android.cc b/boot_control_android.cc
index af1a5f9..421c091 100644
--- a/boot_control_android.cc
+++ b/boot_control_android.cc
@@ -396,7 +396,9 @@
 }  // namespace
 
 bool BootControlAndroid::InitPartitionMetadata(
-    Slot target_slot, const PartitionMetadata& partition_metadata) {
+    Slot target_slot,
+    const PartitionMetadata& partition_metadata,
+    bool update_metadata) {
   if (fs_mgr_overlayfs_is_setup()) {
     // Non DAP devices can use overlayfs as well.
     LOG(WARNING)
@@ -414,11 +416,6 @@
     return false;
   }
 
-  string target_suffix;
-  if (!GetSuffix(target_slot, &target_suffix)) {
-    return false;
-  }
-
   // Although the current build supports dynamic partitions, the given payload
   // doesn't use it for target partitions. This could happen when applying a
   // retrofit update. Skip updating the partition metadata for the target slot.
@@ -427,6 +424,15 @@
     return true;
   }
 
+  if (!update_metadata) {
+    return true;
+  }
+
+  string target_suffix;
+  if (!GetSuffix(target_slot, &target_suffix)) {
+    return false;
+  }
+
   // Unmap all the target dynamic partitions because they would become
   // inconsistent with the new metadata.
   if (!UnmapTargetPartitions(
@@ -434,15 +440,11 @@
     return false;
   }
 
-  if (!UpdatePartitionMetadata(dynamic_control_.get(),
-                               source_slot,
-                               target_slot,
-                               target_suffix,
-                               partition_metadata)) {
-    return false;
-  }
-
-  return true;
+  return UpdatePartitionMetadata(dynamic_control_.get(),
+                                 source_slot,
+                                 target_slot,
+                                 target_suffix,
+                                 partition_metadata);
 }
 
 }  // namespace chromeos_update_engine
diff --git a/boot_control_android.h b/boot_control_android.h
index aa62e42..a6f33be 100644
--- a/boot_control_android.h
+++ b/boot_control_android.h
@@ -51,8 +51,9 @@
   bool MarkSlotUnbootable(BootControlInterface::Slot slot) override;
   bool SetActiveBootSlot(BootControlInterface::Slot slot) override;
   bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override;
-  bool InitPartitionMetadata(
-      Slot slot, const PartitionMetadata& partition_metadata) override;
+  bool InitPartitionMetadata(Slot slot,
+                             const PartitionMetadata& partition_metadata,
+                             bool update_metadata) override;
   void Cleanup() override;
 
  private:
diff --git a/boot_control_android_unittest.cc b/boot_control_android_unittest.cc
index 0eb3fe0..bb9903e 100644
--- a/boot_control_android_unittest.cc
+++ b/boot_control_android_unittest.cc
@@ -379,10 +379,12 @@
         .Times(0);
   }
 
-  bool InitPartitionMetadata(uint32_t slot, PartitionSizes partition_sizes) {
+  bool InitPartitionMetadata(uint32_t slot,
+                             PartitionSizes partition_sizes,
+                             bool update_metadata = true) {
     auto m = partitionSizesToMetadata(partition_sizes);
     LOG(INFO) << m;
-    return bootctl_.InitPartitionMetadata(slot, m);
+    return bootctl_.InitPartitionMetadata(slot, m, update_metadata);
   }
 
   BootControlAndroid bootctl_;  // BootControlAndroid under test.
@@ -537,21 +539,74 @@
 
   // Not calling through BootControlAndroidTest::InitPartitionMetadata(), since
   // we don't want any default group in the PartitionMetadata.
-  EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(), {}));
+  EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(), {}, true));
 
   // Should use dynamic source partitions.
   EXPECT_CALL(dynamicControl(), GetState(S("system")))
       .Times(1)
       .WillOnce(Return(DmDeviceState::ACTIVE));
-  string source_device;
-  EXPECT_TRUE(bootctl_.GetPartitionDevice("system", source(), &source_device));
-  EXPECT_EQ(GetDmDevice(S("system")), source_device);
+  string system_device;
+  EXPECT_TRUE(bootctl_.GetPartitionDevice("system", source(), &system_device));
+  EXPECT_EQ(GetDmDevice(S("system")), system_device);
 
   // Should use static target partitions without querying dynamic control.
   EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
-  string target_device;
-  EXPECT_TRUE(bootctl_.GetPartitionDevice("system", target(), &target_device));
-  EXPECT_EQ(GetDevice(T("system")), target_device);
+  EXPECT_TRUE(bootctl_.GetPartitionDevice("system", target(), &system_device));
+  EXPECT_EQ(GetDevice(T("system")), system_device);
+
+  // Static partition "bar".
+  EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
+  std::string bar_device;
+  EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", source(), &bar_device));
+  EXPECT_EQ(GetDevice(S("bar")), bar_device);
+
+  EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
+  EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", target(), &bar_device));
+  EXPECT_EQ(GetDevice(T("bar")), bar_device);
+}
+
+TEST_P(BootControlAndroidTestP, GetPartitionDeviceWhenResumingUpdate) {
+  // Both of the two slots contain valid partition metadata, since this is
+  // resuming an update.
+  SetMetadata(source(),
+              {{S("system"), 2_GiB},
+               {S("vendor"), 1_GiB},
+               {T("system"), 2_GiB},
+               {T("vendor"), 1_GiB}});
+  SetMetadata(target(),
+              {{S("system"), 2_GiB},
+               {S("vendor"), 1_GiB},
+               {T("system"), 2_GiB},
+               {T("vendor"), 1_GiB}});
+  EXPECT_CALL(dynamicControl(),
+              StoreMetadata(GetSuperDevice(target()), _, target()))
+      .Times(0);
+  EXPECT_TRUE(InitPartitionMetadata(
+      target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}, false));
+
+  // Dynamic partition "system".
+  EXPECT_CALL(dynamicControl(), GetState(S("system")))
+      .Times(1)
+      .WillOnce(Return(DmDeviceState::ACTIVE));
+  string system_device;
+  EXPECT_TRUE(bootctl_.GetPartitionDevice("system", source(), &system_device));
+  EXPECT_EQ(GetDmDevice(S("system")), system_device);
+
+  EXPECT_CALL(dynamicControl(), GetState(T("system")))
+      .Times(1)
+      .WillOnce(Return(DmDeviceState::ACTIVE));
+  EXPECT_TRUE(bootctl_.GetPartitionDevice("system", target(), &system_device));
+  EXPECT_EQ(GetDmDevice(T("system")), system_device);
+
+  // Static partition "bar".
+  EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
+  std::string bar_device;
+  EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", source(), &bar_device));
+  EXPECT_EQ(GetDevice(S("bar")), bar_device);
+
+  EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
+  EXPECT_TRUE(bootctl_.GetPartitionDevice("bar", target(), &bar_device));
+  EXPECT_EQ(GetDevice(T("bar")), bar_device);
 }
 
 INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
@@ -695,7 +750,8 @@
       target(),
       PartitionMetadata{
           .groups = {SimpleGroup("android", 3_GiB, "system", 3_GiB),
-                     SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
+                     SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}},
+      true));
 }
 
 TEST_P(BootControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
@@ -703,7 +759,8 @@
       target(),
       PartitionMetadata{
           .groups = {SimpleGroup("android", 3_GiB, "system", 1_GiB),
-                     SimpleGroup("oem", 2_GiB, "vendor", 3_GiB)}}))
+                     SimpleGroup("oem", 2_GiB, "vendor", 3_GiB)}},
+      true))
       << "Should not be able to grow over maximum size of group";
 }
 
@@ -711,7 +768,8 @@
   EXPECT_FALSE(bootctl_.InitPartitionMetadata(
       target(),
       PartitionMetadata{.groups = {{.name = "android", .size = 3_GiB},
-                                   {.name = "oem", .size = 3_GiB}}}))
+                                   {.name = "oem", .size = 3_GiB}}},
+      true))
       << "Should not be able to grow over size of super / 2";
 }
 
@@ -727,12 +785,13 @@
   EXPECT_TRUE(bootctl_.InitPartitionMetadata(
       target(),
       PartitionMetadata{
-          .groups = {
-              {.name = "android",
-               .size = 3_GiB,
-               .partitions = {{.name = "system", .size = 2_GiB},
-                              {.name = "product_services", .size = 1_GiB}}},
-              SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
+          .groups = {{.name = "android",
+                      .size = 3_GiB,
+                      .partitions = {{.name = "system", .size = 2_GiB},
+                                     {.name = "product_services",
+                                      .size = 1_GiB}}},
+                     SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}},
+      true));
 }
 
 TEST_P(BootControlAndroidGroupTestP, RemovePartitionFromGroup) {
@@ -744,7 +803,8 @@
       target(),
       PartitionMetadata{
           .groups = {{.name = "android", .size = 3_GiB, .partitions = {}},
-                     SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
+                     SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}},
+      true));
 }
 
 TEST_P(BootControlAndroidGroupTestP, AddGroup) {
@@ -756,10 +816,10 @@
   EXPECT_TRUE(bootctl_.InitPartitionMetadata(
       target(),
       PartitionMetadata{
-          .groups = {
-              SimpleGroup("android", 2_GiB, "system", 2_GiB),
-              SimpleGroup("oem", 1_GiB, "vendor", 1_GiB),
-              SimpleGroup("new_group", 2_GiB, "new_partition", 2_GiB)}}));
+          .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB),
+                     SimpleGroup("oem", 1_GiB, "vendor", 1_GiB),
+                     SimpleGroup("new_group", 2_GiB, "new_partition", 2_GiB)}},
+      true));
 }
 
 TEST_P(BootControlAndroidGroupTestP, RemoveGroup) {
@@ -768,7 +828,8 @@
   EXPECT_TRUE(bootctl_.InitPartitionMetadata(
       target(),
       PartitionMetadata{
-          .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB)}}));
+          .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB)}},
+      true));
 }
 
 TEST_P(BootControlAndroidGroupTestP, ResizeGroup) {
@@ -781,7 +842,8 @@
       target(),
       PartitionMetadata{
           .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB),
-                     SimpleGroup("oem", 3_GiB, "vendor", 3_GiB)}}));
+                     SimpleGroup("oem", 3_GiB, "vendor", 3_GiB)}},
+      true));
 }
 
 INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
diff --git a/boot_control_chromeos.cc b/boot_control_chromeos.cc
index a82efc7..4fa1268 100644
--- a/boot_control_chromeos.cc
+++ b/boot_control_chromeos.cc
@@ -303,7 +303,9 @@
 }
 
 bool BootControlChromeOS::InitPartitionMetadata(
-    Slot slot, const PartitionMetadata& partition_metadata) {
+    Slot slot,
+    const PartitionMetadata& partition_metadata,
+    bool update_metadata) {
   return true;
 }
 
diff --git a/boot_control_chromeos.h b/boot_control_chromeos.h
index c474d6f..f3682e9 100644
--- a/boot_control_chromeos.h
+++ b/boot_control_chromeos.h
@@ -50,8 +50,9 @@
   bool MarkSlotUnbootable(BootControlInterface::Slot slot) override;
   bool SetActiveBootSlot(BootControlInterface::Slot slot) override;
   bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override;
-  bool InitPartitionMetadata(
-      Slot slot, const PartitionMetadata& partition_metadata) override;
+  bool InitPartitionMetadata(Slot slot,
+                             const PartitionMetadata& partition_metadata,
+                             bool update_metadata) override;
   void Cleanup() override;
 
  private:
diff --git a/common/boot_control_interface.h b/common/boot_control_interface.h
index 43517ce..392d785 100644
--- a/common/boot_control_interface.h
+++ b/common/boot_control_interface.h
@@ -66,7 +66,9 @@
   // Determines the block device for the given partition name and slot number.
   // The |slot| number must be between 0 and GetNumSlots() - 1 and the
   // |partition_name| is a platform-specific name that identifies a partition on
-  // every slot. On success, returns true and stores the block device in
+  // every slot. In order to access the dynamic partitions in the target slot,
+  // InitPartitionMetadata() must be called (once per payload) prior to calling
+  // this function. On success, returns true and stores the block device in
   // |device|.
   virtual bool GetPartitionDevice(const std::string& partition_name,
                                   Slot slot,
@@ -92,14 +94,14 @@
   // of the operation.
   virtual bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) = 0;
 
-  // Initialize metadata of underlying partitions for a given |slot|.
-  // Ensure that all updateable groups with the suffix GetSuffix(|slot|) exactly
-  // matches the layout specified in |partition_metadata|. Ensure that
-  // partitions at the specified |slot| has a given size and updateable group,
-  // as specified by |partition_metadata|. Sizes must be aligned to the logical
-  // block size of the super partition.
+  // Initializes the metadata of the underlying partitions for a given |slot|
+  // and sets up the states for accessing dynamic partitions.
+  // |partition_metadata| will be written to the specified |slot| if
+  // |update_metadata| is set.
   virtual bool InitPartitionMetadata(
-      Slot slot, const PartitionMetadata& partition_metadata) = 0;
+      Slot slot,
+      const PartitionMetadata& partition_metadata,
+      bool update_metadata) = 0;
 
   // Do necessary clean-up operations after the whole update.
   virtual void Cleanup() = 0;
diff --git a/common/boot_control_stub.cc b/common/boot_control_stub.cc
index ca880d4..0fe8a98 100644
--- a/common/boot_control_stub.cc
+++ b/common/boot_control_stub.cc
@@ -60,7 +60,9 @@
 }
 
 bool BootControlStub::InitPartitionMetadata(
-    Slot slot, const PartitionMetadata& partition_metadata) {
+    Slot slot,
+    const PartitionMetadata& partition_metadata,
+    bool update_metadata) {
   LOG(ERROR) << __FUNCTION__ << " should never be called.";
   return false;
 }
diff --git a/common/boot_control_stub.h b/common/boot_control_stub.h
index 0950997..8dfaffc 100644
--- a/common/boot_control_stub.h
+++ b/common/boot_control_stub.h
@@ -45,8 +45,9 @@
   bool MarkSlotUnbootable(BootControlInterface::Slot slot) override;
   bool SetActiveBootSlot(BootControlInterface::Slot slot) override;
   bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override;
-  bool InitPartitionMetadata(
-      Slot slot, const PartitionMetadata& partition_metadata) override;
+  bool InitPartitionMetadata(Slot slot,
+                             const PartitionMetadata& partition_metadata,
+                             bool update_metadata) override;
   void Cleanup() override;
 
  private:
diff --git a/common/constants.cc b/common/constants.cc
index 3ae7a60..310f1b2 100644
--- a/common/constants.cc
+++ b/common/constants.cc
@@ -37,8 +37,8 @@
 const char kPrefsDailyMetricsLastReportedAt[] =
     "daily-metrics-last-reported-at";
 const char kPrefsDeltaUpdateFailures[] = "delta-update-failures";
-const char kPrefsDynamicPartitionMetadataInitialized[] =
-    "dynamic-partition-metadata-initialized";
+const char kPrefsDynamicPartitionMetadataUpdated[] =
+    "dynamic-partition-metadata-updated";
 const char kPrefsFullPayloadAttemptNumber[] = "full-payload-attempt-number";
 const char kPrefsInstallDateDays[] = "install-date-days";
 const char kPrefsLastActivePingDay[] = "last-active-ping-day";
diff --git a/common/constants.h b/common/constants.h
index 61e5ddd..d5a8ae3 100644
--- a/common/constants.h
+++ b/common/constants.h
@@ -41,7 +41,7 @@
 extern const char kPrefsCurrentUrlIndex[];
 extern const char kPrefsDailyMetricsLastReportedAt[];
 extern const char kPrefsDeltaUpdateFailures[];
-extern const char kPrefsDynamicPartitionMetadataInitialized[];
+extern const char kPrefsDynamicPartitionMetadataUpdated[];
 extern const char kPrefsFullPayloadAttemptNumber[];
 extern const char kPrefsInstallDateDays[];
 extern const char kPrefsLastActivePingDay[];
diff --git a/common/fake_boot_control.h b/common/fake_boot_control.h
index 513c149..ba975a2 100644
--- a/common/fake_boot_control.h
+++ b/common/fake_boot_control.h
@@ -74,8 +74,9 @@
     return true;
   }
 
-  bool InitPartitionMetadata(
-      Slot slot, const PartitionMetadata& partition_metadata) override {
+  bool InitPartitionMetadata(Slot slot,
+                             const PartitionMetadata& partition_metadata,
+                             bool update_metadata) override {
     return true;
   }
 
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index 0711ac6..1bfdf9c 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -935,14 +935,6 @@
 }
 
 bool DeltaPerformer::InitPartitionMetadata() {
-  bool metadata_initialized;
-  if (prefs_->GetBoolean(kPrefsDynamicPartitionMetadataInitialized,
-                         &metadata_initialized) &&
-      metadata_initialized) {
-    LOG(INFO) << "Skipping InitPartitionMetadata.";
-    return true;
-  }
-
   BootControlInterface::PartitionMetadata partition_metadata;
   if (manifest_.has_dynamic_partition_metadata()) {
     std::map<string, uint64_t> partition_sizes;
@@ -970,14 +962,16 @@
     }
   }
 
-  if (!boot_control_->InitPartitionMetadata(install_plan_->target_slot,
-                                            partition_metadata)) {
+  bool metadata_updated = false;
+  prefs_->GetBoolean(kPrefsDynamicPartitionMetadataUpdated, &metadata_updated);
+  if (!boot_control_->InitPartitionMetadata(
+          install_plan_->target_slot, partition_metadata, !metadata_updated)) {
     LOG(ERROR) << "Unable to initialize partition metadata for slot "
                << BootControlInterface::SlotName(install_plan_->target_slot);
     return false;
   }
   TEST_AND_RETURN_FALSE(
-      prefs_->SetBoolean(kPrefsDynamicPartitionMetadataInitialized, true));
+      prefs_->SetBoolean(kPrefsDynamicPartitionMetadataUpdated, true));
   LOG(INFO) << "InitPartitionMetadata done.";
 
   return true;
@@ -1901,7 +1895,7 @@
     prefs->SetInt64(kPrefsResumedUpdateFailures, 0);
     prefs->Delete(kPrefsPostInstallSucceeded);
     prefs->Delete(kPrefsVerityWritten);
-    prefs->Delete(kPrefsDynamicPartitionMetadataInitialized);
+    prefs->Delete(kPrefsDynamicPartitionMetadataUpdated);
   }
   return true;
 }
diff --git a/payload_consumer/delta_performer_integration_test.cc b/payload_consumer/delta_performer_integration_test.cc
index 9368e11..0912764 100644
--- a/payload_consumer/delta_performer_integration_test.cc
+++ b/payload_consumer/delta_performer_integration_test.cc
@@ -697,7 +697,7 @@
       .WillRepeatedly(Return(true));
   EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSignedSHA256Context, _))
       .WillRepeatedly(Return(true));
-  EXPECT_CALL(prefs, SetBoolean(kPrefsDynamicPartitionMetadataInitialized, _))
+  EXPECT_CALL(prefs, SetBoolean(kPrefsDynamicPartitionMetadataUpdated, _))
       .WillRepeatedly(Return(true));
   if (op_hash_test == kValidOperationData && signature_test != kSignatureNone) {
     EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSignatureBlob, _))