Proper split of BootControl and DynamicPartitionControl.
am: 3a1a561839

Change-Id: I3caeb55d696c2d60cdcffd0a35bb851a67e6d9e7
diff --git a/Android.bp b/Android.bp
index d6f1090..84d4a7a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -677,7 +677,6 @@
     test_suites: ["device-tests"],
 
     srcs: [
-        "boot_control_android_unittest.cc",
         "certificate_checker_unittest.cc",
         "common/action_pipe_unittest.cc",
         "common/action_processor_unittest.cc",
diff --git a/boot_control_android.cc b/boot_control_android.cc
index b1d775e..05e9637 100644
--- a/boot_control_android.cc
+++ b/boot_control_android.cc
@@ -24,8 +24,6 @@
 #include <base/logging.h>
 #include <bootloader_message/bootloader_message.h>
 #include <brillo/message_loops/message_loop.h>
-#include <fs_mgr_overlayfs.h>
-#include <libdm/dm.h>
 
 #include "update_engine/common/utils.h"
 #include "update_engine/dynamic_partition_control_android.h"
@@ -88,131 +86,12 @@
   return module_->getCurrentSlot();
 }
 
-bool BootControlAndroid::GetSuffix(Slot slot, string* suffix) const {
-  auto store_suffix_cb = [&suffix](hidl_string cb_suffix) {
-    *suffix = cb_suffix.c_str();
-  };
-  Return<void> ret = module_->getSuffix(slot, store_suffix_cb);
-
-  if (!ret.isOk()) {
-    LOG(ERROR) << "boot_control impl returned no suffix for slot "
-               << SlotName(slot);
-    return false;
-  }
-  return true;
-}
-
-bool BootControlAndroid::IsSuperBlockDevice(
-    const base::FilePath& device_dir,
-    Slot slot,
-    const string& partition_name_suffix) const {
-  string source_device =
-      device_dir.Append(dynamic_control_->GetSuperPartitionName(slot)).value();
-  auto source_metadata =
-      dynamic_control_->LoadMetadataBuilder(source_device, slot);
-  return source_metadata->HasBlockDevice(partition_name_suffix);
-}
-
-BootControlAndroid::DynamicPartitionDeviceStatus
-BootControlAndroid::GetDynamicPartitionDevice(
-    const base::FilePath& device_dir,
-    const string& partition_name_suffix,
-    Slot slot,
-    string* device) const {
-  string super_device =
-      device_dir.Append(dynamic_control_->GetSuperPartitionName(slot)).value();
-
-  auto builder = dynamic_control_->LoadMetadataBuilder(super_device, slot);
-
-  if (builder == nullptr) {
-    LOG(ERROR) << "No metadata in slot "
-               << BootControlInterface::SlotName(slot);
-    return DynamicPartitionDeviceStatus::ERROR;
-  }
-
-  Slot current_slot = GetCurrentSlot();
-  if (builder->FindPartition(partition_name_suffix) == nullptr) {
-    LOG(INFO) << partition_name_suffix
-              << " is not in super partition metadata.";
-
-    if (IsSuperBlockDevice(device_dir, current_slot, partition_name_suffix)) {
-      LOG(ERROR) << "The static partition " << partition_name_suffix
-                 << " is a block device for current metadata ("
-                 << dynamic_control_->GetSuperPartitionName(current_slot)
-                 << ", slot " << BootControlInterface::SlotName(current_slot)
-                 << "). It cannot be used as a logical partition.";
-      return DynamicPartitionDeviceStatus::ERROR;
-    }
-
-    return DynamicPartitionDeviceStatus::TRY_STATIC;
-  }
-
-  if (slot == current_slot) {
-    if (dynamic_control_->GetState(partition_name_suffix) !=
-        DmDeviceState::ACTIVE) {
-      LOG(WARNING) << partition_name_suffix << " is at current slot but it is "
-                   << "not mapped. Now try to map it.";
-    } else {
-      if (dynamic_control_->GetDmDevicePathByName(partition_name_suffix,
-                                                  device)) {
-        LOG(INFO) << partition_name_suffix
-                  << " is mapped on device mapper: " << *device;
-        return DynamicPartitionDeviceStatus::SUCCESS;
-      }
-      LOG(ERROR) << partition_name_suffix << "is mapped but path is unknown.";
-      return DynamicPartitionDeviceStatus::ERROR;
-    }
-  }
-
-  bool force_writable = slot != current_slot;
-  if (dynamic_control_->MapPartitionOnDeviceMapper(
-          super_device, partition_name_suffix, slot, force_writable, device)) {
-    return DynamicPartitionDeviceStatus::SUCCESS;
-  }
-  return DynamicPartitionDeviceStatus::ERROR;
-}
 
 bool BootControlAndroid::GetPartitionDevice(const string& partition_name,
                                             Slot slot,
                                             string* device) const {
-  string suffix;
-  if (!GetSuffix(slot, &suffix)) {
-    return false;
-  }
-  const string partition_name_suffix = partition_name + suffix;
-
-  string device_dir_str;
-  if (!dynamic_control_->GetDeviceDir(&device_dir_str)) {
-    return false;
-  }
-  base::FilePath device_dir(device_dir_str);
-
-  // When looking up target partition devices, treat them as static if the
-  // current payload doesn't encode them as dynamic partitions. This may happen
-  // when applying a retrofit update on top of a dynamic-partitions-enabled
-  // build.
-  if (dynamic_control_->GetDynamicPartitionsFeatureFlag().IsEnabled() &&
-      (slot == GetCurrentSlot() || is_target_dynamic_)) {
-    switch (GetDynamicPartitionDevice(
-        device_dir, partition_name_suffix, slot, device)) {
-      case DynamicPartitionDeviceStatus::SUCCESS:
-        return true;
-      case DynamicPartitionDeviceStatus::TRY_STATIC:
-        break;
-      case DynamicPartitionDeviceStatus::ERROR:  // fallthrough
-      default:
-        return false;
-    }
-  }
-
-  base::FilePath path = device_dir.Append(partition_name_suffix);
-  if (!dynamic_control_->DeviceExists(path.value())) {
-    LOG(ERROR) << "Device file " << path.value() << " does not exist.";
-    return false;
-  }
-
-  *device = path.value();
-  return true;
+  return dynamic_control_->GetPartitionDevice(
+      partition_name, slot, GetCurrentSlot(), device);
 }
 
 bool BootControlAndroid::IsSlotBootable(Slot slot) const {
@@ -283,31 +162,8 @@
     Slot target_slot,
     const DeltaArchiveManifest& manifest,
     bool update_metadata) {
-  if (fs_mgr_overlayfs_is_setup()) {
-    // Non DAP devices can use overlayfs as well.
-    LOG(WARNING)
-        << "overlayfs overrides are active and can interfere with our "
-           "resources.\n"
-        << "run adb enable-verity to deactivate if required and try again.";
-  }
-  if (!dynamic_control_->GetDynamicPartitionsFeatureFlag().IsEnabled()) {
-    return true;
-  }
 
   auto source_slot = GetCurrentSlot();
-  if (target_slot == source_slot) {
-    LOG(ERROR) << "Cannot call PreparePartitionsForUpdate on current slot.";
-    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.
-  is_target_dynamic_ = !manifest.dynamic_partition_metadata().groups().empty();
-  if (!is_target_dynamic_) {
-    return true;
-  }
-
   return dynamic_control_->PreparePartitionsForUpdate(
       source_slot, target_slot, manifest, update_metadata);
 }
diff --git a/boot_control_android.h b/boot_control_android.h
index 65543ca..c81f86d 100644
--- a/boot_control_android.h
+++ b/boot_control_android.h
@@ -22,10 +22,10 @@
 #include <string>
 
 #include <android/hardware/boot/1.0/IBootControl.h>
-#include <base/files/file_util.h>
 #include <liblp/builder.h>
 
 #include "update_engine/common/boot_control.h"
+#include "update_engine/dynamic_partition_control_android.h"
 #include "update_engine/dynamic_partition_control_interface.h"
 
 namespace chromeos_update_engine {
@@ -58,35 +58,10 @@
 
  private:
   ::android::sp<::android::hardware::boot::V1_0::IBootControl> module_;
-  std::unique_ptr<DynamicPartitionControlInterface> dynamic_control_;
+  std::unique_ptr<DynamicPartitionControlAndroid> dynamic_control_;
 
   friend class BootControlAndroidTest;
 
-  // Wrapper method of IBootControl::getSuffix().
-  bool GetSuffix(Slot slot, std::string* out) const;
-
-  enum class DynamicPartitionDeviceStatus {
-    SUCCESS,
-    ERROR,
-    TRY_STATIC,
-  };
-
-  DynamicPartitionDeviceStatus GetDynamicPartitionDevice(
-      const base::FilePath& device_dir,
-      const std::string& partition_name_suffix,
-      Slot slot,
-      std::string* device) const;
-
-  // Return true if |partition_name_suffix| is a block device of
-  // super partition metadata slot |slot|.
-  bool IsSuperBlockDevice(const base::FilePath& device_dir,
-                          Slot slot,
-                          const std::string& partition_name_suffix) const;
-
-  // Whether the target partitions should be loaded as dynamic partitions. Set
-  // by PreparePartitionsForUpdate() per each update.
-  bool is_target_dynamic_{false};
-
   DISALLOW_COPY_AND_ASSIGN(BootControlAndroid);
 };
 
diff --git a/boot_control_android_unittest.cc b/boot_control_android_unittest.cc
deleted file mode 100644
index e44af15..0000000
--- a/boot_control_android_unittest.cc
+++ /dev/null
@@ -1,250 +0,0 @@
-//
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include "update_engine/boot_control_android.h"
-
-#include <set>
-#include <vector>
-
-#include <base/logging.h>
-#include <base/strings/string_util.h>
-#include <fs_mgr.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <libdm/dm.h>
-
-#include "update_engine/dynamic_partition_test_utils.h"
-#include "update_engine/mock_boot_control_hal.h"
-#include "update_engine/mock_dynamic_partition_control.h"
-
-using android::dm::DmDeviceState;
-using android::hardware::Void;
-using std::string;
-using testing::_;
-using testing::AnyNumber;
-using testing::Invoke;
-using testing::NiceMock;
-using testing::Not;
-using testing::Return;
-
-namespace chromeos_update_engine {
-
-class BootControlAndroidTest : public ::testing::Test {
- protected:
-  void SetUp() override {
-    // Fake init bootctl_
-    bootctl_.module_ = new NiceMock<MockBootControlHal>();
-    bootctl_.dynamic_control_ =
-        std::make_unique<NiceMock<MockDynamicPartitionControl>>();
-
-    ON_CALL(module(), getNumberSlots()).WillByDefault(Invoke([] {
-      return kMaxNumSlots;
-    }));
-    ON_CALL(module(), getSuffix(_, _))
-        .WillByDefault(Invoke([](auto slot, auto cb) {
-          EXPECT_LE(slot, kMaxNumSlots);
-          cb(slot < kMaxNumSlots ? kSlotSuffixes[slot] : "");
-          return Void();
-        }));
-
-    ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
-        .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
-    ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
-        .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
-    ON_CALL(dynamicControl(), DeviceExists(_)).WillByDefault(Return(true));
-    ON_CALL(dynamicControl(), GetDeviceDir(_))
-        .WillByDefault(Invoke([](auto path) {
-          *path = kFakeDevicePath;
-          return true;
-        }));
-    ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
-        .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
-          *device = GetDmDevice(partition_name_suffix);
-          return true;
-        }));
-
-    ON_CALL(dynamicControl(), GetSuperPartitionName(_))
-        .WillByDefault(Return(kFakeSuper));
-  }
-
-  std::string GetSuperDevice(uint32_t slot) {
-    return GetDevice(dynamicControl().GetSuperPartitionName(slot));
-  }
-
-  // Return the mocked HAL module.
-  NiceMock<MockBootControlHal>& module() {
-    return static_cast<NiceMock<MockBootControlHal>&>(*bootctl_.module_);
-  }
-
-  // Return the mocked DynamicPartitionControlInterface.
-  NiceMock<MockDynamicPartitionControl>& dynamicControl() {
-    return static_cast<NiceMock<MockDynamicPartitionControl>&>(
-        *bootctl_.dynamic_control_);
-  }
-
-  // Set the fake metadata to return when LoadMetadataBuilder is called on
-  // |slot|.
-  void SetMetadata(uint32_t slot, const PartitionSuffixSizes& sizes) {
-    EXPECT_CALL(dynamicControl(),
-                LoadMetadataBuilder(GetSuperDevice(slot), slot))
-        .Times(AnyNumber())
-        .WillRepeatedly(Invoke([sizes](auto, auto) {
-          return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes));
-        }));
-  }
-
-  uint32_t source() { return slots_.source; }
-
-  uint32_t target() { return slots_.target; }
-
-  // Return partition names with suffix of source().
-  string S(const string& name) { return name + kSlotSuffixes[source()]; }
-
-  // Return partition names with suffix of target().
-  string T(const string& name) { return name + kSlotSuffixes[target()]; }
-
-  // Set source and target slots to use before testing.
-  void SetSlots(const TestParam& slots) {
-    slots_ = slots;
-
-    ON_CALL(module(), getCurrentSlot()).WillByDefault(Invoke([this] {
-      return source();
-    }));
-  }
-
-  bool PreparePartitionsForUpdate(uint32_t slot,
-                                  PartitionSizes partition_sizes,
-                                  bool update_metadata = true) {
-    auto m = PartitionSizesToManifest(partition_sizes);
-    return bootctl_.PreparePartitionsForUpdate(slot, m, update_metadata);
-  }
-
-  BootControlAndroid bootctl_;  // BootControlAndroid under test.
-  TestParam slots_;
-};
-
-class BootControlAndroidTestP
-    : public BootControlAndroidTest,
-      public ::testing::WithParamInterface<TestParam> {
- public:
-  void SetUp() override {
-    BootControlAndroidTest::SetUp();
-    SetSlots(GetParam());
-  }
-};
-
-// Test applying retrofit update on a build with dynamic partitions enabled.
-TEST_P(BootControlAndroidTestP,
-       ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
-  SetMetadata(source(),
-              {{S("system"), 2_GiB},
-               {S("vendor"), 1_GiB},
-               {T("system"), 2_GiB},
-               {T("vendor"), 1_GiB}});
-
-  // Not calling through BootControlAndroidTest::PreparePartitionsForUpdate(),
-  // since we don't want any default group in the PartitionMetadata.
-  EXPECT_TRUE(bootctl_.PreparePartitionsForUpdate(target(), {}, true));
-
-  // Should use dynamic source partitions.
-  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);
-
-  // Should use static target partitions without querying dynamic control.
-  EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
-  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(), PreparePartitionsForUpdate(_, _, _, false))
-      .WillOnce(Return(true));
-
-  EXPECT_TRUE(PreparePartitionsForUpdate(
-      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(AnyNumber())
-      .WillOnce(Return(DmDeviceState::ACTIVE));
-  EXPECT_CALL(dynamicControl(),
-              MapPartitionOnDeviceMapper(
-                  GetSuperDevice(target()), T("system"), target(), _, _))
-      .Times(AnyNumber())
-      .WillRepeatedly(
-          Invoke([](const auto&, const auto& name, auto, auto, auto* device) {
-            *device = "/fake/remapped/" + name;
-            return true;
-          }));
-  EXPECT_TRUE(bootctl_.GetPartitionDevice("system", target(), &system_device));
-  EXPECT_EQ("/fake/remapped/" + 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,
-                        BootControlAndroidTestP,
-                        testing::Values(TestParam{0, 1}, TestParam{1, 0}));
-
-TEST_F(BootControlAndroidTest, ApplyingToCurrentSlot) {
-  SetSlots({1, 1});
-  EXPECT_FALSE(PreparePartitionsForUpdate(target(), {}))
-      << "Should not be able to apply to current slot.";
-}
-
-}  // namespace chromeos_update_engine
diff --git a/dynamic_partition_control_android.cc b/dynamic_partition_control_android.cc
index c641a6b..464cdf1 100644
--- a/dynamic_partition_control_android.cc
+++ b/dynamic_partition_control_android.cc
@@ -31,6 +31,8 @@
 #include <bootloader_message/bootloader_message.h>
 #include <fs_mgr.h>
 #include <fs_mgr_dm_linear.h>
+#include <fs_mgr_overlayfs.h>
+#include <libdm/dm.h>
 #include <libsnapshot/snapshot.h>
 
 #include "update_engine/common/boot_control_interface.h"
@@ -354,6 +356,31 @@
     uint32_t target_slot,
     const DeltaArchiveManifest& manifest,
     bool update) {
+  if (fs_mgr_overlayfs_is_setup()) {
+    // Non DAP devices can use overlayfs as well.
+    LOG(WARNING)
+        << "overlayfs overrides are active and can interfere with our "
+           "resources.\n"
+        << "run adb enable-verity to deactivate if required and try again.";
+  }
+
+  if (!GetDynamicPartitionsFeatureFlag().IsEnabled()) {
+    return true;
+  }
+
+  if (target_slot == source_slot) {
+    LOG(ERROR) << "Cannot call PreparePartitionsForUpdate on current slot.";
+    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.
+  is_target_dynamic_ = !manifest.dynamic_partition_metadata().groups().empty();
+  if (!is_target_dynamic_) {
+    return true;
+  }
+
   target_supports_snapshot_ =
       manifest.dynamic_partition_metadata().snapshot_enabled();
 
@@ -532,4 +559,105 @@
   return true;
 }
 
+bool DynamicPartitionControlAndroid::GetPartitionDevice(
+    const std::string& partition_name,
+    uint32_t slot,
+    uint32_t current_slot,
+    std::string* device) {
+  const auto& partition_name_suffix =
+      partition_name + SlotSuffixForSlotNumber(slot);
+  std::string device_dir_str;
+  TEST_AND_RETURN_FALSE(GetDeviceDir(&device_dir_str));
+  base::FilePath device_dir(device_dir_str);
+
+  // When looking up target partition devices, treat them as static if the
+  // current payload doesn't encode them as dynamic partitions. This may happen
+  // when applying a retrofit update on top of a dynamic-partitions-enabled
+  // build.
+  if (GetDynamicPartitionsFeatureFlag().IsEnabled() &&
+      (slot == current_slot || is_target_dynamic_)) {
+    switch (GetDynamicPartitionDevice(
+        device_dir, partition_name_suffix, slot, current_slot, device)) {
+      case DynamicPartitionDeviceStatus::SUCCESS:
+        return true;
+      case DynamicPartitionDeviceStatus::TRY_STATIC:
+        break;
+      case DynamicPartitionDeviceStatus::ERROR:  // fallthrough
+      default:
+        return false;
+    }
+  }
+  base::FilePath path = device_dir.Append(partition_name_suffix);
+  if (!DeviceExists(path.value())) {
+    LOG(ERROR) << "Device file " << path.value() << " does not exist.";
+    return false;
+  }
+
+  *device = path.value();
+  return true;
+}
+
+bool DynamicPartitionControlAndroid::IsSuperBlockDevice(
+    const base::FilePath& device_dir,
+    uint32_t current_slot,
+    const std::string& partition_name_suffix) {
+  std::string source_device =
+      device_dir.Append(GetSuperPartitionName(current_slot)).value();
+  auto source_metadata = LoadMetadataBuilder(source_device, current_slot);
+  return source_metadata->HasBlockDevice(partition_name_suffix);
+}
+
+DynamicPartitionControlAndroid::DynamicPartitionDeviceStatus
+DynamicPartitionControlAndroid::GetDynamicPartitionDevice(
+    const base::FilePath& device_dir,
+    const std::string& partition_name_suffix,
+    uint32_t slot,
+    uint32_t current_slot,
+    std::string* device) {
+  std::string super_device =
+      device_dir.Append(GetSuperPartitionName(slot)).value();
+
+  auto builder = LoadMetadataBuilder(super_device, slot);
+  if (builder == nullptr) {
+    LOG(ERROR) << "No metadata in slot "
+               << BootControlInterface::SlotName(slot);
+    return DynamicPartitionDeviceStatus::ERROR;
+  }
+  if (builder->FindPartition(partition_name_suffix) == nullptr) {
+    LOG(INFO) << partition_name_suffix
+              << " is not in super partition metadata.";
+
+    if (IsSuperBlockDevice(device_dir, current_slot, partition_name_suffix)) {
+      LOG(ERROR) << "The static partition " << partition_name_suffix
+                 << " is a block device for current metadata."
+                 << "It cannot be used as a logical partition.";
+      return DynamicPartitionDeviceStatus::ERROR;
+    }
+
+    return DynamicPartitionDeviceStatus::TRY_STATIC;
+  }
+
+  if (slot == current_slot) {
+    if (GetState(partition_name_suffix) != DmDeviceState::ACTIVE) {
+      LOG(WARNING) << partition_name_suffix << " is at current slot but it is "
+                   << "not mapped. Now try to map it.";
+    } else {
+      if (GetDmDevicePathByName(partition_name_suffix, device)) {
+        LOG(INFO) << partition_name_suffix
+                  << " is mapped on device mapper: " << *device;
+        return DynamicPartitionDeviceStatus::SUCCESS;
+      }
+      LOG(ERROR) << partition_name_suffix << "is mapped but path is unknown.";
+      return DynamicPartitionDeviceStatus::ERROR;
+    }
+  }
+
+  bool force_writable = slot != current_slot;
+  if (MapPartitionOnDeviceMapper(
+          super_device, partition_name_suffix, slot, force_writable, device)) {
+    return DynamicPartitionDeviceStatus::SUCCESS;
+  }
+  return DynamicPartitionDeviceStatus::ERROR;
+}
+
 }  // namespace chromeos_update_engine
diff --git a/dynamic_partition_control_android.h b/dynamic_partition_control_android.h
index 07ce281..af37398 100644
--- a/dynamic_partition_control_android.h
+++ b/dynamic_partition_control_android.h
@@ -23,6 +23,7 @@
 #include <set>
 #include <string>
 
+#include <base/files/file_util.h>
 #include <libsnapshot/auto_device.h>
 #include <libsnapshot/snapshot.h>
 
@@ -34,27 +35,24 @@
   ~DynamicPartitionControlAndroid();
   FeatureFlag GetDynamicPartitionsFeatureFlag() override;
   FeatureFlag GetVirtualAbFeatureFlag() override;
-  bool MapPartitionOnDeviceMapper(const std::string& super_device,
-                                  const std::string& target_partition_name,
-                                  uint32_t slot,
-                                  bool force_writable,
-                                  std::string* path) override;
   void Cleanup() override;
-  bool DeviceExists(const std::string& path) override;
-  android::dm::DmDeviceState GetState(const std::string& name) override;
-  bool GetDmDevicePathByName(const std::string& name,
-                             std::string* path) override;
-  std::unique_ptr<android::fs_mgr::MetadataBuilder> LoadMetadataBuilder(
-      const std::string& super_device, uint32_t source_slot) override;
 
   bool PreparePartitionsForUpdate(uint32_t source_slot,
                                   uint32_t target_slot,
                                   const DeltaArchiveManifest& manifest,
                                   bool update) override;
-  bool GetDeviceDir(std::string* path) override;
-  std::string GetSuperPartitionName(uint32_t slot) override;
   bool FinishUpdate() override;
 
+  // Return the device for partition |partition_name| at slot |slot|.
+  // |current_slot| should be set to the current active slot.
+  // Note: this function is only used by BootControl*::GetPartitionDevice.
+  // Other callers should prefer BootControl*::GetPartitionDevice over
+  // BootControl*::GetDynamicPartitionControl()->GetPartitionDevice().
+  bool GetPartitionDevice(const std::string& partition_name,
+                          uint32_t slot,
+                          uint32_t current_slot,
+                          std::string* device);
+
  protected:
   // These functions are exposed for testing.
 
@@ -84,6 +82,45 @@
                              android::fs_mgr::MetadataBuilder* builder,
                              uint32_t target_slot);
 
+  // Map logical partition on device-mapper.
+  // |super_device| is the device path of the physical partition ("super").
+  // |target_partition_name| is the identifier used in metadata; for example,
+  // "vendor_a"
+  // |slot| is the selected slot to mount; for example, 0 for "_a".
+  // Returns true if mapped successfully; if so, |path| is set to the device
+  // path of the mapped logical partition.
+  virtual bool MapPartitionOnDeviceMapper(
+      const std::string& super_device,
+      const std::string& target_partition_name,
+      uint32_t slot,
+      bool force_writable,
+      std::string* path);
+
+  // Return true if a static partition exists at device path |path|.
+  virtual bool DeviceExists(const std::string& path);
+
+  // Returns the current state of the underlying device mapper device
+  // with given name.
+  // One of INVALID, SUSPENDED or ACTIVE.
+  virtual android::dm::DmDeviceState GetState(const std::string& name);
+
+  // Returns the path to the device mapper device node in '/dev' corresponding
+  // to 'name'. If the device does not exist, false is returned, and the path
+  // parameter is not set.
+  virtual bool GetDmDevicePathByName(const std::string& name,
+                                     std::string* path);
+
+  // Retrieve metadata from |super_device| at slot |source_slot|.
+  virtual std::unique_ptr<android::fs_mgr::MetadataBuilder> LoadMetadataBuilder(
+      const std::string& super_device, uint32_t source_slot);
+
+  // Return a possible location for devices listed by name.
+  virtual bool GetDeviceDir(std::string* path);
+
+  // Return the name of the super partition (which stores super partition
+  // metadata) for a given slot.
+  virtual std::string GetSuperPartitionName(uint32_t slot);
+
  private:
   friend class DynamicPartitionControlAndroidTest;
 
@@ -112,12 +149,38 @@
                                           uint32_t target_slot,
                                           const DeltaArchiveManifest& manifest);
 
+  enum class DynamicPartitionDeviceStatus {
+    SUCCESS,
+    ERROR,
+    TRY_STATIC,
+  };
+
+  // Return SUCCESS and path in |device| if partition is dynamic.
+  // Return ERROR if any error.
+  // Return TRY_STATIC if caller should resolve the partition as a static
+  // partition instead.
+  DynamicPartitionDeviceStatus GetDynamicPartitionDevice(
+      const base::FilePath& device_dir,
+      const std::string& partition_name_suffix,
+      uint32_t slot,
+      uint32_t current_slot,
+      std::string* device);
+
+  // Return true if |partition_name_suffix| is a block device of
+  // super partition metadata slot |slot|.
+  bool IsSuperBlockDevice(const base::FilePath& device_dir,
+                          uint32_t current_slot,
+                          const std::string& partition_name_suffix);
+
   std::set<std::string> mapped_devices_;
   const FeatureFlag dynamic_partitions_;
   const FeatureFlag virtual_ab_;
   std::unique_ptr<android::snapshot::SnapshotManager> snapshot_;
   std::unique_ptr<android::snapshot::AutoDevice> metadata_device_;
   bool target_supports_snapshot_ = false;
+  // Whether the target partitions should be loaded as dynamic partitions. Set
+  // by PreparePartitionsForUpdate() per each update.
+  bool is_target_dynamic_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(DynamicPartitionControlAndroid);
 };
diff --git a/dynamic_partition_control_android_unittest.cc b/dynamic_partition_control_android_unittest.cc
index e8ef1f9..10075ed 100644
--- a/dynamic_partition_control_android_unittest.cc
+++ b/dynamic_partition_control_android_unittest.cc
@@ -27,9 +27,11 @@
 #include "update_engine/dynamic_partition_test_utils.h"
 #include "update_engine/mock_dynamic_partition_control.h"
 
+using android::dm::DmDeviceState;
 using std::string;
 using testing::_;
 using testing::AnyNumber;
+using testing::AnyOf;
 using testing::Invoke;
 using testing::NiceMock;
 using testing::Not;
@@ -55,6 +57,12 @@
 
     ON_CALL(dynamicControl(), GetSuperPartitionName(_))
         .WillByDefault(Return(kFakeSuper));
+
+    ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
+        .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
+          *device = GetDmDevice(partition_name_suffix);
+          return true;
+        }));
   }
 
   // Return the mocked DynamicPartitionControlInterface.
@@ -283,6 +291,122 @@
       << "Should not be able to grow over size of super / 2";
 }
 
+TEST_P(DynamicPartitionControlAndroidTestP,
+       ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
+  ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
+      .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::RETROFIT)));
+  // Static partition {system,bar}_{a,b} exists.
+  EXPECT_CALL(dynamicControl(),
+              DeviceExists(AnyOf(GetDevice(S("bar")),
+                                 GetDevice(T("bar")),
+                                 GetDevice(S("system")),
+                                 GetDevice(T("system")))))
+      .WillRepeatedly(Return(true));
+
+  SetMetadata(source(),
+              {{S("system"), 2_GiB},
+               {S("vendor"), 1_GiB},
+               {T("system"), 2_GiB},
+               {T("vendor"), 1_GiB}});
+
+  // Not calling through
+  // DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we
+  // don't want any default group in the PartitionMetadata.
+  EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
+      source(), target(), {}, true));
+
+  // Should use dynamic source partitions.
+  EXPECT_CALL(dynamicControl(), GetState(S("system")))
+      .Times(1)
+      .WillOnce(Return(DmDeviceState::ACTIVE));
+  string system_device;
+  EXPECT_TRUE(dynamicControl().GetPartitionDevice(
+      "system", source(), 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);
+  EXPECT_TRUE(dynamicControl().GetPartitionDevice(
+      "system", target(), source(), &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(dynamicControl().GetPartitionDevice(
+      "bar", source(), source(), &bar_device));
+  EXPECT_EQ(GetDevice(S("bar")), bar_device);
+
+  EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
+  EXPECT_TRUE(dynamicControl().GetPartitionDevice(
+      "bar", target(), source(), &bar_device));
+  EXPECT_EQ(GetDevice(T("bar")), bar_device);
+}
+
+TEST_P(DynamicPartitionControlAndroidTestP,
+       GetPartitionDeviceWhenResumingUpdate) {
+  // Static partition bar_{a,b} exists.
+  EXPECT_CALL(dynamicControl(),
+              DeviceExists(AnyOf(GetDevice(S("bar")), GetDevice(T("bar")))))
+      .WillRepeatedly(Return(true));
+
+  // 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_TRUE(dynamicControl().PreparePartitionsForUpdate(
+      source(),
+      target(),
+      PartitionSizesToManifest({{"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(dynamicControl().GetPartitionDevice(
+      "system", source(), source(), &system_device));
+  EXPECT_EQ(GetDmDevice(S("system")), system_device);
+
+  EXPECT_CALL(dynamicControl(), GetState(T("system")))
+      .Times(AnyNumber())
+      .WillOnce(Return(DmDeviceState::ACTIVE));
+  EXPECT_CALL(dynamicControl(),
+              MapPartitionOnDeviceMapper(
+                  GetSuperDevice(target()), T("system"), target(), _, _))
+      .Times(AnyNumber())
+      .WillRepeatedly(
+          Invoke([](const auto&, const auto& name, auto, auto, auto* device) {
+            *device = "/fake/remapped/" + name;
+            return true;
+          }));
+  EXPECT_TRUE(dynamicControl().GetPartitionDevice(
+      "system", target(), source(), &system_device));
+  EXPECT_EQ("/fake/remapped/" + T("system"), system_device);
+
+  // Static partition "bar".
+  EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
+  std::string bar_device;
+  EXPECT_TRUE(dynamicControl().GetPartitionDevice(
+      "bar", source(), source(), &bar_device));
+  EXPECT_EQ(GetDevice(S("bar")), bar_device);
+
+  EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
+  EXPECT_TRUE(dynamicControl().GetPartitionDevice(
+      "bar", target(), source(), &bar_device));
+  EXPECT_EQ(GetDevice(T("bar")), bar_device);
+}
+
 INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
                         DynamicPartitionControlAndroidTestP,
                         testing::Values(TestParam{0, 1}, TestParam{1, 0}));
@@ -486,4 +610,10 @@
                                           {"deleted", 64_MiB}}));
 }
 
+TEST_F(DynamicPartitionControlAndroidTest, ApplyingToCurrentSlot) {
+  SetSlots({1, 1});
+  EXPECT_FALSE(PreparePartitionsForUpdate({}))
+      << "Should not be able to apply to current slot.";
+}
+
 }  // namespace chromeos_update_engine
diff --git a/dynamic_partition_control_interface.h b/dynamic_partition_control_interface.h
index 9c18973..b5be2be 100644
--- a/dynamic_partition_control_interface.h
+++ b/dynamic_partition_control_interface.h
@@ -22,11 +22,6 @@
 #include <memory>
 #include <string>
 
-#include <base/files/file_util.h>
-#include <libdm/dm.h>
-#include <liblp/builder.h>
-
-#include "update_engine/common/boot_control_interface.h"
 #include "update_engine/update_metadata.pb.h"
 
 namespace chromeos_update_engine {
@@ -55,41 +50,9 @@
   // Return the feature flags of Virtual A/B on this device.
   virtual FeatureFlag GetVirtualAbFeatureFlag() = 0;
 
-  // Map logical partition on device-mapper.
-  // |super_device| is the device path of the physical partition ("super").
-  // |target_partition_name| is the identifier used in metadata; for example,
-  // "vendor_a"
-  // |slot| is the selected slot to mount; for example, 0 for "_a".
-  // Returns true if mapped successfully; if so, |path| is set to the device
-  // path of the mapped logical partition.
-  virtual bool MapPartitionOnDeviceMapper(
-      const std::string& super_device,
-      const std::string& target_partition_name,
-      uint32_t slot,
-      bool force_writable,
-      std::string* path) = 0;
-
   // Do necessary cleanups before destroying the object.
   virtual void Cleanup() = 0;
 
-  // Return true if a static partition exists at device path |path|.
-  virtual bool DeviceExists(const std::string& path) = 0;
-
-  // Returns the current state of the underlying device mapper device
-  // with given name.
-  // One of INVALID, SUSPENDED or ACTIVE.
-  virtual android::dm::DmDeviceState GetState(const std::string& name) = 0;
-
-  // Returns the path to the device mapper device node in '/dev' corresponding
-  // to 'name'. If the device does not exist, false is returned, and the path
-  // parameter is not set.
-  virtual bool GetDmDevicePathByName(const std::string& name,
-                                     std::string* path) = 0;
-
-  // Retrieve metadata from |super_device| at slot |source_slot|.
-  virtual std::unique_ptr<android::fs_mgr::MetadataBuilder> LoadMetadataBuilder(
-      const std::string& super_device, uint32_t source_slot) = 0;
-
   // Prepare all partitions for an update specified in |manifest|.
   // This is needed before calling MapPartitionOnDeviceMapper(), otherwise the
   // device would be mapped in an inconsistent way.
@@ -99,13 +62,6 @@
                                           const DeltaArchiveManifest& manifest,
                                           bool update) = 0;
 
-  // Return a possible location for devices listed by name.
-  virtual bool GetDeviceDir(std::string* path) = 0;
-
-  // Return the name of the super partition (which stores super partition
-  // metadata) for a given slot.
-  virtual std::string GetSuperPartitionName(uint32_t slot) = 0;
-
   virtual bool FinishUpdate() = 0;
 };
 
diff --git a/mock_dynamic_partition_control.h b/mock_dynamic_partition_control.h
index 8146e0f..67b3998 100644
--- a/mock_dynamic_partition_control.h
+++ b/mock_dynamic_partition_control.h
@@ -36,17 +36,9 @@
                     bool,
                     std::string*));
   MOCK_METHOD0(Cleanup, void());
-  MOCK_METHOD1(DeviceExists, bool(const std::string&));
-  MOCK_METHOD1(GetState, ::android::dm::DmDeviceState(const std::string&));
-  MOCK_METHOD2(GetDmDevicePathByName, bool(const std::string&, std::string*));
-  MOCK_METHOD2(LoadMetadataBuilder,
-               std::unique_ptr<::android::fs_mgr::MetadataBuilder>(
-                   const std::string&, uint32_t));
-  MOCK_METHOD1(GetDeviceDir, bool(std::string*));
   MOCK_METHOD0(GetDynamicPartitionsFeatureFlag, FeatureFlag());
   MOCK_METHOD4(PreparePartitionsForUpdate,
                bool(uint32_t, uint32_t, const DeltaArchiveManifest&, bool));
-  MOCK_METHOD1(GetSuperPartitionName, std::string(uint32_t));
   MOCK_METHOD0(GetVirtualAbFeatureFlag, FeatureFlag());
   MOCK_METHOD0(FinishUpdate, bool());
 };