Snap for 6439596 from 92f188b249cd0a99e50a04c6f70df207d66defc1 to qt-aml-tzdata-release

Change-Id: Ife2ff0109b56469285ec6aec6c08fdfb0f78d3ce
diff --git a/.clang-format b/.clang-format
index 3b6a627..c1244fe 100644
--- a/.clang-format
+++ b/.clang-format
@@ -34,6 +34,5 @@
 BinPackParameters: false
 CommentPragmas: NOLINT:.*
 DerivePointerAlignment: false
-IncludeBlocks: Preserve
 PointerAlignment: Left
 TabWidth: 2
diff --git a/Android.bp b/Android.bp
index d6f1090..284845d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -128,7 +128,6 @@
         "libverity_tree",
     ],
     shared_libs: [
-        "libziparchive",
         "libbase",
         "libcrypto",
         "libfec",
@@ -165,7 +164,6 @@
         "common/utils.cc",
         "payload_consumer/bzip_extent_writer.cc",
         "payload_consumer/cached_file_descriptor.cc",
-        "payload_consumer/certificate_parser_android.cc",
         "payload_consumer/delta_performer.cc",
         "payload_consumer/download_action.cc",
         "payload_consumer/extent_reader.cc",
@@ -193,25 +191,16 @@
     name: "libupdate_engine_boot_control_exports",
     defaults: ["update_metadata-protos_exports"],
 
-    static_libs: [
-        "libsnapshot",
-        "update_metadata-protos",
-    ],
+    static_libs: ["update_metadata-protos"],
     shared_libs: [
         "libbootloader_message",
         "libfs_mgr",
+        "libhwbinder",
         "libhidlbase",
         "liblp",
         "libutils",
         "android.hardware.boot@1.0",
-        "android.hardware.boot@1.1",
     ],
-    target: {
-        recovery: {
-            static_libs: ["libsnapshot_nobinder"],
-            exclude_static_libs: ["libsnapshot"],
-        },
-    },
 }
 
 cc_library_static {
@@ -225,7 +214,6 @@
     srcs: [
         "boot_control_android.cc",
         "dynamic_partition_control_android.cc",
-        "dynamic_partition_utils.cc",
     ],
 }
 
@@ -305,10 +293,7 @@
     ],
 
     static_libs: ["libupdate_engine_android"],
-    required: [
-        "cacerts_google",
-        "otacerts",
-    ],
+    required: ["cacerts_google"],
 
     srcs: ["main.cc"],
     init_rc: ["update_engine.rc"],
@@ -339,7 +324,6 @@
         "metrics_reporter_stub.cc",
         "metrics_utils.cc",
         "network_selector_stub.cc",
-        "sideload_logging_android.cc",
         "sideload_main.cc",
         "update_attempter_android.cc",
         "update_boot_flags_action.cc",
@@ -374,6 +358,7 @@
         recovery: {
             exclude_shared_libs: [
                 "libprotobuf-cpp-lite",
+                "libhwbinder",
                 "libbrillo-stream",
                 "libbrillo",
                 "libchrome",
@@ -381,9 +366,7 @@
         },
     },
 
-    required: [
-        "otacerts.recovery",
-    ],
+    required: ["android.hardware.boot@1.0-impl-wrapper.recovery"],
 }
 
 // libupdate_engine_client (type: shared_library)
@@ -417,7 +400,8 @@
     ],
 
     srcs: [
-        ":libupdate_engine_client_aidl",
+        "binder_bindings/android/brillo/IUpdateEngine.aidl",
+        "binder_bindings/android/brillo/IUpdateEngineStatusCallback.aidl",
         "client_library/client.cc",
         "client_library/client_binder.cc",
         "parcelable_update_engine_status.cc",
@@ -425,15 +409,6 @@
     ],
 }
 
-filegroup {
-    name: "libupdate_engine_client_aidl",
-    srcs: [
-        "binder_bindings/android/brillo/IUpdateEngine.aidl",
-        "binder_bindings/android/brillo/IUpdateEngineStatusCallback.aidl",
-    ],
-    path: "binder_bindings",
-}
-
 // update_engine_client (type: executable)
 // ========================================================
 // update_engine console client.
@@ -569,6 +544,8 @@
 
     gtest: false,
     stem: "delta_generator",
+    relative_install_path: "update_engine_unittests",
+    no_named_install_directory: true,
 }
 
 // test_http_server (type: executable)
@@ -583,6 +560,8 @@
     ],
 
     gtest: false,
+    relative_install_path: "update_engine_unittests",
+    no_named_install_directory: true,
 }
 
 // test_subprocess (type: executable)
@@ -594,6 +573,8 @@
     srcs: ["test_subprocess.cc"],
 
     gtest: false,
+    relative_install_path: "update_engine_unittests",
+    no_named_install_directory: true,
 }
 
 // Public keys for unittests.
@@ -602,19 +583,16 @@
     name: "ue_unittest_keys",
     cmd: "openssl rsa -in $(location unittest_key.pem) -pubout -out $(location unittest_key.pub.pem) &&" +
         "openssl rsa -in $(location unittest_key2.pem) -pubout -out $(location unittest_key2.pub.pem) &&" +
-        "openssl rsa -in $(location unittest_key_RSA4096.pem) -pubout -out $(location unittest_key_RSA4096.pub.pem) &&" +
-        "openssl pkey -in $(location unittest_key_EC.pem) -pubout -out $(location unittest_key_EC.pub.pem)",
+        "openssl rsa -in $(location unittest_key_RSA4096.pem) -pubout -out $(location unittest_key_RSA4096.pub.pem)",
     srcs: [
         "unittest_key.pem",
         "unittest_key2.pem",
         "unittest_key_RSA4096.pem",
-        "unittest_key_EC.pem",
     ],
     out: [
         "unittest_key.pub.pem",
         "unittest_key2.pub.pem",
         "unittest_key_RSA4096.pub.pem",
-        "unittest_key_EC.pub.pem",
     ],
 }
 
@@ -644,6 +622,11 @@
         "libpayload_generator_exports",
         "libupdate_engine_android_exports",
     ],
+    required: [
+        "test_http_server",
+        "test_subprocess",
+        "ue_unittest_delta_generator",
+    ],
 
     static_libs: [
         "libpayload_generator",
@@ -652,30 +635,19 @@
         "libchrome_test_helpers",
         "libupdate_engine_android",
     ],
-
-    header_libs: [
-        "libstorage_literals_headers",
+    shared_libs: [
+        "libhidltransport",
     ],
 
     data: [
-        ":test_http_server",
-        ":test_subprocess",
-        ":ue_unittest_delta_generator",
         ":ue_unittest_disk_imgs",
         ":ue_unittest_keys",
-        "otacerts.zip",
         "unittest_key.pem",
         "unittest_key2.pem",
         "unittest_key_RSA4096.pem",
-        "unittest_key_EC.pem",
         "update_engine.conf",
     ],
 
-    // We cannot use the default generated AndroidTest.xml because of the use of helper modules
-    // (i.e. test_http_server, test_subprocess, ue_unittest_delta_generator).
-    test_config: "test_config.xml",
-    test_suites: ["device-tests"],
-
     srcs: [
         "boot_control_android_unittest.cc",
         "certificate_checker_unittest.cc",
@@ -695,10 +667,8 @@
         "common/terminator_unittest.cc",
         "common/test_utils.cc",
         "common/utils_unittest.cc",
-        "dynamic_partition_control_android_unittest.cc",
         "payload_consumer/bzip_extent_writer_unittest.cc",
         "payload_consumer/cached_file_descriptor_unittest.cc",
-        "payload_consumer/certificate_parser_android_unittest.cc",
         "payload_consumer/delta_performer_integration_test.cc",
         "payload_consumer/delta_performer_unittest.cc",
         "payload_consumer/extent_reader_unittest.cc",
diff --git a/binder_bindings/android/os/IUpdateEngine.aidl b/binder_bindings/android/os/IUpdateEngine.aidl
index 1305079..c0e29f5 100644
--- a/binder_bindings/android/os/IUpdateEngine.aidl
+++ b/binder_bindings/android/os/IUpdateEngine.aidl
@@ -17,7 +17,6 @@
 package android.os;
 
 import android.os.IUpdateEngineCallback;
-import android.os.ParcelFileDescriptor;
 
 /** @hide */
 interface IUpdateEngine {
@@ -27,11 +26,6 @@
                     in long payload_size,
                     in String[] headerKeyValuePairs);
   /** @hide */
-  void applyPayloadFd(in ParcelFileDescriptor pfd,
-                      in long payload_offset,
-                      in long payload_size,
-                      in String[] headerKeyValuePairs);
-  /** @hide */
   boolean bind(IUpdateEngineCallback callback);
   /** @hide */
   boolean unbind(IUpdateEngineCallback callback);
diff --git a/binder_bindings/android/os/IUpdateEngineCallback.aidl b/binder_bindings/android/os/IUpdateEngineCallback.aidl
index 4bacf9a..ee15c8b 100644
--- a/binder_bindings/android/os/IUpdateEngineCallback.aidl
+++ b/binder_bindings/android/os/IUpdateEngineCallback.aidl
@@ -19,7 +19,6 @@
 /** @hide */
 oneway interface IUpdateEngineCallback {
   /** @hide */
-  @UnsupportedAppUsage
   void onStatusUpdate(int status_code, float percentage);
   /** @hide */
   void onPayloadApplicationComplete(int error_code);
diff --git a/binder_service_android.cc b/binder_service_android.cc
index 88bc1f2..137694a 100644
--- a/binder_service_android.cc
+++ b/binder_service_android.cc
@@ -24,9 +24,6 @@
 
 using android::binder::Status;
 using android::os::IUpdateEngineCallback;
-using android::os::ParcelFileDescriptor;
-using std::string;
-using std::vector;
 using update_engine::UpdateEngineStatus;
 
 namespace {
@@ -97,9 +94,9 @@
     const android::String16& url,
     int64_t payload_offset,
     int64_t payload_size,
-    const vector<android::String16>& header_kv_pairs) {
-  const string payload_url{android::String8{url}.string()};
-  vector<string> str_headers;
+    const std::vector<android::String16>& header_kv_pairs) {
+  const std::string payload_url{android::String8{url}.string()};
+  std::vector<std::string> str_headers;
   str_headers.reserve(header_kv_pairs.size());
   for (const auto& header : header_kv_pairs) {
     str_headers.emplace_back(android::String8{header}.string());
@@ -113,25 +110,6 @@
   return Status::ok();
 }
 
-Status BinderUpdateEngineAndroidService::applyPayloadFd(
-    const ParcelFileDescriptor& pfd,
-    int64_t payload_offset,
-    int64_t payload_size,
-    const vector<android::String16>& header_kv_pairs) {
-  vector<string> str_headers;
-  str_headers.reserve(header_kv_pairs.size());
-  for (const auto& header : header_kv_pairs) {
-    str_headers.emplace_back(android::String8{header}.string());
-  }
-
-  brillo::ErrorPtr error;
-  if (!service_delegate_->ApplyPayload(
-          pfd.get(), payload_offset, payload_size, str_headers, &error)) {
-    return ErrorPtrToStatus(error);
-  }
-  return Status::ok();
-}
-
 Status BinderUpdateEngineAndroidService::suspend() {
   brillo::ErrorPtr error;
   if (!service_delegate_->SuspendUpdate(&error))
diff --git a/binder_service_android.h b/binder_service_android.h
index 0dda93b..d8c4e9c 100644
--- a/binder_service_android.h
+++ b/binder_service_android.h
@@ -53,11 +53,6 @@
       int64_t payload_offset,
       int64_t payload_size,
       const std::vector<android::String16>& header_kv_pairs) override;
-  android::binder::Status applyPayloadFd(
-      const ::android::os::ParcelFileDescriptor& pfd,
-      int64_t payload_offset,
-      int64_t payload_size,
-      const std::vector<android::String16>& header_kv_pairs) override;
   android::binder::Status bind(
       const android::sp<android::os::IUpdateEngineCallback>& callback,
       bool* return_value) override;
diff --git a/boot_control_android.cc b/boot_control_android.cc
index b1d775e..1fab85f 100644
--- a/boot_control_android.cc
+++ b/boot_control_android.cc
@@ -22,10 +22,11 @@
 
 #include <base/bind.h>
 #include <base/logging.h>
+#include <base/strings/string_util.h>
 #include <bootloader_message/bootloader_message.h>
 #include <brillo/message_loops/message_loop.h>
+#include <fs_mgr.h>
 #include <fs_mgr_overlayfs.h>
-#include <libdm/dm.h>
 
 #include "update_engine/common/utils.h"
 #include "update_engine/dynamic_partition_control_android.h"
@@ -33,12 +34,15 @@
 using std::string;
 
 using android::dm::DmDeviceState;
+using android::fs_mgr::Partition;
 using android::hardware::hidl_string;
 using android::hardware::Return;
 using android::hardware::boot::V1_0::BoolResult;
 using android::hardware::boot::V1_0::CommandResult;
 using android::hardware::boot::V1_0::IBootControl;
 using Slot = chromeos_update_engine::BootControlInterface::Slot;
+using PartitionMetadata =
+    chromeos_update_engine::BootControlInterface::PartitionMetadata;
 
 namespace {
 
@@ -107,9 +111,9 @@
     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);
+      device_dir.Append(fs_mgr_get_super_partition_name(slot)).value();
+  auto source_metadata = dynamic_control_->LoadMetadataBuilder(
+      source_device, slot, BootControlInterface::kInvalidSlot);
   return source_metadata->HasBlockDevice(partition_name_suffix);
 }
 
@@ -120,9 +124,10 @@
     Slot slot,
     string* device) const {
   string super_device =
-      device_dir.Append(dynamic_control_->GetSuperPartitionName(slot)).value();
+      device_dir.Append(fs_mgr_get_super_partition_name(slot)).value();
 
-  auto builder = dynamic_control_->LoadMetadataBuilder(super_device, slot);
+  auto builder = dynamic_control_->LoadMetadataBuilder(
+      super_device, slot, BootControlInterface::kInvalidSlot);
 
   if (builder == nullptr) {
     LOG(ERROR) << "No metadata in slot "
@@ -138,8 +143,8 @@
     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)
+                 << fs_mgr_get_super_partition_name(current_slot) << ", slot "
+                 << BootControlInterface::SlotName(current_slot)
                  << "). It cannot be used as a logical partition.";
       return DynamicPartitionDeviceStatus::ERROR;
     }
@@ -191,7 +196,7 @@
   // 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() &&
+  if (dynamic_control_->IsDynamicPartitionsEnabled() &&
       (slot == GetCurrentSlot() || is_target_dynamic_)) {
     switch (GetDynamicPartitionDevice(
         device_dir, partition_name_suffix, slot, device)) {
@@ -245,10 +250,6 @@
 }
 
 bool BootControlAndroid::SetActiveBootSlot(Slot slot) {
-  if (slot != GetCurrentSlot() && !dynamic_control_->FinishUpdate()) {
-    return false;
-  }
-
   CommandResult result;
   auto ret = module_->setActiveBootSlot(slot, StoreResultCallback(&result));
   if (!ret.isOk()) {
@@ -279,9 +280,113 @@
          brillo::MessageLoop::kTaskIdNull;
 }
 
-bool BootControlAndroid::PreparePartitionsForUpdate(
+namespace {
+
+bool UpdatePartitionMetadata(DynamicPartitionControlInterface* dynamic_control,
+                             Slot source_slot,
+                             Slot target_slot,
+                             const string& target_suffix,
+                             const PartitionMetadata& partition_metadata) {
+  string device_dir_str;
+  if (!dynamic_control->GetDeviceDir(&device_dir_str)) {
+    return false;
+  }
+  base::FilePath device_dir(device_dir_str);
+  auto source_device =
+      device_dir.Append(fs_mgr_get_super_partition_name(source_slot)).value();
+
+  auto builder = dynamic_control->LoadMetadataBuilder(
+      source_device, source_slot, target_slot);
+  if (builder == nullptr) {
+    // TODO(elsk): allow reconstructing metadata from partition_metadata
+    // in recovery sideload.
+    LOG(ERROR) << "No metadata at "
+               << BootControlInterface::SlotName(source_slot);
+    return false;
+  }
+
+  std::vector<string> groups = builder->ListGroups();
+  for (const auto& group_name : groups) {
+    if (base::EndsWith(
+            group_name, target_suffix, base::CompareCase::SENSITIVE)) {
+      LOG(INFO) << "Removing group " << group_name;
+      builder->RemoveGroupAndPartitions(group_name);
+    }
+  }
+
+  uint64_t total_size = 0;
+  for (const auto& group : partition_metadata.groups) {
+    total_size += group.size;
+  }
+
+  string expr;
+  uint64_t allocatable_space = builder->AllocatableSpace();
+  if (!dynamic_control->IsDynamicPartitionsRetrofit()) {
+    allocatable_space /= 2;
+    expr = "half of ";
+  }
+  if (total_size > allocatable_space) {
+    LOG(ERROR) << "The maximum size of all groups with suffix " << target_suffix
+               << " (" << total_size << ") has exceeded " << expr
+               << " allocatable space for dynamic partitions "
+               << allocatable_space << ".";
+    return false;
+  }
+
+  for (const auto& group : partition_metadata.groups) {
+    auto group_name_suffix = group.name + target_suffix;
+    if (!builder->AddGroup(group_name_suffix, group.size)) {
+      LOG(ERROR) << "Cannot add group " << group_name_suffix << " with size "
+                 << group.size;
+      return false;
+    }
+    LOG(INFO) << "Added group " << group_name_suffix << " with size "
+              << group.size;
+
+    for (const auto& partition : group.partitions) {
+      auto partition_name_suffix = partition.name + target_suffix;
+      Partition* p = builder->AddPartition(
+          partition_name_suffix, group_name_suffix, LP_PARTITION_ATTR_READONLY);
+      if (!p) {
+        LOG(ERROR) << "Cannot add partition " << partition_name_suffix
+                   << " to group " << group_name_suffix;
+        return false;
+      }
+      if (!builder->ResizePartition(p, partition.size)) {
+        LOG(ERROR) << "Cannot resize partition " << partition_name_suffix
+                   << " to size " << partition.size << ". Not enough space?";
+        return false;
+      }
+      LOG(INFO) << "Added partition " << partition_name_suffix << " to group "
+                << group_name_suffix << " with size " << partition.size;
+    }
+  }
+
+  auto target_device =
+      device_dir.Append(fs_mgr_get_super_partition_name(target_slot)).value();
+  return dynamic_control->StoreMetadata(
+      target_device, builder.get(), target_slot);
+}
+
+bool UnmapTargetPartitions(DynamicPartitionControlInterface* dynamic_control,
+                           const string& target_suffix,
+                           const PartitionMetadata& partition_metadata) {
+  for (const auto& group : partition_metadata.groups) {
+    for (const auto& partition : group.partitions) {
+      if (!dynamic_control->UnmapPartitionOnDeviceMapper(
+              partition.name + target_suffix, true /* wait */)) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+}  // namespace
+
+bool BootControlAndroid::InitPartitionMetadata(
     Slot target_slot,
-    const DeltaArchiveManifest& manifest,
+    const PartitionMetadata& partition_metadata,
     bool update_metadata) {
   if (fs_mgr_overlayfs_is_setup()) {
     // Non DAP devices can use overlayfs as well.
@@ -290,26 +395,45 @@
            "resources.\n"
         << "run adb enable-verity to deactivate if required and try again.";
   }
-  if (!dynamic_control_->GetDynamicPartitionsFeatureFlag().IsEnabled()) {
+  if (!dynamic_control_->IsDynamicPartitionsEnabled()) {
     return true;
   }
 
   auto source_slot = GetCurrentSlot();
   if (target_slot == source_slot) {
-    LOG(ERROR) << "Cannot call PreparePartitionsForUpdate on current slot.";
+    LOG(ERROR) << "Cannot call InitPartitionMetadata 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();
+  is_target_dynamic_ = !partition_metadata.groups.empty();
   if (!is_target_dynamic_) {
     return true;
   }
 
-  return dynamic_control_->PreparePartitionsForUpdate(
-      source_slot, target_slot, manifest, update_metadata);
+  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(
+          dynamic_control_.get(), target_suffix, partition_metadata)) {
+    return false;
+  }
+
+  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 65543ca..a6f33be 100644
--- a/boot_control_android.h
+++ b/boot_control_android.h
@@ -51,9 +51,9 @@
   bool MarkSlotUnbootable(BootControlInterface::Slot slot) override;
   bool SetActiveBootSlot(BootControlInterface::Slot slot) override;
   bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override;
-  bool PreparePartitionsForUpdate(Slot slot,
-                                  const DeltaArchiveManifest& manifest,
-                                  bool update_metadata) override;
+  bool InitPartitionMetadata(Slot slot,
+                             const PartitionMetadata& partition_metadata,
+                             bool update_metadata) override;
   void Cleanup() override;
 
  private:
@@ -84,7 +84,7 @@
                           const std::string& partition_name_suffix) const;
 
   // Whether the target partitions should be loaded as dynamic partitions. Set
-  // by PreparePartitionsForUpdate() per each update.
+  // by InitPartitionMetadata() 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
index e44af15..b2885a3 100644
--- a/boot_control_android_unittest.cc
+++ b/boot_control_android_unittest.cc
@@ -26,22 +26,236 @@
 #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::fs_mgr::MetadataBuilder;
 using android::hardware::Void;
 using std::string;
 using testing::_;
 using testing::AnyNumber;
+using testing::Contains;
+using testing::Eq;
 using testing::Invoke;
+using testing::Key;
+using testing::MakeMatcher;
+using testing::Matcher;
+using testing::MatcherInterface;
+using testing::MatchResultListener;
 using testing::NiceMock;
 using testing::Not;
 using testing::Return;
 
 namespace chromeos_update_engine {
 
+constexpr const uint32_t kMaxNumSlots = 2;
+constexpr const char* kSlotSuffixes[kMaxNumSlots] = {"_a", "_b"};
+constexpr const char* kFakeDevicePath = "/fake/dev/path/";
+constexpr const char* kFakeDmDevicePath = "/fake/dm/dev/path/";
+constexpr const uint32_t kFakeMetadataSize = 65536;
+constexpr const char* kDefaultGroup = "foo";
+
+// A map describing the size of each partition.
+// "{name, size}"
+using PartitionSizes = std::map<string, uint64_t>;
+
+// "{name_a, size}"
+using PartitionSuffixSizes = std::map<string, uint64_t>;
+
+using PartitionMetadata = BootControlInterface::PartitionMetadata;
+
+// C++ standards do not allow uint64_t (aka unsigned long) to be the parameter
+// of user-defined literal operators.
+constexpr unsigned long long operator"" _MiB(unsigned long long x) {  // NOLINT
+  return x << 20;
+}
+constexpr unsigned long long operator"" _GiB(unsigned long long x) {  // NOLINT
+  return x << 30;
+}
+
+constexpr uint64_t kDefaultGroupSize = 5_GiB;
+// Super device size. 1 MiB for metadata.
+constexpr uint64_t kDefaultSuperSize = kDefaultGroupSize * 2 + 1_MiB;
+
+template <typename U, typename V>
+std::ostream& operator<<(std::ostream& os, const std::map<U, V>& param) {
+  os << "{";
+  bool first = true;
+  for (const auto& pair : param) {
+    if (!first)
+      os << ", ";
+    os << pair.first << ":" << pair.second;
+    first = false;
+  }
+  return os << "}";
+}
+
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const std::vector<T>& param) {
+  os << "[";
+  bool first = true;
+  for (const auto& e : param) {
+    if (!first)
+      os << ", ";
+    os << e;
+    first = false;
+  }
+  return os << "]";
+}
+
+std::ostream& operator<<(std::ostream& os,
+                         const PartitionMetadata::Partition& p) {
+  return os << "{" << p.name << ", " << p.size << "}";
+}
+
+std::ostream& operator<<(std::ostream& os, const PartitionMetadata::Group& g) {
+  return os << "{" << g.name << ", " << g.size << ", " << g.partitions << "}";
+}
+
+std::ostream& operator<<(std::ostream& os, const PartitionMetadata& m) {
+  return os << m.groups;
+}
+
+inline string GetDevice(const string& name) {
+  return kFakeDevicePath + name;
+}
+
+inline string GetDmDevice(const string& name) {
+  return kFakeDmDevicePath + name;
+}
+
+// TODO(elsk): fs_mgr_get_super_partition_name should be mocked.
+inline string GetSuperDevice(uint32_t slot) {
+  return GetDevice(fs_mgr_get_super_partition_name(slot));
+}
+
+struct TestParam {
+  uint32_t source;
+  uint32_t target;
+};
+std::ostream& operator<<(std::ostream& os, const TestParam& param) {
+  return os << "{source: " << param.source << ", target:" << param.target
+            << "}";
+}
+
+// To support legacy tests, auto-convert {name_a: size} map to
+// PartitionMetadata.
+PartitionMetadata partitionSuffixSizesToMetadata(
+    const PartitionSuffixSizes& partition_sizes) {
+  PartitionMetadata metadata;
+  for (const char* suffix : kSlotSuffixes) {
+    metadata.groups.push_back(
+        {string(kDefaultGroup) + suffix, kDefaultGroupSize, {}});
+  }
+  for (const auto& pair : partition_sizes) {
+    for (size_t suffix_idx = 0; suffix_idx < kMaxNumSlots; ++suffix_idx) {
+      if (base::EndsWith(pair.first,
+                         kSlotSuffixes[suffix_idx],
+                         base::CompareCase::SENSITIVE)) {
+        metadata.groups[suffix_idx].partitions.push_back(
+            {pair.first, pair.second});
+      }
+    }
+  }
+  return metadata;
+}
+
+// To support legacy tests, auto-convert {name: size} map to PartitionMetadata.
+PartitionMetadata partitionSizesToMetadata(
+    const PartitionSizes& partition_sizes) {
+  PartitionMetadata metadata;
+  metadata.groups.push_back({string{kDefaultGroup}, kDefaultGroupSize, {}});
+  for (const auto& pair : partition_sizes) {
+    metadata.groups[0].partitions.push_back({pair.first, pair.second});
+  }
+  return metadata;
+}
+
+std::unique_ptr<MetadataBuilder> NewFakeMetadata(
+    const PartitionMetadata& metadata) {
+  auto builder =
+      MetadataBuilder::New(kDefaultSuperSize, kFakeMetadataSize, kMaxNumSlots);
+  EXPECT_GE(builder->AllocatableSpace(), kDefaultGroupSize * 2);
+  EXPECT_NE(nullptr, builder);
+  if (builder == nullptr)
+    return nullptr;
+  for (const auto& group : metadata.groups) {
+    EXPECT_TRUE(builder->AddGroup(group.name, group.size));
+    for (const auto& partition : group.partitions) {
+      auto p = builder->AddPartition(partition.name, group.name, 0 /* attr */);
+      EXPECT_TRUE(p && builder->ResizePartition(p, partition.size));
+    }
+  }
+  return builder;
+}
+
+class MetadataMatcher : public MatcherInterface<MetadataBuilder*> {
+ public:
+  explicit MetadataMatcher(const PartitionSuffixSizes& partition_sizes)
+      : partition_metadata_(partitionSuffixSizesToMetadata(partition_sizes)) {}
+  explicit MetadataMatcher(const PartitionMetadata& partition_metadata)
+      : partition_metadata_(partition_metadata) {}
+
+  bool MatchAndExplain(MetadataBuilder* metadata,
+                       MatchResultListener* listener) const override {
+    bool success = true;
+    for (const auto& group : partition_metadata_.groups) {
+      for (const auto& partition : group.partitions) {
+        auto p = metadata->FindPartition(partition.name);
+        if (p == nullptr) {
+          if (!success)
+            *listener << "; ";
+          *listener << "No partition " << partition.name;
+          success = false;
+          continue;
+        }
+        if (p->size() != partition.size) {
+          if (!success)
+            *listener << "; ";
+          *listener << "Partition " << partition.name << " has size "
+                    << p->size() << ", expected " << partition.size;
+          success = false;
+        }
+        if (p->group_name() != group.name) {
+          if (!success)
+            *listener << "; ";
+          *listener << "Partition " << partition.name << " has group "
+                    << p->group_name() << ", expected " << group.name;
+          success = false;
+        }
+      }
+    }
+    return success;
+  }
+
+  void DescribeTo(std::ostream* os) const override {
+    *os << "expect: " << partition_metadata_;
+  }
+
+  void DescribeNegationTo(std::ostream* os) const override {
+    *os << "expect not: " << partition_metadata_;
+  }
+
+ private:
+  PartitionMetadata partition_metadata_;
+};
+
+inline Matcher<MetadataBuilder*> MetadataMatches(
+    const PartitionSuffixSizes& partition_sizes) {
+  return MakeMatcher(new MetadataMatcher(partition_sizes));
+}
+
+inline Matcher<MetadataBuilder*> MetadataMatches(
+    const PartitionMetadata& partition_metadata) {
+  return MakeMatcher(new MetadataMatcher(partition_metadata));
+}
+
+MATCHER_P(HasGroup, group, " has group " + group) {
+  auto groups = arg->ListGroups();
+  return std::find(groups.begin(), groups.end(), group) != groups.end();
+}
+
 class BootControlAndroidTest : public ::testing::Test {
  protected:
   void SetUp() override {
@@ -60,10 +274,10 @@
           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(), IsDynamicPartitionsEnabled())
+        .WillByDefault(Return(true));
+    ON_CALL(dynamicControl(), IsDynamicPartitionsRetrofit())
+        .WillByDefault(Return(false));
     ON_CALL(dynamicControl(), DeviceExists(_)).WillByDefault(Return(true));
     ON_CALL(dynamicControl(), GetDeviceDir(_))
         .WillByDefault(Invoke([](auto path) {
@@ -75,13 +289,6 @@
           *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.
@@ -98,14 +305,53 @@
   // Set the fake metadata to return when LoadMetadataBuilder is called on
   // |slot|.
   void SetMetadata(uint32_t slot, const PartitionSuffixSizes& sizes) {
+    SetMetadata(slot, partitionSuffixSizesToMetadata(sizes));
+  }
+
+  void SetMetadata(uint32_t slot, const PartitionMetadata& metadata) {
     EXPECT_CALL(dynamicControl(),
-                LoadMetadataBuilder(GetSuperDevice(slot), slot))
+                LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
         .Times(AnyNumber())
-        .WillRepeatedly(Invoke([sizes](auto, auto) {
-          return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes));
+        .WillRepeatedly(Invoke([metadata](auto, auto, auto) {
+          return NewFakeMetadata(metadata);
         }));
   }
 
+  // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
+  // slot with each partition in |partitions|.
+  void ExpectUnmap(const std::set<string>& partitions) {
+    // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
+    ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_, _))
+        .WillByDefault(Return(false));
+
+    for (const auto& partition : partitions) {
+      EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition, _))
+          .WillOnce(Invoke([this](auto partition, auto) {
+            mapped_devices_.erase(partition);
+            return true;
+          }));
+    }
+  }
+
+  void ExpectDevicesAreMapped(const std::set<string>& partitions) {
+    ASSERT_EQ(partitions.size(), mapped_devices_.size());
+    for (const auto& partition : partitions) {
+      EXPECT_THAT(mapped_devices_, Contains(Key(Eq(partition))))
+          << "Expect that " << partition << " is mapped, but it is not.";
+    }
+  }
+
+  void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
+    ExpectStoreMetadataMatch(MetadataMatches(partition_sizes));
+  }
+
+  virtual void ExpectStoreMetadataMatch(
+      const Matcher<MetadataBuilder*>& matcher) {
+    EXPECT_CALL(dynamicControl(),
+                StoreMetadata(GetSuperDevice(target()), matcher, target()))
+        .WillOnce(Return(true));
+  }
+
   uint32_t source() { return slots_.source; }
 
   uint32_t target() { return slots_.target; }
@@ -123,17 +369,28 @@
     ON_CALL(module(), getCurrentSlot()).WillByDefault(Invoke([this] {
       return source();
     }));
+    // Should not store metadata to source slot.
+    EXPECT_CALL(dynamicControl(),
+                StoreMetadata(GetSuperDevice(source()), _, source()))
+        .Times(0);
+    // Should not load metadata from target slot.
+    EXPECT_CALL(dynamicControl(),
+                LoadMetadataBuilder(GetSuperDevice(target()), target(), _))
+        .Times(0);
   }
 
-  bool PreparePartitionsForUpdate(uint32_t slot,
-                                  PartitionSizes partition_sizes,
-                                  bool update_metadata = true) {
-    auto m = PartitionSizesToManifest(partition_sizes);
-    return bootctl_.PreparePartitionsForUpdate(slot, m, update_metadata);
+  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, update_metadata);
   }
 
   BootControlAndroid bootctl_;  // BootControlAndroid under test.
   TestParam slots_;
+  // mapped devices through MapPartitionOnDeviceMapper.
+  std::map<string, string> mapped_devices_;
 };
 
 class BootControlAndroidTestP
@@ -146,6 +403,125 @@
   }
 };
 
+// Test resize case. Grow if target metadata contains a partition with a size
+// less than expected.
+TEST_P(BootControlAndroidTestP, NeedGrowIfSizeNotMatchWhenResizing) {
+  SetMetadata(source(),
+              {{S("system"), 2_GiB},
+               {S("vendor"), 1_GiB},
+               {T("system"), 2_GiB},
+               {T("vendor"), 1_GiB}});
+  ExpectStoreMetadata({{S("system"), 2_GiB},
+                       {S("vendor"), 1_GiB},
+                       {T("system"), 3_GiB},
+                       {T("vendor"), 1_GiB}});
+  ExpectUnmap({T("system"), T("vendor")});
+
+  EXPECT_TRUE(
+      InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 1_GiB}}));
+}
+
+// Test resize case. Shrink if target metadata contains a partition with a size
+// greater than expected.
+TEST_P(BootControlAndroidTestP, NeedShrinkIfSizeNotMatchWhenResizing) {
+  SetMetadata(source(),
+              {{S("system"), 2_GiB},
+               {S("vendor"), 1_GiB},
+               {T("system"), 2_GiB},
+               {T("vendor"), 1_GiB}});
+  ExpectStoreMetadata({{S("system"), 2_GiB},
+                       {S("vendor"), 1_GiB},
+                       {T("system"), 2_GiB},
+                       {T("vendor"), 150_MiB}});
+  ExpectUnmap({T("system"), T("vendor")});
+
+  EXPECT_TRUE(InitPartitionMetadata(target(),
+                                    {{"system", 2_GiB}, {"vendor", 150_MiB}}));
+}
+
+// Test adding partitions on the first run.
+TEST_P(BootControlAndroidTestP, AddPartitionToEmptyMetadata) {
+  SetMetadata(source(), PartitionSuffixSizes{});
+  ExpectStoreMetadata({{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
+  ExpectUnmap({T("system"), T("vendor")});
+
+  EXPECT_TRUE(
+      InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
+}
+
+// Test subsequent add case.
+TEST_P(BootControlAndroidTestP, AddAdditionalPartition) {
+  SetMetadata(source(), {{S("system"), 2_GiB}, {T("system"), 2_GiB}});
+  ExpectStoreMetadata(
+      {{S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
+  ExpectUnmap({T("system"), T("vendor")});
+
+  EXPECT_TRUE(
+      InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
+}
+
+// Test delete one partition.
+TEST_P(BootControlAndroidTestP, DeletePartition) {
+  SetMetadata(source(),
+              {{S("system"), 2_GiB},
+               {S("vendor"), 1_GiB},
+               {T("system"), 2_GiB},
+               {T("vendor"), 1_GiB}});
+  // No T("vendor")
+  ExpectStoreMetadata(
+      {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}});
+  ExpectUnmap({T("system")});
+
+  EXPECT_TRUE(InitPartitionMetadata(target(), {{"system", 2_GiB}}));
+}
+
+// Test delete all partitions.
+TEST_P(BootControlAndroidTestP, DeleteAll) {
+  SetMetadata(source(),
+              {{S("system"), 2_GiB},
+               {S("vendor"), 1_GiB},
+               {T("system"), 2_GiB},
+               {T("vendor"), 1_GiB}});
+  ExpectStoreMetadata({{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
+
+  EXPECT_TRUE(InitPartitionMetadata(target(), {}));
+}
+
+// Test corrupt source metadata case.
+TEST_P(BootControlAndroidTestP, CorruptedSourceMetadata) {
+  EXPECT_CALL(dynamicControl(),
+              LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
+      .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
+  ExpectUnmap({T("system")});
+
+  EXPECT_FALSE(InitPartitionMetadata(target(), {{"system", 1_GiB}}))
+      << "Should not be able to continue with corrupt source metadata";
+}
+
+// Test that InitPartitionMetadata fail if there is not enough space on the
+// device.
+TEST_P(BootControlAndroidTestP, NotEnoughSpace) {
+  SetMetadata(source(),
+              {{S("system"), 3_GiB},
+               {S("vendor"), 2_GiB},
+               {T("system"), 0},
+               {T("vendor"), 0}});
+  EXPECT_FALSE(
+      InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
+      << "Should not be able to fit 11GiB data into 10GiB space";
+}
+
+TEST_P(BootControlAndroidTestP, NotEnoughSpaceForSlot) {
+  SetMetadata(source(),
+              {{S("system"), 1_GiB},
+               {S("vendor"), 1_GiB},
+               {T("system"), 0},
+               {T("vendor"), 0}});
+  EXPECT_FALSE(
+      InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
+      << "Should not be able to grow over size of super / 2";
+}
+
 // Test applying retrofit update on a build with dynamic partitions enabled.
 TEST_P(BootControlAndroidTestP,
        ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
@@ -154,10 +530,16 @@
                {S("vendor"), 1_GiB},
                {T("system"), 2_GiB},
                {T("vendor"), 1_GiB}});
+  // Should not try to unmap any target partition.
+  EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_, _)).Times(0);
+  // Should not store metadata to target slot.
+  EXPECT_CALL(dynamicControl(),
+              StoreMetadata(GetSuperDevice(target()), _, target()))
+      .Times(0);
 
-  // Not calling through BootControlAndroidTest::PreparePartitionsForUpdate(),
-  // since we don't want any default group in the PartitionMetadata.
-  EXPECT_TRUE(bootctl_.PreparePartitionsForUpdate(target(), {}, true));
+  // Not calling through BootControlAndroidTest::InitPartitionMetadata(), since
+  // we don't want any default group in the PartitionMetadata.
+  EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(), {}, true));
 
   // Should use dynamic source partitions.
   EXPECT_CALL(dynamicControl(), GetState(S("system")))
@@ -196,11 +578,10 @@
                {S("vendor"), 1_GiB},
                {T("system"), 2_GiB},
                {T("vendor"), 1_GiB}});
-
-  EXPECT_CALL(dynamicControl(), PreparePartitionsForUpdate(_, _, _, false))
-      .WillOnce(Return(true));
-
-  EXPECT_TRUE(PreparePartitionsForUpdate(
+  EXPECT_CALL(dynamicControl(),
+              StoreMetadata(GetSuperDevice(target()), _, target()))
+      .Times(0);
+  EXPECT_TRUE(InitPartitionMetadata(
       target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}, false));
 
   // Dynamic partition "system".
@@ -241,10 +622,241 @@
                         BootControlAndroidTestP,
                         testing::Values(TestParam{0, 1}, TestParam{1, 0}));
 
+const PartitionSuffixSizes update_sizes_0() {
+  // Initial state is 0 for "other" slot.
+  return {
+      {"grown_a", 2_GiB},
+      {"shrunk_a", 1_GiB},
+      {"same_a", 100_MiB},
+      {"deleted_a", 150_MiB},
+      // no added_a
+      {"grown_b", 200_MiB},
+      // simulate system_other
+      {"shrunk_b", 0},
+      {"same_b", 0},
+      {"deleted_b", 0},
+      // no added_b
+  };
+}
+
+const PartitionSuffixSizes update_sizes_1() {
+  return {
+      {"grown_a", 2_GiB},
+      {"shrunk_a", 1_GiB},
+      {"same_a", 100_MiB},
+      {"deleted_a", 150_MiB},
+      // no added_a
+      {"grown_b", 3_GiB},
+      {"shrunk_b", 150_MiB},
+      {"same_b", 100_MiB},
+      {"added_b", 150_MiB},
+      // no deleted_b
+  };
+}
+
+const PartitionSuffixSizes update_sizes_2() {
+  return {
+      {"grown_a", 4_GiB},
+      {"shrunk_a", 100_MiB},
+      {"same_a", 100_MiB},
+      {"deleted_a", 64_MiB},
+      // no added_a
+      {"grown_b", 3_GiB},
+      {"shrunk_b", 150_MiB},
+      {"same_b", 100_MiB},
+      {"added_b", 150_MiB},
+      // no deleted_b
+  };
+}
+
+// Test case for first update after the device is manufactured, in which
+// case the "other" slot is likely of size "0" (except system, which is
+// non-zero because of system_other partition)
+TEST_F(BootControlAndroidTest, SimulatedFirstUpdate) {
+  SetSlots({0, 1});
+
+  SetMetadata(source(), update_sizes_0());
+  SetMetadata(target(), update_sizes_0());
+  ExpectStoreMetadata(update_sizes_1());
+  ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
+
+  EXPECT_TRUE(InitPartitionMetadata(target(),
+                                    {{"grown", 3_GiB},
+                                     {"shrunk", 150_MiB},
+                                     {"same", 100_MiB},
+                                     {"added", 150_MiB}}));
+}
+
+// After first update, test for the second update. In the second update, the
+// "added" partition is deleted and "deleted" partition is re-added.
+TEST_F(BootControlAndroidTest, SimulatedSecondUpdate) {
+  SetSlots({1, 0});
+
+  SetMetadata(source(), update_sizes_1());
+  SetMetadata(target(), update_sizes_0());
+
+  ExpectStoreMetadata(update_sizes_2());
+  ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
+
+  EXPECT_TRUE(InitPartitionMetadata(target(),
+                                    {{"grown", 4_GiB},
+                                     {"shrunk", 100_MiB},
+                                     {"same", 100_MiB},
+                                     {"deleted", 64_MiB}}));
+}
+
 TEST_F(BootControlAndroidTest, ApplyingToCurrentSlot) {
   SetSlots({1, 1});
-  EXPECT_FALSE(PreparePartitionsForUpdate(target(), {}))
+  EXPECT_FALSE(InitPartitionMetadata(target(), {}))
       << "Should not be able to apply to current slot.";
 }
 
+class BootControlAndroidGroupTestP : public BootControlAndroidTestP {
+ public:
+  void SetUp() override {
+    BootControlAndroidTestP::SetUp();
+    SetMetadata(
+        source(),
+        {.groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB),
+                    SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB),
+                    SimpleGroup(T("android"), 3_GiB, T("system"), 0),
+                    SimpleGroup(T("oem"), 2_GiB, T("vendor"), 0)}});
+  }
+
+  // Return a simple group with only one partition.
+  PartitionMetadata::Group SimpleGroup(const string& group,
+                                       uint64_t group_size,
+                                       const string& partition,
+                                       uint64_t partition_size) {
+    return {.name = group,
+            .size = group_size,
+            .partitions = {{.name = partition, .size = partition_size}}};
+  }
+
+  void ExpectStoreMetadata(const PartitionMetadata& partition_metadata) {
+    ExpectStoreMetadataMatch(MetadataMatches(partition_metadata));
+  }
+
+  // Expect that target slot is stored with target groups.
+  void ExpectStoreMetadataMatch(
+      const Matcher<MetadataBuilder*>& matcher) override {
+    BootControlAndroidTestP::ExpectStoreMetadataMatch(AllOf(
+        MetadataMatches(PartitionMetadata{
+            .groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB),
+                       SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB)}}),
+        matcher));
+  }
+};
+
+// Allow to resize within group.
+TEST_P(BootControlAndroidGroupTestP, ResizeWithinGroup) {
+  ExpectStoreMetadata(PartitionMetadata{
+      .groups = {SimpleGroup(T("android"), 3_GiB, T("system"), 3_GiB),
+                 SimpleGroup(T("oem"), 2_GiB, T("vendor"), 2_GiB)}});
+  ExpectUnmap({T("system"), T("vendor")});
+
+  EXPECT_TRUE(bootctl_.InitPartitionMetadata(
+      target(),
+      PartitionMetadata{
+          .groups = {SimpleGroup("android", 3_GiB, "system", 3_GiB),
+                     SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}},
+      true));
+}
+
+TEST_P(BootControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
+  EXPECT_FALSE(bootctl_.InitPartitionMetadata(
+      target(),
+      PartitionMetadata{
+          .groups = {SimpleGroup("android", 3_GiB, "system", 1_GiB),
+                     SimpleGroup("oem", 2_GiB, "vendor", 3_GiB)}},
+      true))
+      << "Should not be able to grow over maximum size of group";
+}
+
+TEST_P(BootControlAndroidGroupTestP, GroupTooBig) {
+  EXPECT_FALSE(bootctl_.InitPartitionMetadata(
+      target(),
+      PartitionMetadata{.groups = {{.name = "android", .size = 3_GiB},
+                                   {.name = "oem", .size = 3_GiB}}},
+      true))
+      << "Should not be able to grow over size of super / 2";
+}
+
+TEST_P(BootControlAndroidGroupTestP, AddPartitionToGroup) {
+  ExpectStoreMetadata(PartitionMetadata{
+      .groups = {
+          {.name = T("android"),
+           .size = 3_GiB,
+           .partitions = {{.name = T("system"), .size = 2_GiB},
+                          {.name = T("product_services"), .size = 1_GiB}}}}});
+  ExpectUnmap({T("system"), T("vendor"), T("product_services")});
+
+  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)}},
+      true));
+}
+
+TEST_P(BootControlAndroidGroupTestP, RemovePartitionFromGroup) {
+  ExpectStoreMetadata(PartitionMetadata{
+      .groups = {{.name = T("android"), .size = 3_GiB, .partitions = {}}}});
+  ExpectUnmap({T("vendor")});
+
+  EXPECT_TRUE(bootctl_.InitPartitionMetadata(
+      target(),
+      PartitionMetadata{
+          .groups = {{.name = "android", .size = 3_GiB, .partitions = {}},
+                     SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}},
+      true));
+}
+
+TEST_P(BootControlAndroidGroupTestP, AddGroup) {
+  ExpectStoreMetadata(PartitionMetadata{
+      .groups = {
+          SimpleGroup(T("new_group"), 2_GiB, T("new_partition"), 2_GiB)}});
+  ExpectUnmap({T("system"), T("vendor"), T("new_partition")});
+
+  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)}},
+      true));
+}
+
+TEST_P(BootControlAndroidGroupTestP, RemoveGroup) {
+  ExpectStoreMetadataMatch(Not(HasGroup(T("oem"))));
+  ExpectUnmap({T("system")});
+  EXPECT_TRUE(bootctl_.InitPartitionMetadata(
+      target(),
+      PartitionMetadata{
+          .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB)}},
+      true));
+}
+
+TEST_P(BootControlAndroidGroupTestP, ResizeGroup) {
+  ExpectStoreMetadata(PartitionMetadata{
+      .groups = {SimpleGroup(T("android"), 2_GiB, T("system"), 2_GiB),
+                 SimpleGroup(T("oem"), 3_GiB, T("vendor"), 3_GiB)}});
+  ExpectUnmap({T("system"), T("vendor")});
+
+  EXPECT_TRUE(bootctl_.InitPartitionMetadata(
+      target(),
+      PartitionMetadata{
+          .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB),
+                     SimpleGroup("oem", 3_GiB, "vendor", 3_GiB)}},
+      true));
+}
+
+INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
+                        BootControlAndroidGroupTestP,
+                        testing::Values(TestParam{0, 1}, TestParam{1, 0}));
+
 }  // namespace chromeos_update_engine
diff --git a/boot_control_chromeos.cc b/boot_control_chromeos.cc
index 7e748d5..ccba316 100644
--- a/boot_control_chromeos.cc
+++ b/boot_control_chromeos.cc
@@ -326,8 +326,10 @@
   return -1;
 }
 
-bool BootControlChromeOS::PreparePartitionsForUpdate(
-    Slot slot, const DeltaArchiveManifest& manifest, bool update_metadata) {
+bool BootControlChromeOS::InitPartitionMetadata(
+    Slot slot,
+    const PartitionMetadata& partition_metadata,
+    bool update_metadata) {
   return true;
 }
 
diff --git a/boot_control_chromeos.h b/boot_control_chromeos.h
index 29841c9..f3682e9 100644
--- a/boot_control_chromeos.h
+++ b/boot_control_chromeos.h
@@ -50,9 +50,9 @@
   bool MarkSlotUnbootable(BootControlInterface::Slot slot) override;
   bool SetActiveBootSlot(BootControlInterface::Slot slot) override;
   bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override;
-  bool PreparePartitionsForUpdate(Slot slot,
-                                  const DeltaArchiveManifest& manifest,
-                                  bool update_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 9bf639a..392d785 100644
--- a/common/boot_control_interface.h
+++ b/common/boot_control_interface.h
@@ -25,8 +25,6 @@
 #include <base/callback.h>
 #include <base/macros.h>
 
-#include "update_engine/update_metadata.pb.h"
-
 namespace chromeos_update_engine {
 
 // The abstract boot control interface defines the interaction with the
@@ -37,6 +35,19 @@
  public:
   using Slot = unsigned int;
 
+  struct PartitionMetadata {
+    struct Partition {
+      std::string name;
+      uint64_t size;
+    };
+    struct Group {
+      std::string name;
+      uint64_t size;
+      std::vector<Partition> partitions;
+    };
+    std::vector<Group> groups;
+  };
+
   static const Slot kInvalidSlot = UINT_MAX;
 
   virtual ~BootControlInterface() = default;
@@ -56,9 +67,9 @@
   // 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. In order to access the dynamic partitions in the target slot,
-  // PreparePartitionsForUpdate() must be called (once per payload) prior to
-  // calling this function. On success, returns true and stores the block device
-  // in |device|.
+  // 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,
                                   std::string* device) const = 0;
@@ -85,11 +96,12 @@
 
   // Initializes the metadata of the underlying partitions for a given |slot|
   // and sets up the states for accessing dynamic partitions.
-  // Metadata will be written to the specified |slot| if
+  // |partition_metadata| will be written to the specified |slot| if
   // |update_metadata| is set.
-  virtual bool PreparePartitionsForUpdate(Slot slot,
-                                          const DeltaArchiveManifest& manifest,
-                                          bool update_metadata) = 0;
+  virtual bool InitPartitionMetadata(
+      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 b10e82f..0fe8a98 100644
--- a/common/boot_control_stub.cc
+++ b/common/boot_control_stub.cc
@@ -59,8 +59,10 @@
   return false;
 }
 
-bool BootControlStub::PreparePartitionsForUpdate(
-    Slot slot, const DeltaArchiveManifest& manifest, bool update_metadata) {
+bool BootControlStub::InitPartitionMetadata(
+    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 f2973a2..8dfaffc 100644
--- a/common/boot_control_stub.h
+++ b/common/boot_control_stub.h
@@ -45,9 +45,9 @@
   bool MarkSlotUnbootable(BootControlInterface::Slot slot) override;
   bool SetActiveBootSlot(BootControlInterface::Slot slot) override;
   bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override;
-  bool PreparePartitionsForUpdate(Slot slot,
-                                  const DeltaArchiveManifest& manifest,
-                                  bool update_metadata) override;
+  bool InitPartitionMetadata(Slot slot,
+                             const PartitionMetadata& partition_metadata,
+                             bool update_metadata) override;
   void Cleanup() override;
 
  private:
diff --git a/common/fake_boot_control.h b/common/fake_boot_control.h
index 11810d1..3d65075 100644
--- a/common/fake_boot_control.h
+++ b/common/fake_boot_control.h
@@ -74,9 +74,9 @@
     return true;
   }
 
-  bool PreparePartitionsForUpdate(Slot slot,
-                                  const DeltaArchiveManifest& manifest,
-                                  bool update_metadata) override {
+  bool InitPartitionMetadata(Slot slot,
+                             const PartitionMetadata& partition_metadata,
+                             bool update_metadata) override {
     return true;
   }
 
diff --git a/common/fake_hardware.h b/common/fake_hardware.h
index 8da5326..3e5a66e 100644
--- a/common/fake_hardware.h
+++ b/common/fake_hardware.h
@@ -128,8 +128,6 @@
 
   int64_t GetBuildTimestamp() const override { return build_timestamp_; }
 
-  bool AllowDowngrade() const override { return false; }
-
   bool GetFirstActiveOmahaPingSent() const override {
     return first_active_omaha_ping_sent_;
   }
diff --git a/common/file_fetcher.cc b/common/file_fetcher.cc
index 7134fd6..3836e54 100644
--- a/common/file_fetcher.cc
+++ b/common/file_fetcher.cc
@@ -43,9 +43,8 @@
 // static
 bool FileFetcher::SupportedUrl(const string& url) {
   // Note that we require the file path to start with a "/".
-  return (
-      base::StartsWith(url, "file:///", base::CompareCase::INSENSITIVE_ASCII) ||
-      base::StartsWith(url, "fd://", base::CompareCase::INSENSITIVE_ASCII));
+  return base::StartsWith(
+      url, "file:///", base::CompareCase::INSENSITIVE_ASCII);
 }
 
 FileFetcher::~FileFetcher() {
@@ -68,20 +67,12 @@
     return;
   }
 
-  string file_path;
-
-  if (base::StartsWith(url, "fd://", base::CompareCase::INSENSITIVE_ASCII)) {
-    int fd = std::stoi(url.substr(strlen("fd://")));
-    file_path = url;
-    stream_ = brillo::FileStream::FromFileDescriptor(fd, false, nullptr);
-  } else {
-    file_path = url.substr(strlen("file://"));
-    stream_ =
-        brillo::FileStream::Open(base::FilePath(file_path),
-                                 brillo::Stream::AccessMode::READ,
-                                 brillo::FileStream::Disposition::OPEN_EXISTING,
-                                 nullptr);
-  }
+  string file_path = url.substr(strlen("file://"));
+  stream_ =
+      brillo::FileStream::Open(base::FilePath(file_path),
+                               brillo::Stream::AccessMode::READ,
+                               brillo::FileStream::Disposition::OPEN_EXISTING,
+                               nullptr);
 
   if (!stream_) {
     LOG(ERROR) << "Couldn't open " << file_path;
@@ -192,4 +183,5 @@
   transfer_in_progress_ = false;
   transfer_paused_ = false;
 }
+
 }  // namespace chromeos_update_engine
diff --git a/common/hardware_interface.h b/common/hardware_interface.h
index 4a64c3e..0140588 100644
--- a/common/hardware_interface.h
+++ b/common/hardware_interface.h
@@ -122,10 +122,6 @@
   // Returns the timestamp of the current OS build.
   virtual int64_t GetBuildTimestamp() const = 0;
 
-  // Returns true if the current OS build allows installing the payload with an
-  // older timestamp.
-  virtual bool AllowDowngrade() const = 0;
-
   // Returns whether the first active ping was sent to Omaha at some point, and
   // that the value is persisted across recovery (and powerwash) once set with
   // |SetFirstActiveOmahaPingSent()|.
diff --git a/common/platform_constants.h b/common/platform_constants.h
index 243af69..6eaa940 100644
--- a/common/platform_constants.h
+++ b/common/platform_constants.h
@@ -38,10 +38,6 @@
 // whole payload.
 extern const char kUpdatePayloadPublicKeyPath[];
 
-// Path to the location of the zip archive file that contains PEM encoded X509
-// certificates. e.g. 'system/etc/security/otacerts.zip'.
-extern const char kUpdateCertificatesPath[];
-
 // Path to the directory containing all the SSL certificates accepted by
 // update_engine when sending requests to Omaha and the download server (if
 // HTTPS is used for that as well).
diff --git a/common/platform_constants_android.cc b/common/platform_constants_android.cc
index f468c3b..9d8d30e 100644
--- a/common/platform_constants_android.cc
+++ b/common/platform_constants_android.cc
@@ -25,8 +25,8 @@
     "https://clients2.google.com/service/update2/brillo";
 const char kOmahaUpdaterID[] = "Brillo";
 const char kOmahaPlatformName[] = "Brillo";
-const char kUpdatePayloadPublicKeyPath[] = "";
-const char kUpdateCertificatesPath[] = "/system/etc/security/otacerts.zip";
+const char kUpdatePayloadPublicKeyPath[] =
+    "/etc/update_engine/update-payload-key.pub.pem";
 const char kCACertificatesPath[] = "/system/etc/security/cacerts_google";
 // No deadline file API support on Android.
 const char kOmahaResponseDeadlineFile[] = "";
diff --git a/common/platform_constants_chromeos.cc b/common/platform_constants_chromeos.cc
index fe94a45..f1ac490 100644
--- a/common/platform_constants_chromeos.cc
+++ b/common/platform_constants_chromeos.cc
@@ -27,7 +27,6 @@
 const char kOmahaPlatformName[] = "Chrome OS";
 const char kUpdatePayloadPublicKeyPath[] =
     "/usr/share/update_engine/update-payload-key.pub.pem";
-const char kUpdateCertificatesPath[] = "";
 const char kCACertificatesPath[] = "/usr/share/chromeos-ca-certificates";
 const char kOmahaResponseDeadlineFile[] = "/tmp/update-check-response-deadline";
 // This directory is wiped during powerwash.
diff --git a/common/utils.cc b/common/utils.cc
index e7b6975..34d97a2 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -1064,16 +1064,6 @@
   }
 }
 
-string GetFilePath(int fd) {
-  base::FilePath proc("/proc/self/fd/" + std::to_string(fd));
-  base::FilePath file_name;
-
-  if (!base::ReadSymbolicLink(proc, &file_name)) {
-    return "not found";
-  }
-  return file_name.value();
-}
-
 }  // namespace utils
 
 }  // namespace chromeos_update_engine
diff --git a/common/utils.h b/common/utils.h
index 9dca9e8..9160d9f 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -304,9 +304,6 @@
 // reboot. Returns whether it succeeded getting the boot_id.
 bool GetBootId(std::string* boot_id);
 
-// This function gets the file path of the file pointed to by FileDiscriptor.
-std::string GetFilePath(int fd);
-
 // Divide |x| by |y| and round up to the nearest integer.
 constexpr uint64_t DivRoundUp(uint64_t x, uint64_t y) {
   return (x + y - 1) / y;
diff --git a/common/utils_unittest.cc b/common/utils_unittest.cc
index b4ac2f5..7d1c59e 100644
--- a/common/utils_unittest.cc
+++ b/common/utils_unittest.cc
@@ -507,13 +507,4 @@
   ExpectInvalidParseRollbackKeyVersion("1.99999");
 }
 
-TEST(UtilsTest, GetFilePathTest) {
-  test_utils::ScopedTempFile file;
-  int fd = HANDLE_EINTR(open(file.path().c_str(), O_RDONLY));
-  EXPECT_GE(fd, 0);
-  EXPECT_EQ(file.path(), utils::GetFilePath(fd));
-  EXPECT_EQ("not found", utils::GetFilePath(-1));
-  IGNORE_EINTR(close(fd));
-}
-
 }  // namespace chromeos_update_engine
diff --git a/dynamic_partition_control_android.cc b/dynamic_partition_control_android.cc
index c641a6b..40c2663 100644
--- a/dynamic_partition_control_android.cc
+++ b/dynamic_partition_control_android.cc
@@ -16,90 +16,46 @@
 
 #include "update_engine/dynamic_partition_control_android.h"
 
-#include <chrono>  // NOLINT(build/c++11) - using libsnapshot / liblp API
-#include <map>
 #include <memory>
 #include <set>
 #include <string>
-#include <vector>
 
 #include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <base/files/file_util.h>
 #include <base/logging.h>
-#include <base/strings/string_util.h>
 #include <bootloader_message/bootloader_message.h>
-#include <fs_mgr.h>
 #include <fs_mgr_dm_linear.h>
-#include <libsnapshot/snapshot.h>
 
 #include "update_engine/common/boot_control_interface.h"
 #include "update_engine/common/utils.h"
-#include "update_engine/dynamic_partition_utils.h"
 
 using android::base::GetBoolProperty;
 using android::base::Join;
 using android::dm::DeviceMapper;
 using android::dm::DmDeviceState;
 using android::fs_mgr::CreateLogicalPartition;
-using android::fs_mgr::CreateLogicalPartitionParams;
 using android::fs_mgr::DestroyLogicalPartition;
 using android::fs_mgr::MetadataBuilder;
-using android::fs_mgr::Partition;
 using android::fs_mgr::PartitionOpener;
-using android::fs_mgr::SlotSuffixForSlotNumber;
 
 namespace chromeos_update_engine {
 
 constexpr char kUseDynamicPartitions[] = "ro.boot.dynamic_partitions";
 constexpr char kRetrfoitDynamicPartitions[] =
     "ro.boot.dynamic_partitions_retrofit";
-constexpr char kVirtualAbEnabled[] = "ro.virtual_ab.enabled";
-constexpr char kVirtualAbRetrofit[] = "ro.virtual_ab.retrofit";
-// Map timeout for dynamic partitions.
-constexpr std::chrono::milliseconds kMapTimeout{1000};
-// Map timeout for dynamic partitions with snapshots. Since several devices
-// needs to be mapped, this timeout is longer than |kMapTimeout|.
-constexpr std::chrono::milliseconds kMapSnapshotTimeout{5000};
+constexpr uint64_t kMapTimeoutMillis = 1000;
 
 DynamicPartitionControlAndroid::~DynamicPartitionControlAndroid() {
-  CleanupInternal();
+  CleanupInternal(false /* wait */);
 }
 
-static FeatureFlag GetFeatureFlag(const char* enable_prop,
-                                  const char* retrofit_prop) {
-  bool retrofit = GetBoolProperty(retrofit_prop, false);
-  bool enabled = GetBoolProperty(enable_prop, false);
-  if (retrofit && !enabled) {
-    LOG(ERROR) << retrofit_prop << " is true but " << enable_prop
-               << " is not. These sysprops are inconsistent. Assume that "
-               << enable_prop << " is true from now on.";
-  }
-  if (retrofit) {
-    return FeatureFlag(FeatureFlag::Value::RETROFIT);
-  }
-  if (enabled) {
-    return FeatureFlag(FeatureFlag::Value::LAUNCH);
-  }
-  return FeatureFlag(FeatureFlag::Value::NONE);
+bool DynamicPartitionControlAndroid::IsDynamicPartitionsEnabled() {
+  return GetBoolProperty(kUseDynamicPartitions, false);
 }
 
-DynamicPartitionControlAndroid::DynamicPartitionControlAndroid()
-    : dynamic_partitions_(
-          GetFeatureFlag(kUseDynamicPartitions, kRetrfoitDynamicPartitions)),
-      virtual_ab_(GetFeatureFlag(kVirtualAbEnabled, kVirtualAbRetrofit)) {
-  if (GetVirtualAbFeatureFlag().IsEnabled()) {
-    snapshot_ = android::snapshot::SnapshotManager::New();
-    CHECK(snapshot_ != nullptr) << "Cannot initialize SnapshotManager.";
-  }
-}
-
-FeatureFlag DynamicPartitionControlAndroid::GetDynamicPartitionsFeatureFlag() {
-  return dynamic_partitions_;
-}
-
-FeatureFlag DynamicPartitionControlAndroid::GetVirtualAbFeatureFlag() {
-  return virtual_ab_;
+bool DynamicPartitionControlAndroid::IsDynamicPartitionsRetrofit() {
+  return GetBoolProperty(kRetrfoitDynamicPartitions, false);
 }
 
 bool DynamicPartitionControlAndroid::MapPartitionInternal(
@@ -108,26 +64,12 @@
     uint32_t slot,
     bool force_writable,
     std::string* path) {
-  CreateLogicalPartitionParams params = {
-      .block_device = super_device,
-      .metadata_slot = slot,
-      .partition_name = target_partition_name,
-      .force_writable = force_writable,
-  };
-  bool success = false;
-  if (GetVirtualAbFeatureFlag().IsEnabled() && target_supports_snapshot_ &&
-      force_writable) {
-    // Only target partitions are mapped with force_writable. On Virtual
-    // A/B devices, target partitions may overlap with source partitions, so
-    // they must be mapped with snapshot.
-    params.timeout_ms = kMapSnapshotTimeout;
-    success = snapshot_->MapUpdateSnapshot(params, path);
-  } else {
-    params.timeout_ms = kMapTimeout;
-    success = CreateLogicalPartition(params, path);
-  }
-
-  if (!success) {
+  if (!CreateLogicalPartition(super_device.c_str(),
+                              slot,
+                              target_partition_name,
+                              force_writable,
+                              std::chrono::milliseconds(kMapTimeoutMillis),
+                              path)) {
     LOG(ERROR) << "Cannot map " << target_partition_name << " in "
                << super_device << " on device mapper.";
     return false;
@@ -161,7 +103,7 @@
     // Note that for source partitions, if GetState() == ACTIVE, callers (e.g.
     // BootControlAndroid) should not call MapPartitionOnDeviceMapper, but
     // should directly call GetDmDevicePathByName.
-    if (!UnmapPartitionOnDeviceMapper(target_partition_name)) {
+    if (!UnmapPartitionOnDeviceMapper(target_partition_name, true /* wait */)) {
       LOG(ERROR) << target_partition_name
                  << " is mapped before the update, and it cannot be unmapped.";
       return false;
@@ -185,22 +127,12 @@
 }
 
 bool DynamicPartitionControlAndroid::UnmapPartitionOnDeviceMapper(
-    const std::string& target_partition_name) {
+    const std::string& target_partition_name, bool wait) {
   if (DeviceMapper::Instance().GetState(target_partition_name) !=
       DmDeviceState::INVALID) {
-    // Partitions at target slot on non-Virtual A/B devices are mapped as
-    // dm-linear. Also, on Virtual A/B devices, system_other may be mapped for
-    // preopt apps as dm-linear.
-    // Call DestroyLogicalPartition to handle these cases.
-    bool success = DestroyLogicalPartition(target_partition_name);
-
-    // On a Virtual A/B device, |target_partition_name| may be a leftover from
-    // a paused update. Clean up any underlying devices.
-    if (GetVirtualAbFeatureFlag().IsEnabled()) {
-      success &= snapshot_->UnmapUpdateSnapshot(target_partition_name);
-    }
-
-    if (!success) {
+    if (!DestroyLogicalPartition(
+            target_partition_name,
+            std::chrono::milliseconds(wait ? kMapTimeoutMillis : 0))) {
       LOG(ERROR) << "Cannot unmap " << target_partition_name
                  << " from device mapper.";
       return false;
@@ -212,22 +144,18 @@
   return true;
 }
 
-void DynamicPartitionControlAndroid::CleanupInternal() {
-  metadata_device_.reset();
-  if (mapped_devices_.empty()) {
-    return;
-  }
+void DynamicPartitionControlAndroid::CleanupInternal(bool wait) {
   // UnmapPartitionOnDeviceMapper removes objects from mapped_devices_, hence
   // a copy is needed for the loop.
   std::set<std::string> mapped = mapped_devices_;
   LOG(INFO) << "Destroying [" << Join(mapped, ", ") << "] from device mapper";
   for (const auto& partition_name : mapped) {
-    ignore_result(UnmapPartitionOnDeviceMapper(partition_name));
+    ignore_result(UnmapPartitionOnDeviceMapper(partition_name, wait));
   }
 }
 
 void DynamicPartitionControlAndroid::Cleanup() {
-  CleanupInternal();
+  CleanupInternal(true /* wait */);
 }
 
 bool DynamicPartitionControlAndroid::DeviceExists(const std::string& path) {
@@ -246,27 +174,18 @@
 
 std::unique_ptr<MetadataBuilder>
 DynamicPartitionControlAndroid::LoadMetadataBuilder(
-    const std::string& super_device, uint32_t source_slot) {
-  return LoadMetadataBuilder(
-      super_device, source_slot, BootControlInterface::kInvalidSlot);
-}
-
-std::unique_ptr<MetadataBuilder>
-DynamicPartitionControlAndroid::LoadMetadataBuilder(
     const std::string& super_device,
     uint32_t source_slot,
     uint32_t target_slot) {
   std::unique_ptr<MetadataBuilder> builder;
-  if (target_slot == BootControlInterface::kInvalidSlot) {
+
+  if (target_slot != BootControlInterface::kInvalidSlot &&
+      IsDynamicPartitionsRetrofit()) {
+    builder = MetadataBuilder::NewForUpdate(
+        PartitionOpener(), super_device, source_slot, target_slot);
+  } else {
     builder =
         MetadataBuilder::New(PartitionOpener(), super_device, source_slot);
-  } else {
-    bool always_keep_source_slot = !target_supports_snapshot_;
-    builder = MetadataBuilder::NewForUpdate(PartitionOpener(),
-                                            super_device,
-                                            source_slot,
-                                            target_slot,
-                                            always_keep_source_slot);
   }
 
   if (builder == nullptr) {
@@ -293,7 +212,7 @@
     return false;
   }
 
-  if (GetDynamicPartitionsFeatureFlag().IsRetrofit()) {
+  if (IsDynamicPartitionsRetrofit()) {
     if (!FlashPartitionTable(super_device, *metadata)) {
       LOG(ERROR) << "Cannot write metadata to " << super_device;
       return false;
@@ -348,188 +267,4 @@
   *out = base::FilePath(misc_device).DirName().value();
   return true;
 }
-
-bool DynamicPartitionControlAndroid::PreparePartitionsForUpdate(
-    uint32_t source_slot,
-    uint32_t target_slot,
-    const DeltaArchiveManifest& manifest,
-    bool update) {
-  target_supports_snapshot_ =
-      manifest.dynamic_partition_metadata().snapshot_enabled();
-
-  if (GetVirtualAbFeatureFlag().IsEnabled()) {
-    metadata_device_ = snapshot_->EnsureMetadataMounted();
-    TEST_AND_RETURN_FALSE(metadata_device_ != nullptr);
-  }
-
-  if (!update)
-    return true;
-
-  if (GetVirtualAbFeatureFlag().IsEnabled()) {
-    // On Virtual A/B device, either CancelUpdate() or BeginUpdate() must be
-    // called before calling UnmapUpdateSnapshot.
-    // - If target_supports_snapshot_, PrepareSnapshotPartitionsForUpdate()
-    //   calls BeginUpdate() which resets update state
-    // - If !target_supports_snapshot_, explicitly CancelUpdate().
-    if (target_supports_snapshot_) {
-      return PrepareSnapshotPartitionsForUpdate(
-          source_slot, target_slot, manifest);
-    }
-    if (!snapshot_->CancelUpdate()) {
-      LOG(ERROR) << "Cannot cancel previous update.";
-      return false;
-    }
-  }
-  return PrepareDynamicPartitionsForUpdate(source_slot, target_slot, manifest);
-}
-
-bool DynamicPartitionControlAndroid::PrepareDynamicPartitionsForUpdate(
-    uint32_t source_slot,
-    uint32_t target_slot,
-    const DeltaArchiveManifest& manifest) {
-  const std::string target_suffix = SlotSuffixForSlotNumber(target_slot);
-
-  // Unmap all the target dynamic partitions because they would become
-  // inconsistent with the new metadata.
-  for (const auto& group : manifest.dynamic_partition_metadata().groups()) {
-    for (const auto& partition_name : group.partition_names()) {
-      if (!UnmapPartitionOnDeviceMapper(partition_name + target_suffix)) {
-        return false;
-      }
-    }
-  }
-
-  std::string device_dir_str;
-  if (!GetDeviceDir(&device_dir_str)) {
-    return false;
-  }
-  base::FilePath device_dir(device_dir_str);
-  auto source_device =
-      device_dir.Append(GetSuperPartitionName(source_slot)).value();
-
-  auto builder = LoadMetadataBuilder(source_device, source_slot, target_slot);
-  if (builder == nullptr) {
-    LOG(ERROR) << "No metadata at "
-               << BootControlInterface::SlotName(source_slot);
-    return false;
-  }
-
-  if (!UpdatePartitionMetadata(builder.get(), target_slot, manifest)) {
-    return false;
-  }
-
-  auto target_device =
-      device_dir.Append(GetSuperPartitionName(target_slot)).value();
-  return StoreMetadata(target_device, builder.get(), target_slot);
-}
-
-bool DynamicPartitionControlAndroid::PrepareSnapshotPartitionsForUpdate(
-    uint32_t source_slot,
-    uint32_t target_slot,
-    const DeltaArchiveManifest& manifest) {
-  if (!snapshot_->BeginUpdate()) {
-    LOG(ERROR) << "Cannot begin new update.";
-    return false;
-  }
-  if (!snapshot_->CreateUpdateSnapshots(manifest)) {
-    LOG(ERROR) << "Cannot create update snapshots.";
-    return false;
-  }
-  return true;
-}
-
-std::string DynamicPartitionControlAndroid::GetSuperPartitionName(
-    uint32_t slot) {
-  return fs_mgr_get_super_partition_name(slot);
-}
-
-bool DynamicPartitionControlAndroid::UpdatePartitionMetadata(
-    MetadataBuilder* builder,
-    uint32_t target_slot,
-    const DeltaArchiveManifest& manifest) {
-  // If applying downgrade from Virtual A/B to non-Virtual A/B, the left-over
-  // COW group needs to be deleted to ensure there are enough space to create
-  // target partitions.
-  builder->RemoveGroupAndPartitions(android::snapshot::kCowGroupName);
-
-  const std::string target_suffix = SlotSuffixForSlotNumber(target_slot);
-  DeleteGroupsWithSuffix(builder, target_suffix);
-
-  uint64_t total_size = 0;
-  for (const auto& group : manifest.dynamic_partition_metadata().groups()) {
-    total_size += group.size();
-  }
-
-  std::string expr;
-  uint64_t allocatable_space = builder->AllocatableSpace();
-  if (!GetDynamicPartitionsFeatureFlag().IsRetrofit()) {
-    allocatable_space /= 2;
-    expr = "half of ";
-  }
-  if (total_size > allocatable_space) {
-    LOG(ERROR) << "The maximum size of all groups with suffix " << target_suffix
-               << " (" << total_size << ") has exceeded " << expr
-               << "allocatable space for dynamic partitions "
-               << allocatable_space << ".";
-    return false;
-  }
-
-  // name of partition(e.g. "system") -> size in bytes
-  std::map<std::string, uint64_t> partition_sizes;
-  for (const auto& partition : manifest.partitions()) {
-    partition_sizes.emplace(partition.partition_name(),
-                            partition.new_partition_info().size());
-  }
-
-  for (const auto& group : manifest.dynamic_partition_metadata().groups()) {
-    auto group_name_suffix = group.name() + target_suffix;
-    if (!builder->AddGroup(group_name_suffix, group.size())) {
-      LOG(ERROR) << "Cannot add group " << group_name_suffix << " with size "
-                 << group.size();
-      return false;
-    }
-    LOG(INFO) << "Added group " << group_name_suffix << " with size "
-              << group.size();
-
-    for (const auto& partition_name : group.partition_names()) {
-      auto partition_sizes_it = partition_sizes.find(partition_name);
-      if (partition_sizes_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;
-      }
-      uint64_t partition_size = partition_sizes_it->second;
-
-      auto partition_name_suffix = partition_name + target_suffix;
-      Partition* p = builder->AddPartition(
-          partition_name_suffix, group_name_suffix, LP_PARTITION_ATTR_READONLY);
-      if (!p) {
-        LOG(ERROR) << "Cannot add partition " << partition_name_suffix
-                   << " to group " << group_name_suffix;
-        return false;
-      }
-      if (!builder->ResizePartition(p, partition_size)) {
-        LOG(ERROR) << "Cannot resize partition " << partition_name_suffix
-                   << " to size " << partition_size << ". Not enough space?";
-        return false;
-      }
-      LOG(INFO) << "Added partition " << partition_name_suffix << " to group "
-                << group_name_suffix << " with size " << partition_size;
-    }
-  }
-
-  return true;
-}
-
-bool DynamicPartitionControlAndroid::FinishUpdate() {
-  if (GetVirtualAbFeatureFlag().IsEnabled() && target_supports_snapshot_) {
-    LOG(INFO) << "Snapshot writes are done.";
-    return snapshot_->FinishedSnapshotWrites();
-  }
-  return true;
-}
-
 }  // namespace chromeos_update_engine
diff --git a/dynamic_partition_control_android.h b/dynamic_partition_control_android.h
index 07ce281..1233b64 100644
--- a/dynamic_partition_control_android.h
+++ b/dynamic_partition_control_android.h
@@ -23,102 +23,45 @@
 #include <set>
 #include <string>
 
-#include <libsnapshot/auto_device.h>
-#include <libsnapshot/snapshot.h>
-
 namespace chromeos_update_engine {
 
 class DynamicPartitionControlAndroid : public DynamicPartitionControlInterface {
  public:
-  DynamicPartitionControlAndroid();
+  DynamicPartitionControlAndroid() = default;
   ~DynamicPartitionControlAndroid();
-  FeatureFlag GetDynamicPartitionsFeatureFlag() override;
-  FeatureFlag GetVirtualAbFeatureFlag() override;
+  bool IsDynamicPartitionsEnabled() override;
+  bool IsDynamicPartitionsRetrofit() override;
   bool MapPartitionOnDeviceMapper(const std::string& super_device,
                                   const std::string& target_partition_name,
                                   uint32_t slot,
                                   bool force_writable,
                                   std::string* path) override;
+  bool UnmapPartitionOnDeviceMapper(const std::string& target_partition_name,
+                                    bool wait) 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;
-
- protected:
-  // These functions are exposed for testing.
-
-  // Unmap logical partition on device mapper. This is the reverse operation
-  // of MapPartitionOnDeviceMapper.
-  // Returns true if unmapped successfully.
-  virtual bool UnmapPartitionOnDeviceMapper(
-      const std::string& target_partition_name);
-
-  // Retrieve metadata from |super_device| at slot |source_slot|.
-  //
-  // If |target_slot| != kInvalidSlot, before returning the metadata, this
-  // function modifies the metadata so that during updates, the metadata can be
-  // written to |target_slot|. In particular, on retrofit devices, the returned
-  // metadata automatically includes block devices at |target_slot|.
-  //
-  // If |target_slot| == kInvalidSlot, this function returns metadata at
-  // |source_slot| without modifying it. This is the same as
-  // LoadMetadataBuilder(const std::string&, uint32_t).
-  virtual std::unique_ptr<android::fs_mgr::MetadataBuilder> LoadMetadataBuilder(
       const std::string& super_device,
       uint32_t source_slot,
-      uint32_t target_slot);
-
-  // Write metadata |builder| to |super_device| at slot |target_slot|.
-  virtual bool StoreMetadata(const std::string& super_device,
-                             android::fs_mgr::MetadataBuilder* builder,
-                             uint32_t target_slot);
+      uint32_t target_slot) override;
+  bool StoreMetadata(const std::string& super_device,
+                     android::fs_mgr::MetadataBuilder* builder,
+                     uint32_t target_slot) override;
+  bool GetDeviceDir(std::string* path) override;
 
  private:
-  friend class DynamicPartitionControlAndroidTest;
+  std::set<std::string> mapped_devices_;
 
-  void CleanupInternal();
+  void CleanupInternal(bool wait);
   bool MapPartitionInternal(const std::string& super_device,
                             const std::string& target_partition_name,
                             uint32_t slot,
                             bool force_writable,
                             std::string* path);
 
-  // Update |builder| according to |partition_metadata|, assuming the device
-  // does not have Virtual A/B.
-  bool UpdatePartitionMetadata(android::fs_mgr::MetadataBuilder* builder,
-                               uint32_t target_slot,
-                               const DeltaArchiveManifest& manifest);
-
-  // Helper for PreparePartitionsForUpdate. Used for dynamic partitions without
-  // Virtual A/B update.
-  bool PrepareDynamicPartitionsForUpdate(uint32_t source_slot,
-                                         uint32_t target_slot,
-                                         const DeltaArchiveManifest& manifest);
-
-  // Helper for PreparePartitionsForUpdate. Used for snapshotted partitions for
-  // Virtual A/B update.
-  bool PrepareSnapshotPartitionsForUpdate(uint32_t source_slot,
-                                          uint32_t target_slot,
-                                          const DeltaArchiveManifest& manifest);
-
-  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;
-
   DISALLOW_COPY_AND_ASSIGN(DynamicPartitionControlAndroid);
 };
 
diff --git a/dynamic_partition_control_android_unittest.cc b/dynamic_partition_control_android_unittest.cc
deleted file mode 100644
index e8ef1f9..0000000
--- a/dynamic_partition_control_android_unittest.cc
+++ /dev/null
@@ -1,489 +0,0 @@
-//
-// Copyright (C) 2019 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/dynamic_partition_control_android.h"
-
-#include <set>
-#include <vector>
-
-#include <base/logging.h>
-#include <base/strings/string_util.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/dynamic_partition_test_utils.h"
-#include "update_engine/mock_dynamic_partition_control.h"
-
-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 DynamicPartitionControlAndroidTest : public ::testing::Test {
- public:
-  void SetUp() override {
-    module_ = std::make_unique<NiceMock<MockDynamicPartitionControlAndroid>>();
-
-    ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
-        .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
-    ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
-        .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
-
-    ON_CALL(dynamicControl(), GetDeviceDir(_))
-        .WillByDefault(Invoke([](auto path) {
-          *path = kFakeDevicePath;
-          return true;
-        }));
-
-    ON_CALL(dynamicControl(), GetSuperPartitionName(_))
-        .WillByDefault(Return(kFakeSuper));
-  }
-
-  // Return the mocked DynamicPartitionControlInterface.
-  NiceMock<MockDynamicPartitionControlAndroid>& dynamicControl() {
-    return static_cast<NiceMock<MockDynamicPartitionControlAndroid>&>(*module_);
-  }
-
-  std::string GetSuperDevice(uint32_t slot) {
-    return GetDevice(dynamicControl().GetSuperPartitionName(slot));
-  }
-
-  uint32_t source() { return slots_.source; }
-  uint32_t target() { return slots_.target; }
-
-  // Return partition names with suffix of source().
-  std::string S(const std::string& name) {
-    return name + kSlotSuffixes[source()];
-  }
-
-  // Return partition names with suffix of target().
-  std::string T(const std::string& name) {
-    return name + kSlotSuffixes[target()];
-  }
-
-  // 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, auto) {
-          return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes));
-        }));
-  }
-
-  void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
-    EXPECT_CALL(dynamicControl(),
-                StoreMetadata(GetSuperDevice(target()),
-                              MetadataMatches(partition_sizes),
-                              target()))
-        .WillOnce(Return(true));
-  }
-
-  // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
-  // slot with each partition in |partitions|.
-  void ExpectUnmap(const std::set<std::string>& partitions) {
-    // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
-    ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_))
-        .WillByDefault(Return(false));
-
-    for (const auto& partition : partitions) {
-      EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition))
-          .WillOnce(Return(true));
-    }
-  }
-  bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) {
-    return dynamicControl().PreparePartitionsForUpdate(
-        source(), target(), PartitionSizesToManifest(partition_sizes), true);
-  }
-  void SetSlots(const TestParam& slots) { slots_ = slots; }
-
-  struct Listener : public ::testing::MatchResultListener {
-    explicit Listener(std::ostream* os) : MatchResultListener(os) {}
-  };
-
-  testing::AssertionResult UpdatePartitionMetadata(
-      const PartitionSuffixSizes& source_metadata,
-      const PartitionSizes& update_metadata,
-      const PartitionSuffixSizes& expected) {
-    return UpdatePartitionMetadata(
-        PartitionSuffixSizesToManifest(source_metadata),
-        PartitionSizesToManifest(update_metadata),
-        PartitionSuffixSizesToManifest(expected));
-  }
-  testing::AssertionResult UpdatePartitionMetadata(
-      const DeltaArchiveManifest& source_manifest,
-      const DeltaArchiveManifest& update_manifest,
-      const DeltaArchiveManifest& expected) {
-    return UpdatePartitionMetadata(
-        source_manifest, update_manifest, MetadataMatches(expected));
-  }
-  testing::AssertionResult UpdatePartitionMetadata(
-      const DeltaArchiveManifest& source_manifest,
-      const DeltaArchiveManifest& update_manifest,
-      const Matcher<MetadataBuilder*>& matcher) {
-    auto super_metadata = NewFakeMetadata(source_manifest);
-    if (!module_->UpdatePartitionMetadata(
-            super_metadata.get(), target(), update_manifest)) {
-      return testing::AssertionFailure()
-             << "UpdatePartitionMetadataInternal failed";
-    }
-    std::stringstream ss;
-    Listener listener(&ss);
-    if (matcher.MatchAndExplain(super_metadata.get(), &listener)) {
-      return testing::AssertionSuccess() << ss.str();
-    } else {
-      return testing::AssertionFailure() << ss.str();
-    }
-  }
-
-  std::unique_ptr<DynamicPartitionControlAndroid> module_;
-  TestParam slots_;
-};
-
-class DynamicPartitionControlAndroidTestP
-    : public DynamicPartitionControlAndroidTest,
-      public ::testing::WithParamInterface<TestParam> {
- public:
-  void SetUp() override {
-    DynamicPartitionControlAndroidTest::SetUp();
-    SetSlots(GetParam());
-  }
-};
-
-// Test resize case. Grow if target metadata contains a partition with a size
-// less than expected.
-TEST_P(DynamicPartitionControlAndroidTestP,
-       NeedGrowIfSizeNotMatchWhenResizing) {
-  PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
-                                       {S("vendor"), 1_GiB},
-                                       {T("system"), 2_GiB},
-                                       {T("vendor"), 1_GiB}};
-  PartitionSuffixSizes expected{{S("system"), 2_GiB},
-                                {S("vendor"), 1_GiB},
-                                {T("system"), 3_GiB},
-                                {T("vendor"), 1_GiB}};
-  PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}};
-  EXPECT_TRUE(
-      UpdatePartitionMetadata(source_metadata, update_metadata, expected));
-}
-
-// Test resize case. Shrink if target metadata contains a partition with a size
-// greater than expected.
-TEST_P(DynamicPartitionControlAndroidTestP,
-       NeedShrinkIfSizeNotMatchWhenResizing) {
-  PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
-                                       {S("vendor"), 1_GiB},
-                                       {T("system"), 2_GiB},
-                                       {T("vendor"), 1_GiB}};
-  PartitionSuffixSizes expected{{S("system"), 2_GiB},
-                                {S("vendor"), 1_GiB},
-                                {T("system"), 2_GiB},
-                                {T("vendor"), 150_MiB}};
-  PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}};
-  EXPECT_TRUE(
-      UpdatePartitionMetadata(source_metadata, update_metadata, expected));
-}
-
-// Test adding partitions on the first run.
-TEST_P(DynamicPartitionControlAndroidTestP, AddPartitionToEmptyMetadata) {
-  PartitionSuffixSizes source_metadata{};
-  PartitionSuffixSizes expected{{T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
-  PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
-  EXPECT_TRUE(
-      UpdatePartitionMetadata(source_metadata, update_metadata, expected));
-}
-
-// Test subsequent add case.
-TEST_P(DynamicPartitionControlAndroidTestP, AddAdditionalPartition) {
-  PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
-                                       {T("system"), 2_GiB}};
-  PartitionSuffixSizes expected{
-      {S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
-  PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
-  EXPECT_TRUE(
-      UpdatePartitionMetadata(source_metadata, update_metadata, expected));
-}
-
-// Test delete one partition.
-TEST_P(DynamicPartitionControlAndroidTestP, DeletePartition) {
-  PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
-                                       {S("vendor"), 1_GiB},
-                                       {T("system"), 2_GiB},
-                                       {T("vendor"), 1_GiB}};
-  // No T("vendor")
-  PartitionSuffixSizes expected{
-      {S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}};
-  PartitionSizes update_metadata{{"system", 2_GiB}};
-  EXPECT_TRUE(
-      UpdatePartitionMetadata(source_metadata, update_metadata, expected));
-}
-
-// Test delete all partitions.
-TEST_P(DynamicPartitionControlAndroidTestP, DeleteAll) {
-  PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
-                                       {S("vendor"), 1_GiB},
-                                       {T("system"), 2_GiB},
-                                       {T("vendor"), 1_GiB}};
-  PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}};
-  PartitionSizes update_metadata{};
-  EXPECT_TRUE(
-      UpdatePartitionMetadata(source_metadata, update_metadata, expected));
-}
-
-// Test corrupt source metadata case.
-TEST_P(DynamicPartitionControlAndroidTestP, CorruptedSourceMetadata) {
-  EXPECT_CALL(dynamicControl(),
-              LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
-      .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
-  ExpectUnmap({T("system")});
-
-  EXPECT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
-      << "Should not be able to continue with corrupt source metadata";
-}
-
-// Test that UpdatePartitionMetadata fails if there is not enough space on the
-// device.
-TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpace) {
-  PartitionSuffixSizes source_metadata{{S("system"), 3_GiB},
-                                       {S("vendor"), 2_GiB},
-                                       {T("system"), 0},
-                                       {T("vendor"), 0}};
-  PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
-
-  EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
-      << "Should not be able to fit 11GiB data into 10GiB space";
-}
-
-TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpaceForSlot) {
-  PartitionSuffixSizes source_metadata{{S("system"), 1_GiB},
-                                       {S("vendor"), 1_GiB},
-                                       {T("system"), 0},
-                                       {T("vendor"), 0}};
-  PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
-  EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
-      << "Should not be able to grow over size of super / 2";
-}
-
-INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
-                        DynamicPartitionControlAndroidTestP,
-                        testing::Values(TestParam{0, 1}, TestParam{1, 0}));
-
-class DynamicPartitionControlAndroidGroupTestP
-    : public DynamicPartitionControlAndroidTestP {
- public:
-  DeltaArchiveManifest source_manifest;
-  void SetUp() override {
-    DynamicPartitionControlAndroidTestP::SetUp();
-    AddGroupAndPartition(
-        &source_manifest, S("android"), 3_GiB, S("system"), 2_GiB);
-    AddGroupAndPartition(&source_manifest, S("oem"), 2_GiB, S("vendor"), 1_GiB);
-    AddGroupAndPartition(&source_manifest, T("android"), 3_GiB, T("system"), 0);
-    AddGroupAndPartition(&source_manifest, T("oem"), 2_GiB, T("vendor"), 0);
-  }
-
-  void AddGroupAndPartition(DeltaArchiveManifest* manifest,
-                            const string& group,
-                            uint64_t group_size,
-                            const string& partition,
-                            uint64_t partition_size) {
-    auto* g = AddGroup(manifest, group, group_size);
-    AddPartition(manifest, g, partition, partition_size);
-  }
-};
-
-// Allow to resize within group.
-TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeWithinGroup) {
-  DeltaArchiveManifest expected;
-  AddGroupAndPartition(&expected, T("android"), 3_GiB, T("system"), 3_GiB);
-  AddGroupAndPartition(&expected, T("oem"), 2_GiB, T("vendor"), 2_GiB);
-
-  DeltaArchiveManifest update_manifest;
-  AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 3_GiB);
-  AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
-
-  EXPECT_TRUE(
-      UpdatePartitionMetadata(source_manifest, update_manifest, expected));
-}
-
-TEST_P(DynamicPartitionControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
-  DeltaArchiveManifest update_manifest;
-  AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 1_GiB),
-      AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 3_GiB);
-  EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
-      << "Should not be able to grow over maximum size of group";
-}
-
-TEST_P(DynamicPartitionControlAndroidGroupTestP, GroupTooBig) {
-  DeltaArchiveManifest update_manifest;
-  AddGroup(&update_manifest, "android", 3_GiB);
-  AddGroup(&update_manifest, "oem", 3_GiB);
-  EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
-      << "Should not be able to grow over size of super / 2";
-}
-
-TEST_P(DynamicPartitionControlAndroidGroupTestP, AddPartitionToGroup) {
-  DeltaArchiveManifest expected;
-  auto* g = AddGroup(&expected, T("android"), 3_GiB);
-  AddPartition(&expected, g, T("system"), 2_GiB);
-  AddPartition(&expected, g, T("system_ext"), 1_GiB);
-
-  DeltaArchiveManifest update_manifest;
-  g = AddGroup(&update_manifest, "android", 3_GiB);
-  AddPartition(&update_manifest, g, "system", 2_GiB);
-  AddPartition(&update_manifest, g, "system_ext", 1_GiB);
-  AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
-
-  EXPECT_TRUE(
-      UpdatePartitionMetadata(source_manifest, update_manifest, expected));
-}
-
-TEST_P(DynamicPartitionControlAndroidGroupTestP, RemovePartitionFromGroup) {
-  DeltaArchiveManifest expected;
-  AddGroup(&expected, T("android"), 3_GiB);
-
-  DeltaArchiveManifest update_manifest;
-  AddGroup(&update_manifest, "android", 3_GiB);
-  AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
-
-  EXPECT_TRUE(
-      UpdatePartitionMetadata(source_manifest, update_manifest, expected));
-}
-
-TEST_P(DynamicPartitionControlAndroidGroupTestP, AddGroup) {
-  DeltaArchiveManifest expected;
-  AddGroupAndPartition(
-      &expected, T("new_group"), 2_GiB, T("new_partition"), 2_GiB);
-
-  DeltaArchiveManifest update_manifest;
-  AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
-  AddGroupAndPartition(&update_manifest, "oem", 1_GiB, "vendor", 1_GiB);
-  AddGroupAndPartition(
-      &update_manifest, "new_group", 2_GiB, "new_partition", 2_GiB);
-  EXPECT_TRUE(
-      UpdatePartitionMetadata(source_manifest, update_manifest, expected));
-}
-
-TEST_P(DynamicPartitionControlAndroidGroupTestP, RemoveGroup) {
-  DeltaArchiveManifest update_manifest;
-  AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
-
-  EXPECT_TRUE(UpdatePartitionMetadata(
-      source_manifest, update_manifest, Not(HasGroup(T("oem")))));
-}
-
-TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeGroup) {
-  DeltaArchiveManifest expected;
-  AddGroupAndPartition(&expected, T("android"), 2_GiB, T("system"), 2_GiB);
-  AddGroupAndPartition(&expected, T("oem"), 3_GiB, T("vendor"), 3_GiB);
-  DeltaArchiveManifest update_manifest;
-  AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB),
-      AddGroupAndPartition(&update_manifest, "oem", 3_GiB, "vendor", 3_GiB);
-  EXPECT_TRUE(
-      UpdatePartitionMetadata(source_manifest, update_manifest, expected));
-}
-
-INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
-                        DynamicPartitionControlAndroidGroupTestP,
-                        testing::Values(TestParam{0, 1}, TestParam{1, 0}));
-
-const PartitionSuffixSizes update_sizes_0() {
-  // Initial state is 0 for "other" slot.
-  return {
-      {"grown_a", 2_GiB},
-      {"shrunk_a", 1_GiB},
-      {"same_a", 100_MiB},
-      {"deleted_a", 150_MiB},
-      // no added_a
-      {"grown_b", 200_MiB},
-      // simulate system_other
-      {"shrunk_b", 0},
-      {"same_b", 0},
-      {"deleted_b", 0},
-      // no added_b
-  };
-}
-
-const PartitionSuffixSizes update_sizes_1() {
-  return {
-      {"grown_a", 2_GiB},
-      {"shrunk_a", 1_GiB},
-      {"same_a", 100_MiB},
-      {"deleted_a", 150_MiB},
-      // no added_a
-      {"grown_b", 3_GiB},
-      {"shrunk_b", 150_MiB},
-      {"same_b", 100_MiB},
-      {"added_b", 150_MiB},
-      // no deleted_b
-  };
-}
-
-const PartitionSuffixSizes update_sizes_2() {
-  return {
-      {"grown_a", 4_GiB},
-      {"shrunk_a", 100_MiB},
-      {"same_a", 100_MiB},
-      {"deleted_a", 64_MiB},
-      // no added_a
-      {"grown_b", 3_GiB},
-      {"shrunk_b", 150_MiB},
-      {"same_b", 100_MiB},
-      {"added_b", 150_MiB},
-      // no deleted_b
-  };
-}
-
-// Test case for first update after the device is manufactured, in which
-// case the "other" slot is likely of size "0" (except system, which is
-// non-zero because of system_other partition)
-TEST_F(DynamicPartitionControlAndroidTest, SimulatedFirstUpdate) {
-  SetSlots({0, 1});
-
-  SetMetadata(source(), update_sizes_0());
-  SetMetadata(target(), update_sizes_0());
-  ExpectStoreMetadata(update_sizes_1());
-  ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
-
-  EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 3_GiB},
-                                          {"shrunk", 150_MiB},
-                                          {"same", 100_MiB},
-                                          {"added", 150_MiB}}));
-}
-
-// After first update, test for the second update. In the second update, the
-// "added" partition is deleted and "deleted" partition is re-added.
-TEST_F(DynamicPartitionControlAndroidTest, SimulatedSecondUpdate) {
-  SetSlots({1, 0});
-
-  SetMetadata(source(), update_sizes_1());
-  SetMetadata(target(), update_sizes_0());
-
-  ExpectStoreMetadata(update_sizes_2());
-  ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
-
-  EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 4_GiB},
-                                          {"shrunk", 100_MiB},
-                                          {"same", 100_MiB},
-                                          {"deleted", 64_MiB}}));
-}
-
-}  // namespace chromeos_update_engine
diff --git a/dynamic_partition_control_interface.h b/dynamic_partition_control_interface.h
index 9c18973..86a0730 100644
--- a/dynamic_partition_control_interface.h
+++ b/dynamic_partition_control_interface.h
@@ -26,34 +26,17 @@
 #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 {
 
-struct FeatureFlag {
-  enum class Value { NONE = 0, RETROFIT, LAUNCH };
-  constexpr explicit FeatureFlag(Value value) : value_(value) {}
-  constexpr bool IsEnabled() const { return value_ != Value::NONE; }
-  constexpr bool IsRetrofit() const { return value_ == Value::RETROFIT; }
-  constexpr bool IsLaunch() const { return value_ == Value::LAUNCH; }
-
- private:
-  Value value_;
-};
-
 class DynamicPartitionControlInterface {
  public:
   virtual ~DynamicPartitionControlInterface() = default;
 
-  // Return the feature flags of dynamic partitions on this device.
-  // Return RETROFIT iff dynamic partitions is retrofitted on this device,
-  //        LAUNCH iff this device is launched with dynamic partitions,
-  //        NONE iff dynamic partitions is disabled on this device.
-  virtual FeatureFlag GetDynamicPartitionsFeatureFlag() = 0;
+  // Return true iff dynamic partitions is enabled on this device.
+  virtual bool IsDynamicPartitionsEnabled() = 0;
 
-  // Return the feature flags of Virtual A/B on this device.
-  virtual FeatureFlag GetVirtualAbFeatureFlag() = 0;
+  // Return true iff dynamic partitions is retrofitted on this device.
+  virtual bool IsDynamicPartitionsRetrofit() = 0;
 
   // Map logical partition on device-mapper.
   // |super_device| is the device path of the physical partition ("super").
@@ -69,6 +52,13 @@
       bool force_writable,
       std::string* path) = 0;
 
+  // Unmap logical partition on device mapper. This is the reverse operation
+  // of MapPartitionOnDeviceMapper.
+  // If |wait| is set, wait until the device is unmapped.
+  // Returns true if unmapped successfully.
+  virtual bool UnmapPartitionOnDeviceMapper(
+      const std::string& target_partition_name, bool wait) = 0;
+
   // Do necessary cleanups before destroying the object.
   virtual void Cleanup() = 0;
 
@@ -87,26 +77,20 @@
                                      std::string* path) = 0;
 
   // Retrieve metadata from |super_device| at slot |source_slot|.
+  // On retrofit devices, if |target_slot| != kInvalidSlot, the returned
+  // metadata automatically includes block devices at |target_slot|.
   virtual std::unique_ptr<android::fs_mgr::MetadataBuilder> LoadMetadataBuilder(
-      const std::string& super_device, uint32_t source_slot) = 0;
+      const std::string& super_device,
+      uint32_t source_slot,
+      uint32_t target_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.
-  // If |update| is set, create snapshots and writes super partition metadata.
-  virtual bool PreparePartitionsForUpdate(uint32_t source_slot,
-                                          uint32_t target_slot,
-                                          const DeltaArchiveManifest& manifest,
-                                          bool update) = 0;
+  // Write metadata |builder| to |super_device| at slot |target_slot|.
+  virtual bool StoreMetadata(const std::string& super_device,
+                             android::fs_mgr::MetadataBuilder* builder,
+                             uint32_t target_slot) = 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;
 };
 
 }  // namespace chromeos_update_engine
diff --git a/dynamic_partition_test_utils.h b/dynamic_partition_test_utils.h
deleted file mode 100644
index 346998f..0000000
--- a/dynamic_partition_test_utils.h
+++ /dev/null
@@ -1,286 +0,0 @@
-//
-// Copyright (C) 2019 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.
-//
-
-#ifndef UPDATE_ENGINE_DYNAMIC_PARTITION_TEST_UTILS_H_
-#define UPDATE_ENGINE_DYNAMIC_PARTITION_TEST_UTILS_H_
-
-#include <stdint.h>
-
-#include <iostream>
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <base/strings/string_util.h>
-#include <fs_mgr.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <liblp/builder.h>
-#include <storage_literals/storage_literals.h>
-
-#include "update_engine/common/boot_control_interface.h"
-#include "update_engine/update_metadata.pb.h"
-
-namespace chromeos_update_engine {
-
-using android::fs_mgr::MetadataBuilder;
-using testing::_;
-using testing::MakeMatcher;
-using testing::Matcher;
-using testing::MatcherInterface;
-using testing::MatchResultListener;
-using namespace android::storage_literals;  // NOLINT(build/namespaces)
-
-constexpr const uint32_t kMaxNumSlots = 2;
-constexpr const char* kSlotSuffixes[kMaxNumSlots] = {"_a", "_b"};
-constexpr const char* kFakeDevicePath = "/fake/dev/path/";
-constexpr const char* kFakeDmDevicePath = "/fake/dm/dev/path/";
-constexpr const uint32_t kFakeMetadataSize = 65536;
-constexpr const char* kDefaultGroup = "foo";
-constexpr const char* kFakeSuper = "fake_super";
-
-// A map describing the size of each partition.
-// "{name, size}"
-using PartitionSizes = std::map<std::string, uint64_t>;
-
-// "{name_a, size}"
-using PartitionSuffixSizes = std::map<std::string, uint64_t>;
-
-constexpr uint64_t kDefaultGroupSize = 5_GiB;
-// Super device size. 1 MiB for metadata.
-constexpr uint64_t kDefaultSuperSize = kDefaultGroupSize * 2 + 1_MiB;
-
-template <typename U, typename V>
-inline std::ostream& operator<<(std::ostream& os, const std::map<U, V>& param) {
-  os << "{";
-  bool first = true;
-  for (const auto& pair : param) {
-    if (!first)
-      os << ", ";
-    os << pair.first << ":" << pair.second;
-    first = false;
-  }
-  return os << "}";
-}
-
-template <typename V>
-inline void VectorToStream(std::ostream& os, const V& param) {
-  os << "[";
-  bool first = true;
-  for (const auto& e : param) {
-    if (!first)
-      os << ", ";
-    os << e;
-    first = false;
-  }
-  os << "]";
-}
-
-inline std::ostream& operator<<(std::ostream& os, const PartitionUpdate& p) {
-  return os << "{" << p.partition_name() << ", "
-            << p.new_partition_info().size() << "}";
-}
-
-inline std::ostream& operator<<(std::ostream& os,
-                                const DynamicPartitionGroup& g) {
-  os << "{" << g.name() << ", " << g.size() << ", ";
-  VectorToStream(os, g.partition_names());
-  return os << "}";
-}
-
-inline std::ostream& operator<<(std::ostream& os,
-                                const DeltaArchiveManifest& m) {
-  os << "{.groups = ";
-  VectorToStream(os, m.dynamic_partition_metadata().groups());
-  os << ", .partitions = ";
-  VectorToStream(os, m.partitions());
-  return os;
-}
-
-inline std::string GetDevice(const std::string& name) {
-  return kFakeDevicePath + name;
-}
-
-inline std::string GetDmDevice(const std::string& name) {
-  return kFakeDmDevicePath + name;
-}
-
-inline DynamicPartitionGroup* AddGroup(DeltaArchiveManifest* manifest,
-                                       const std::string& group,
-                                       uint64_t group_size) {
-  auto* g = manifest->mutable_dynamic_partition_metadata()->add_groups();
-  g->set_name(group);
-  g->set_size(group_size);
-  return g;
-}
-
-inline void AddPartition(DeltaArchiveManifest* manifest,
-                         DynamicPartitionGroup* group,
-                         const std::string& partition,
-                         uint64_t partition_size) {
-  group->add_partition_names(partition);
-  auto* p = manifest->add_partitions();
-  p->set_partition_name(partition);
-  p->mutable_new_partition_info()->set_size(partition_size);
-}
-
-// To support legacy tests, auto-convert {name_a: size} map to
-// DeltaArchiveManifest.
-inline DeltaArchiveManifest PartitionSuffixSizesToManifest(
-    const PartitionSuffixSizes& partition_sizes) {
-  DeltaArchiveManifest manifest;
-  for (const char* suffix : kSlotSuffixes) {
-    AddGroup(&manifest, std::string(kDefaultGroup) + suffix, kDefaultGroupSize);
-  }
-  for (const auto& pair : partition_sizes) {
-    for (size_t suffix_idx = 0; suffix_idx < kMaxNumSlots; ++suffix_idx) {
-      if (base::EndsWith(pair.first,
-                         kSlotSuffixes[suffix_idx],
-                         base::CompareCase::SENSITIVE)) {
-        AddPartition(
-            &manifest,
-            manifest.mutable_dynamic_partition_metadata()->mutable_groups(
-                suffix_idx),
-            pair.first,
-            pair.second);
-      }
-    }
-  }
-  return manifest;
-}
-
-// To support legacy tests, auto-convert {name: size} map to PartitionMetadata.
-inline DeltaArchiveManifest PartitionSizesToManifest(
-    const PartitionSizes& partition_sizes) {
-  DeltaArchiveManifest manifest;
-  auto* g = AddGroup(&manifest, std::string(kDefaultGroup), kDefaultGroupSize);
-  for (const auto& pair : partition_sizes) {
-    AddPartition(&manifest, g, pair.first, pair.second);
-  }
-  return manifest;
-}
-
-inline std::unique_ptr<MetadataBuilder> NewFakeMetadata(
-    const DeltaArchiveManifest& manifest) {
-  auto builder =
-      MetadataBuilder::New(kDefaultSuperSize, kFakeMetadataSize, kMaxNumSlots);
-  for (const auto& group : manifest.dynamic_partition_metadata().groups()) {
-    EXPECT_TRUE(builder->AddGroup(group.name(), group.size()));
-    for (const auto& partition_name : group.partition_names()) {
-      EXPECT_NE(
-          nullptr,
-          builder->AddPartition(partition_name, group.name(), 0 /* attr */));
-    }
-  }
-  for (const auto& partition : manifest.partitions()) {
-    auto p = builder->FindPartition(partition.partition_name());
-    EXPECT_TRUE(p && builder->ResizePartition(
-                         p, partition.new_partition_info().size()));
-  }
-  return builder;
-}
-
-class MetadataMatcher : public MatcherInterface<MetadataBuilder*> {
- public:
-  explicit MetadataMatcher(const PartitionSuffixSizes& partition_sizes)
-      : manifest_(PartitionSuffixSizesToManifest(partition_sizes)) {}
-  explicit MetadataMatcher(const DeltaArchiveManifest& manifest)
-      : manifest_(manifest) {}
-
-  bool MatchAndExplain(MetadataBuilder* metadata,
-                       MatchResultListener* listener) const override {
-    bool success = true;
-    for (const auto& group : manifest_.dynamic_partition_metadata().groups()) {
-      for (const auto& partition_name : group.partition_names()) {
-        auto p = metadata->FindPartition(partition_name);
-        if (p == nullptr) {
-          if (!success)
-            *listener << "; ";
-          *listener << "No partition " << partition_name;
-          success = false;
-          continue;
-        }
-        const auto& partition_updates = manifest_.partitions();
-        auto it = std::find_if(partition_updates.begin(),
-                               partition_updates.end(),
-                               [&](const auto& p) {
-                                 return p.partition_name() == partition_name;
-                               });
-        if (it == partition_updates.end()) {
-          *listener << "Can't find partition update " << partition_name;
-          success = false;
-          continue;
-        }
-        auto partition_size = it->new_partition_info().size();
-        if (p->size() != partition_size) {
-          if (!success)
-            *listener << "; ";
-          *listener << "Partition " << partition_name << " has size "
-                    << p->size() << ", expected " << partition_size;
-          success = false;
-        }
-        if (p->group_name() != group.name()) {
-          if (!success)
-            *listener << "; ";
-          *listener << "Partition " << partition_name << " has group "
-                    << p->group_name() << ", expected " << group.name();
-          success = false;
-        }
-      }
-    }
-    return success;
-  }
-
-  void DescribeTo(std::ostream* os) const override {
-    *os << "expect: " << manifest_;
-  }
-
-  void DescribeNegationTo(std::ostream* os) const override {
-    *os << "expect not: " << manifest_;
-  }
-
- private:
-  DeltaArchiveManifest manifest_;
-};
-
-inline Matcher<MetadataBuilder*> MetadataMatches(
-    const PartitionSuffixSizes& partition_sizes) {
-  return MakeMatcher(new MetadataMatcher(partition_sizes));
-}
-
-inline Matcher<MetadataBuilder*> MetadataMatches(
-    const DeltaArchiveManifest& manifest) {
-  return MakeMatcher(new MetadataMatcher(manifest));
-}
-
-MATCHER_P(HasGroup, group, " has group " + group) {
-  auto groups = arg->ListGroups();
-  return std::find(groups.begin(), groups.end(), group) != groups.end();
-}
-
-struct TestParam {
-  uint32_t source;
-  uint32_t target;
-};
-inline std::ostream& operator<<(std::ostream& os, const TestParam& param) {
-  return os << "{source: " << param.source << ", target:" << param.target
-            << "}";
-}
-
-}  // namespace chromeos_update_engine
-
-#endif  // UPDATE_ENGINE_DYNAMIC_PARTITION_TEST_UTILS_H_
diff --git a/dynamic_partition_utils.cc b/dynamic_partition_utils.cc
deleted file mode 100644
index f9bd886..0000000
--- a/dynamic_partition_utils.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-// Copyright (C) 2019 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/dynamic_partition_utils.h"
-
-#include <vector>
-
-#include <base/logging.h>
-#include <base/strings/string_util.h>
-
-using android::fs_mgr::MetadataBuilder;
-
-namespace chromeos_update_engine {
-
-void DeleteGroupsWithSuffix(MetadataBuilder* builder,
-                            const std::string& suffix) {
-  std::vector<std::string> groups = builder->ListGroups();
-  for (const auto& group_name : groups) {
-    if (base::EndsWith(group_name, suffix, base::CompareCase::SENSITIVE)) {
-      LOG(INFO) << "Removing group " << group_name;
-      builder->RemoveGroupAndPartitions(group_name);
-    }
-  }
-}
-
-}  // namespace chromeos_update_engine
diff --git a/dynamic_partition_utils.h b/dynamic_partition_utils.h
deleted file mode 100644
index 09fce00..0000000
--- a/dynamic_partition_utils.h
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// Copyright (C) 2019 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.
-//
-
-#ifndef UPDATE_ENGINE_DYNAMIC_PARTITION_UTILS_H_
-#define UPDATE_ENGINE_DYNAMIC_PARTITION_UTILS_H_
-
-#include <string>
-
-#include <liblp/builder.h>
-
-namespace chromeos_update_engine {
-
-// Delete all groups (and their partitions) in |builder| that have names
-// ending with |suffix|.
-void DeleteGroupsWithSuffix(android::fs_mgr::MetadataBuilder* builder,
-                            const std::string& suffix);
-
-}  // namespace chromeos_update_engine
-
-#endif  // UPDATE_ENGINE_DYNAMIC_PARTITION_UTILS_H_
diff --git a/hardware_android.cc b/hardware_android.cc
index 9611ba6..21d4659 100644
--- a/hardware_android.cc
+++ b/hardware_android.cc
@@ -192,13 +192,6 @@
   return GetIntProperty<int64_t>(kPropBuildDateUTC, 0);
 }
 
-// Returns true if the device runs an userdebug build, and explicitly allows OTA
-// downgrade.
-bool HardwareAndroid::AllowDowngrade() const {
-  return GetBoolProperty("ro.ota.allow_downgrade", false) &&
-         GetBoolProperty("ro.debuggable", false);
-}
-
 bool HardwareAndroid::GetFirstActiveOmahaPingSent() const {
   LOG(WARNING) << "STUB: Assuming first active omaha was never set.";
   return false;
diff --git a/hardware_android.h b/hardware_android.h
index 2a8f669..5b3c99d 100644
--- a/hardware_android.h
+++ b/hardware_android.h
@@ -53,7 +53,6 @@
   bool GetNonVolatileDirectory(base::FilePath* path) const override;
   bool GetPowerwashSafeDirectory(base::FilePath* path) const override;
   int64_t GetBuildTimestamp() const override;
-  bool AllowDowngrade() const override;
   bool GetFirstActiveOmahaPingSent() const override;
   bool SetFirstActiveOmahaPingSent() override;
 
diff --git a/hardware_chromeos.h b/hardware_chromeos.h
index 57be3b0..8829866 100644
--- a/hardware_chromeos.h
+++ b/hardware_chromeos.h
@@ -58,7 +58,6 @@
   bool GetNonVolatileDirectory(base::FilePath* path) const override;
   bool GetPowerwashSafeDirectory(base::FilePath* path) const override;
   int64_t GetBuildTimestamp() const override;
-  bool AllowDowngrade() const override { return false; }
   bool GetFirstActiveOmahaPingSent() const override;
   bool SetFirstActiveOmahaPingSent() override;
 
diff --git a/mock_dynamic_partition_control.h b/mock_dynamic_partition_control.h
index 8146e0f..24aca06 100644
--- a/mock_dynamic_partition_control.h
+++ b/mock_dynamic_partition_control.h
@@ -21,8 +21,6 @@
 
 #include <gmock/gmock.h>
 
-#include "update_engine/common/boot_control_interface.h"
-#include "update_engine/dynamic_partition_control_android.h"
 #include "update_engine/dynamic_partition_control_interface.h"
 
 namespace chromeos_update_engine {
@@ -35,32 +33,7 @@
                     uint32_t,
                     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());
-};
-
-class MockDynamicPartitionControlAndroid
-    : public DynamicPartitionControlAndroid {
- public:
-  MOCK_METHOD5(MapPartitionOnDeviceMapper,
-               bool(const std::string&,
-                    const std::string&,
-                    uint32_t,
-                    bool,
-                    std::string*));
-  MOCK_METHOD1(UnmapPartitionOnDeviceMapper, bool(const std::string&));
+  MOCK_METHOD2(UnmapPartitionOnDeviceMapper, bool(const std::string&, bool));
   MOCK_METHOD0(Cleanup, void());
   MOCK_METHOD1(DeviceExists, bool(const std::string&));
   MOCK_METHOD1(GetState, ::android::dm::DmDeviceState(const std::string&));
@@ -73,10 +46,8 @@
                     android::fs_mgr::MetadataBuilder*,
                     uint32_t));
   MOCK_METHOD1(GetDeviceDir, bool(std::string*));
-  MOCK_METHOD0(GetDynamicPartitionsFeatureFlag, FeatureFlag());
-  MOCK_METHOD1(GetSuperPartitionName, std::string(uint32_t));
-  MOCK_METHOD0(GetVirtualAbFeatureFlag, FeatureFlag());
-  MOCK_METHOD0(FinishUpdate, bool());
+  MOCK_METHOD0(IsDynamicPartitionsEnabled, bool());
+  MOCK_METHOD0(IsDynamicPartitionsRetrofit, bool());
 };
 
 }  // namespace chromeos_update_engine
diff --git a/otacerts.zip b/otacerts.zip
deleted file mode 100644
index 00a5a51..0000000
--- a/otacerts.zip
+++ /dev/null
Binary files differ
diff --git a/payload_consumer/certificate_parser_android.cc b/payload_consumer/certificate_parser_android.cc
deleted file mode 100644
index 4a20547..0000000
--- a/payload_consumer/certificate_parser_android.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-//
-// Copyright (C) 2019 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/payload_consumer/certificate_parser_android.h"
-
-#include <memory>
-#include <utility>
-
-#include <base/logging.h>
-#include <openssl/bio.h>
-#include <openssl/pem.h>
-#include <ziparchive/zip_archive.h>
-
-#include "update_engine/payload_consumer/certificate_parser_interface.h"
-
-namespace {
-bool IterateZipEntriesAndSearchForKeys(
-    const ZipArchiveHandle& handle, std::vector<std::vector<uint8_t>>* result) {
-  void* cookie;
-  int32_t iter_status = StartIteration(handle, &cookie, "", "x509.pem");
-  if (iter_status != 0) {
-    LOG(ERROR) << "Failed to iterate over entries in the certificate zipfile: "
-               << ErrorCodeString(iter_status);
-    return false;
-  }
-  std::unique_ptr<void, decltype(&EndIteration)> guard(cookie, EndIteration);
-
-  std::vector<std::vector<uint8_t>> pem_keys;
-  std::string_view name;
-  ZipEntry entry;
-  while ((iter_status = Next(cookie, &entry, &name)) == 0) {
-    std::vector<uint8_t> pem_content(entry.uncompressed_length);
-    if (int32_t extract_status = ExtractToMemory(
-            handle, &entry, pem_content.data(), pem_content.size());
-        extract_status != 0) {
-      LOG(ERROR) << "Failed to extract " << name << ": "
-                 << ErrorCodeString(extract_status);
-      return false;
-    }
-    pem_keys.push_back(pem_content);
-  }
-
-  if (iter_status != -1) {
-    LOG(ERROR) << "Error while iterating over zip entries: "
-               << ErrorCodeString(iter_status);
-    return false;
-  }
-
-  *result = std::move(pem_keys);
-  return true;
-}
-
-}  // namespace
-
-namespace chromeos_update_engine {
-bool CertificateParserAndroid::ReadPublicKeysFromCertificates(
-    const std::string& path,
-    std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>>*
-        out_public_keys) {
-  out_public_keys->clear();
-
-  ZipArchiveHandle handle;
-  if (int32_t open_status = OpenArchive(path.c_str(), &handle);
-      open_status != 0) {
-    LOG(ERROR) << "Failed to open " << path << ": "
-               << ErrorCodeString(open_status);
-    return false;
-  }
-
-  std::vector<std::vector<uint8_t>> pem_certs;
-  if (!IterateZipEntriesAndSearchForKeys(handle, &pem_certs)) {
-    CloseArchive(handle);
-    return false;
-  }
-  CloseArchive(handle);
-
-  // Convert the certificates into public keys. Stop and return false if we
-  // encounter an error.
-  std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>> result;
-  for (const auto& cert : pem_certs) {
-    std::unique_ptr<BIO, decltype(&BIO_free)> input(
-        BIO_new_mem_buf(cert.data(), cert.size()), BIO_free);
-
-    std::unique_ptr<X509, decltype(&X509_free)> x509(
-        PEM_read_bio_X509(input.get(), nullptr, nullptr, nullptr), X509_free);
-    if (!x509) {
-      LOG(ERROR) << "Failed to read x509 certificate";
-      return false;
-    }
-
-    std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> public_key(
-        X509_get_pubkey(x509.get()), EVP_PKEY_free);
-    if (!public_key) {
-      LOG(ERROR) << "Failed to extract the public key from x509 certificate";
-      return false;
-    }
-    result.push_back(std::move(public_key));
-  }
-
-  *out_public_keys = std::move(result);
-  return true;
-}
-
-std::unique_ptr<CertificateParserInterface> CreateCertificateParser() {
-  return std::make_unique<CertificateParserAndroid>();
-}
-
-}  // namespace chromeos_update_engine
diff --git a/payload_consumer/certificate_parser_android.h b/payload_consumer/certificate_parser_android.h
deleted file mode 100644
index ccb9293..0000000
--- a/payload_consumer/certificate_parser_android.h
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// Copyright (C) 2019 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.
-//
-
-#ifndef UPDATE_ENGINE_CERTIFICATE_PARSER_ANDROID_H_
-#define UPDATE_ENGINE_CERTIFICATE_PARSER_ANDROID_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <base/macros.h>
-
-#include "payload_consumer/certificate_parser_interface.h"
-
-namespace chromeos_update_engine {
-// This class parses the certificates from a zip file. Because the Android
-// build system stores the certs in otacerts.zip.
-class CertificateParserAndroid : public CertificateParserInterface {
- public:
-  CertificateParserAndroid() = default;
-
-  bool ReadPublicKeysFromCertificates(
-      const std::string& path,
-      std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>>*
-          out_public_keys) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(CertificateParserAndroid);
-};
-
-}  // namespace chromeos_update_engine
-
-#endif
diff --git a/payload_consumer/certificate_parser_android_unittest.cc b/payload_consumer/certificate_parser_android_unittest.cc
deleted file mode 100644
index e300414..0000000
--- a/payload_consumer/certificate_parser_android_unittest.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-//
-// Copyright (C) 2019 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/payload_consumer/certificate_parser_interface.h"
-
-#include <string>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/common/hash_calculator.h"
-#include "update_engine/common/test_utils.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/payload_consumer/payload_verifier.h"
-#include "update_engine/payload_generator/payload_signer.h"
-
-namespace chromeos_update_engine {
-
-extern const char* kUnittestPrivateKeyPath;
-const char* kUnittestOtacertsPath = "otacerts.zip";
-
-TEST(CertificateParserAndroidTest, ParseZipArchive) {
-  std::string ota_cert =
-      test_utils::GetBuildArtifactsPath(kUnittestOtacertsPath);
-  ASSERT_TRUE(utils::FileExists(ota_cert.c_str()));
-
-  std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>> keys;
-  auto parser = CreateCertificateParser();
-  ASSERT_TRUE(parser->ReadPublicKeysFromCertificates(ota_cert, &keys));
-  ASSERT_EQ(1u, keys.size());
-}
-
-TEST(CertificateParserAndroidTest, VerifySignature) {
-  brillo::Blob hash_blob;
-  ASSERT_TRUE(HashCalculator::RawHashOfData({'x'}, &hash_blob));
-  brillo::Blob sig_blob;
-  ASSERT_TRUE(PayloadSigner::SignHash(
-      hash_blob,
-      test_utils::GetBuildArtifactsPath(kUnittestPrivateKeyPath),
-      &sig_blob));
-
-  auto verifier = PayloadVerifier::CreateInstanceFromZipPath(
-      test_utils::GetBuildArtifactsPath(kUnittestOtacertsPath));
-  ASSERT_TRUE(verifier != nullptr);
-  ASSERT_TRUE(verifier->VerifyRawSignature(sig_blob, hash_blob, nullptr));
-}
-
-}  // namespace chromeos_update_engine
diff --git a/payload_consumer/certificate_parser_interface.h b/payload_consumer/certificate_parser_interface.h
deleted file mode 100644
index dad23d2..0000000
--- a/payload_consumer/certificate_parser_interface.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// Copyright (C) 2019 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.
-//
-
-#ifndef UPDATE_ENGINE_CERTIFICATE_PARSER_INTERFACE_H_
-#define UPDATE_ENGINE_CERTIFICATE_PARSER_INTERFACE_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <openssl/pem.h>
-
-namespace chromeos_update_engine {
-
-// This class parses the PEM encoded X509 certificates from |path|; and
-// passes the parsed public keys to the caller.
-class CertificateParserInterface {
- public:
-  virtual ~CertificateParserInterface() = default;
-
-  virtual bool ReadPublicKeysFromCertificates(
-      const std::string& path,
-      std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>>*
-          out_public_keys) = 0;
-};
-
-std::unique_ptr<CertificateParserInterface> CreateCertificateParser();
-
-}  // namespace chromeos_update_engine
-
-#endif
diff --git a/payload_consumer/certificate_parser_stub.cc b/payload_consumer/certificate_parser_stub.cc
deleted file mode 100644
index 95fd6e8..0000000
--- a/payload_consumer/certificate_parser_stub.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-//
-// Copyright (C) 2019 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 <payload_consumer/certificate_parser_stub.h>
-
-namespace chromeos_update_engine {
-bool CertificateParserStub::ReadPublicKeysFromCertificates(
-    const std::string& path,
-    std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>>*
-        out_public_keys) {
-  return true;
-}
-
-std::unique_ptr<CertificateParserInterface> CreateCertificateParser() {
-  return std::make_unique<CertificateParserStub>();
-}
-
-}  // namespace chromeos_update_engine
diff --git a/payload_consumer/certificate_parser_stub.h b/payload_consumer/certificate_parser_stub.h
deleted file mode 100644
index f4f8825..0000000
--- a/payload_consumer/certificate_parser_stub.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// Copyright (C) 2019 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.
-//
-
-#ifndef UPDATE_ENGINE_CERTIFICATE_PARSER_STUB_H_
-#define UPDATE_ENGINE_CERTIFICATE_PARSER_STUB_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <base/macros.h>
-
-#include "payload_consumer/certificate_parser_interface.h"
-
-namespace chromeos_update_engine {
-class CertificateParserStub : public CertificateParserInterface {
- public:
-  CertificateParserStub() = default;
-
-  bool ReadPublicKeysFromCertificates(
-      const std::string& path,
-      std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>>*
-          out_public_keys) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(CertificateParserStub);
-};
-
-}  // namespace chromeos_update_engine
-
-#endif  // UPDATE_ENGINE_CERTIFICATE_PARSER_STUB_H_
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index 8b3f61c..d76a959 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -46,7 +46,6 @@
 #include "update_engine/common/terminator.h"
 #include "update_engine/payload_consumer/bzip_extent_writer.h"
 #include "update_engine/payload_consumer/cached_file_descriptor.h"
-#include "update_engine/payload_consumer/certificate_parser_interface.h"
 #include "update_engine/payload_consumer/download_action.h"
 #include "update_engine/payload_consumer/extent_reader.h"
 #include "update_engine/payload_consumer/extent_writer.h"
@@ -527,19 +526,17 @@
                  << "Trusting metadata size in payload = " << metadata_size_;
   }
 
-  auto [payload_verifier, perform_verification] = CreatePayloadVerifier();
-  if (!payload_verifier) {
-    LOG(ERROR) << "Failed to create payload verifier.";
+  string public_key;
+  if (!GetPublicKey(&public_key)) {
+    LOG(ERROR) << "Failed to get public key.";
     *error = ErrorCode::kDownloadMetadataSignatureVerificationError;
-    if (perform_verification) {
-      return MetadataParseResult::kError;
-    }
-  } else {
-    // We have the full metadata in |payload|. Verify its integrity
-    // and authenticity based on the information we have in Omaha response.
-    *error = payload_metadata_.ValidateMetadataSignature(
-        payload, payload_->metadata_signature, *payload_verifier);
+    return MetadataParseResult::kError;
   }
+
+  // We have the full metadata in |payload|. Verify its integrity
+  // and authenticity based on the information we have in Omaha response.
+  *error = payload_metadata_.ValidateMetadataSignature(
+      payload, payload_->metadata_signature, public_key);
   if (*error != ErrorCode::kSuccess) {
     if (install_plan_->hash_checks_mandatory) {
       // The autoupdate_CatchBadSignatures test checks for this string
@@ -811,6 +808,7 @@
     for (const PartitionUpdate& partition : manifest_.partitions()) {
       partitions_.push_back(partition);
     }
+    manifest_.clear_partitions();
   } else if (major_payload_version_ == kChromeOSMajorPayloadVersion) {
     LOG(INFO) << "Converting update information from old format.";
     PartitionUpdate root_part;
@@ -925,16 +923,12 @@
   }
 
   if (install_plan_->target_slot != BootControlInterface::kInvalidSlot) {
-    if (!PreparePartitionsForUpdate()) {
+    if (!InitPartitionMetadata()) {
       *error = ErrorCode::kInstallDeviceOpenError;
       return false;
     }
   }
 
-  if (major_payload_version_ == kBrilloMajorPayloadVersion) {
-    manifest_.clear_partitions();
-  }
-
   if (!install_plan_->LoadPartitionsFromSlots(boot_control_)) {
     LOG(ERROR) << "Unable to determine all the partition devices.";
     *error = ErrorCode::kInstallDeviceOpenError;
@@ -944,18 +938,45 @@
   return true;
 }
 
-bool DeltaPerformer::PreparePartitionsForUpdate() {
+bool DeltaPerformer::InitPartitionMetadata() {
+  BootControlInterface::PartitionMetadata partition_metadata;
+  if (manifest_.has_dynamic_partition_metadata()) {
+    std::map<string, uint64_t> partition_sizes;
+    for (const auto& 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));
+    }
+  }
+
   bool metadata_updated = false;
   prefs_->GetBoolean(kPrefsDynamicPartitionMetadataUpdated, &metadata_updated);
-  if (!boot_control_->PreparePartitionsForUpdate(
-          install_plan_->target_slot, manifest_, !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(kPrefsDynamicPartitionMetadataUpdated, true));
-  LOG(INFO) << "PreparePartitionsForUpdate done.";
+  LOG(INFO) << "InitPartitionMetadata done.";
 
   return true;
 }
@@ -1599,32 +1620,10 @@
     return brillo::data_encoding::Base64Decode(install_plan_->public_key_rsa,
                                                out_public_key);
   }
-  LOG(INFO) << "No public keys found for verification.";
+
   return true;
 }
 
-std::pair<std::unique_ptr<PayloadVerifier>, bool>
-DeltaPerformer::CreatePayloadVerifier() {
-  if (utils::FileExists(update_certificates_path_.c_str())) {
-    LOG(INFO) << "Verifying using certificates: " << update_certificates_path_;
-    return {
-        PayloadVerifier::CreateInstanceFromZipPath(update_certificates_path_),
-        true};
-  }
-
-  string public_key;
-  if (!GetPublicKey(&public_key)) {
-    LOG(ERROR) << "Failed to read public key";
-    return {nullptr, true};
-  }
-
-  // Skips the verification if the public key is empty.
-  if (public_key.empty()) {
-    return {nullptr, false};
-  }
-  return {PayloadVerifier::CreateInstance(public_key), true};
-}
-
 ErrorCode DeltaPerformer::ValidateManifest() {
   // Perform assorted checks to sanity check the manifest, make sure it
   // matches data from other sources, and that it is a supported version.
@@ -1692,11 +1691,7 @@
                << hardware_->GetBuildTimestamp()
                << ") is newer than the maximum timestamp in the manifest ("
                << manifest_.max_timestamp() << ")";
-    if (!hardware_->AllowDowngrade()) {
-      return ErrorCode::kPayloadTimestampError;
-    }
-    LOG(INFO) << "The current OS build allows downgrade, continuing to apply"
-                 " the payload with an older timestamp.";
+    return ErrorCode::kPayloadTimestampError;
   }
 
   if (major_payload_version_ == kChromeOSMajorPayloadVersion) {
@@ -1789,6 +1784,12 @@
 ErrorCode DeltaPerformer::VerifyPayload(
     const brillo::Blob& update_check_response_hash,
     const uint64_t update_check_response_size) {
+  string public_key;
+  if (!GetPublicKey(&public_key)) {
+    LOG(ERROR) << "Failed to get public key.";
+    return ErrorCode::kDownloadPayloadPubKeyVerificationError;
+  }
+
   // Verifies the download size.
   if (update_check_response_size !=
       metadata_size_ + metadata_signature_size_ + buffer_offset_) {
@@ -1806,22 +1807,19 @@
       ErrorCode::kPayloadHashMismatchError,
       payload_hash_calculator_.raw_hash() == update_check_response_hash);
 
+  // Verifies the signed payload hash.
+  if (public_key.empty()) {
+    LOG(WARNING) << "Not verifying signed delta payload -- missing public key.";
+    return ErrorCode::kSuccess;
+  }
   TEST_AND_RETURN_VAL(ErrorCode::kSignedDeltaPayloadExpectedError,
                       !signatures_message_data_.empty());
   brillo::Blob hash_data = signed_hash_calculator_.raw_hash();
   TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadPubKeyVerificationError,
                       hash_data.size() == kSHA256Size);
 
-  auto [payload_verifier, perform_verification] = CreatePayloadVerifier();
-  if (!perform_verification) {
-    LOG(WARNING) << "Not verifying signed delta payload -- missing public key.";
-    return ErrorCode::kSuccess;
-  }
-  if (!payload_verifier) {
-    LOG(ERROR) << "Failed to create the payload verifier.";
-    return ErrorCode::kDownloadPayloadPubKeyVerificationError;
-  }
-  if (!payload_verifier->VerifySignature(signatures_message_data_, hash_data)) {
+  if (!PayloadVerifier::VerifySignature(
+          signatures_message_data_, public_key, hash_data)) {
     // The autoupdate_CatchBadSignatures test checks for this string
     // in log-files. Keep in sync.
     LOG(ERROR) << "Public key verification failed, thus update failed.";
diff --git a/payload_consumer/delta_performer.h b/payload_consumer/delta_performer.h
index 4c64dfa..17cb599 100644
--- a/payload_consumer/delta_performer.h
+++ b/payload_consumer/delta_performer.h
@@ -20,9 +20,7 @@
 #include <inttypes.h>
 
 #include <limits>
-#include <memory>
 #include <string>
-#include <utility>
 #include <vector>
 
 #include <base/time/time.h>
@@ -36,7 +34,6 @@
 #include "update_engine/payload_consumer/file_writer.h"
 #include "update_engine/payload_consumer/install_plan.h"
 #include "update_engine/payload_consumer/payload_metadata.h"
-#include "update_engine/payload_consumer/payload_verifier.h"
 #include "update_engine/update_metadata.pb.h"
 
 namespace chromeos_update_engine {
@@ -159,11 +156,6 @@
     public_key_path_ = public_key_path;
   }
 
-  void set_update_certificates_path(
-      const std::string& update_certificates_path) {
-    update_certificates_path_ = update_certificates_path;
-  }
-
   // Return true if header parsing is finished and no errors occurred.
   bool IsHeaderParsed() const;
 
@@ -281,15 +273,9 @@
   // |out_public_key|. Returns false on failures.
   bool GetPublicKey(std::string* out_public_key);
 
-  // Creates a PayloadVerifier from the zip file containing certificates. If the
-  // path to the zip file doesn't exist, falls back to use the public key.
-  // Returns a tuple with the created PayloadVerifier and if we should perform
-  // the verification.
-  std::pair<std::unique_ptr<PayloadVerifier>, bool> CreatePayloadVerifier();
-
   // After install_plan_ is filled with partition names and sizes, initialize
   // metadata of partitions and map necessary devices before opening devices.
-  bool PreparePartitionsForUpdate();
+  bool InitPartitionMetadata();
 
   // Update Engine preference store.
   PrefsInterface* prefs_;
@@ -397,9 +383,6 @@
   // override with test keys.
   std::string public_key_path_{constants::kUpdatePayloadPublicKeyPath};
 
-  // The path to the zip file with X509 certificates.
-  std::string update_certificates_path_{constants::kUpdateCertificatesPath};
-
   // The number of bytes received so far, used for progress tracking.
   size_t total_bytes_received_{0};
 
diff --git a/payload_consumer/delta_performer_integration_test.cc b/payload_consumer/delta_performer_integration_test.cc
index a2ad77b..6b4771d 100644
--- a/payload_consumer/delta_performer_integration_test.cc
+++ b/payload_consumer/delta_performer_integration_test.cc
@@ -60,8 +60,6 @@
 extern const char* kUnittestPublicKeyPath;
 extern const char* kUnittestPrivateKey2Path;
 extern const char* kUnittestPublicKey2Path;
-extern const char* kUnittestPrivateKeyECPath;
-extern const char* kUnittestPublicKeyECPath;
 
 static const uint32_t kDefaultKernelSize = 4096;  // Something small for a test
 // clang-format off
@@ -109,7 +107,6 @@
   kSignatureGeneratedPlaceholder,  // Insert placeholder signatures, then real.
   kSignatureGeneratedPlaceholderMismatch,  // Insert a wrong sized placeholder.
   kSignatureGeneratedShell,  // Sign the generated payload through shell cmds.
-  kSignatureGeneratedShellECKey,      // Sign with a EC key through shell cmds.
   kSignatureGeneratedShellBadKey,     // Sign with a bad key through shell cmds.
   kSignatureGeneratedShellRotateCl1,  // Rotate key, test client v1
   kSignatureGeneratedShellRotateCl2,  // Rotate key, test client v2
@@ -167,127 +164,53 @@
   return true;
 }
 
-static bool InsertSignaturePlaceholder(size_t signature_size,
+static size_t GetSignatureSize(const string& private_key_path) {
+  const brillo::Blob data(1, 'x');
+  brillo::Blob hash;
+  EXPECT_TRUE(HashCalculator::RawHashOfData(data, &hash));
+  brillo::Blob signature;
+  EXPECT_TRUE(PayloadSigner::SignHash(hash, private_key_path, &signature));
+  return signature.size();
+}
+
+static bool InsertSignaturePlaceholder(int signature_size,
                                        const string& payload_path,
                                        uint64_t* out_metadata_size) {
   vector<brillo::Blob> signatures;
   signatures.push_back(brillo::Blob(signature_size, 0));
 
-  return PayloadSigner::AddSignatureToPayload(payload_path,
-                                              {signature_size},
-                                              signatures,
-                                              {},
-                                              payload_path,
-                                              out_metadata_size);
+  return PayloadSigner::AddSignatureToPayload(
+      payload_path, signatures, {}, payload_path, out_metadata_size);
 }
 
 static void SignGeneratedPayload(const string& payload_path,
                                  uint64_t* out_metadata_size) {
   string private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyPath);
-  size_t signature_size;
-  ASSERT_TRUE(PayloadSigner::GetMaximumSignatureSize(private_key_path,
-                                                     &signature_size));
+  int signature_size = GetSignatureSize(private_key_path);
   brillo::Blob hash;
   ASSERT_TRUE(PayloadSigner::HashPayloadForSigning(
       payload_path, {signature_size}, &hash, nullptr));
   brillo::Blob signature;
   ASSERT_TRUE(PayloadSigner::SignHash(hash, private_key_path, &signature));
-  ASSERT_TRUE(PayloadSigner::AddSignatureToPayload(payload_path,
-                                                   {signature_size},
-                                                   {signature},
-                                                   {},
-                                                   payload_path,
-                                                   out_metadata_size));
+  ASSERT_TRUE(PayloadSigner::AddSignatureToPayload(
+      payload_path, {signature}, {}, payload_path, out_metadata_size));
   EXPECT_TRUE(PayloadSigner::VerifySignedPayload(
       payload_path, GetBuildArtifactsPath(kUnittestPublicKeyPath)));
 }
 
-static void SignGeneratedShellPayloadWithKeys(
-    const string& payload_path,
-    const vector<string>& private_key_paths,
-    const string& public_key_path,
-    bool verification_success) {
-  vector<string> signature_size_strings;
-  for (const auto& key_path : private_key_paths) {
-    size_t signature_size;
-    ASSERT_TRUE(
-        PayloadSigner::GetMaximumSignatureSize(key_path, &signature_size));
-    signature_size_strings.push_back(base::StringPrintf("%zu", signature_size));
-  }
-  string signature_size_string = base::JoinString(signature_size_strings, ":");
-
-  test_utils::ScopedTempFile hash_file("hash.XXXXXX");
-  string delta_generator_path = GetBuildArtifactsPath("delta_generator");
-  ASSERT_EQ(0,
-            System(base::StringPrintf(
-                "%s -in_file=%s -signature_size=%s -out_hash_file=%s",
-                delta_generator_path.c_str(),
-                payload_path.c_str(),
-                signature_size_string.c_str(),
-                hash_file.path().c_str())));
-
-  // Sign the hash with all private keys.
-  vector<test_utils::ScopedTempFile> sig_files;
-  vector<string> sig_file_paths;
-  for (const auto& key_path : private_key_paths) {
-    brillo::Blob hash, signature;
-    ASSERT_TRUE(utils::ReadFile(hash_file.path(), &hash));
-    ASSERT_TRUE(PayloadSigner::SignHash(hash, key_path, &signature));
-
-    test_utils::ScopedTempFile sig_file("signature.XXXXXX");
-    ASSERT_TRUE(test_utils::WriteFileVector(sig_file.path(), signature));
-    sig_file_paths.push_back(sig_file.path());
-    sig_files.push_back(std::move(sig_file));
-  }
-  string sig_files_string = base::JoinString(sig_file_paths, ":");
-
-  // Add the signature to the payload.
-  ASSERT_EQ(0,
-            System(base::StringPrintf("%s --signature_size=%s -in_file=%s "
-                                      "-payload_signature_file=%s -out_file=%s",
-                                      delta_generator_path.c_str(),
-                                      signature_size_string.c_str(),
-                                      payload_path.c_str(),
-                                      sig_files_string.c_str(),
-                                      payload_path.c_str())));
-
-  int verify_result = System(base::StringPrintf("%s -in_file=%s -public_key=%s",
-                                                delta_generator_path.c_str(),
-                                                payload_path.c_str(),
-                                                public_key_path.c_str()));
-
-  if (verification_success) {
-    ASSERT_EQ(0, verify_result);
-  } else {
-    ASSERT_NE(0, verify_result);
-  }
-}
-
 static void SignGeneratedShellPayload(SignatureTest signature_test,
                                       const string& payload_path) {
-  vector<SignatureTest> supported_test = {
-      kSignatureGeneratedShell,
-      kSignatureGeneratedShellBadKey,
-      kSignatureGeneratedShellECKey,
-      kSignatureGeneratedShellRotateCl1,
-      kSignatureGeneratedShellRotateCl2,
-  };
-  ASSERT_TRUE(std::find(supported_test.begin(),
-                        supported_test.end(),
-                        signature_test) != supported_test.end());
-
-  string private_key_path;
+  string private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyPath);
   if (signature_test == kSignatureGeneratedShellBadKey) {
     ASSERT_TRUE(utils::MakeTempFile("key.XXXXXX", &private_key_path, nullptr));
-  } else if (signature_test == kSignatureGeneratedShellECKey) {
-    private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyECPath);
   } else {
-    private_key_path = GetBuildArtifactsPath(kUnittestPrivateKeyPath);
+    ASSERT_TRUE(signature_test == kSignatureGeneratedShell ||
+                signature_test == kSignatureGeneratedShellRotateCl1 ||
+                signature_test == kSignatureGeneratedShellRotateCl2);
   }
   ScopedPathUnlinker key_unlinker(private_key_path);
   key_unlinker.set_should_remove(signature_test ==
                                  kSignatureGeneratedShellBadKey);
-
   // Generates a new private key that will not match the public key.
   if (signature_test == kSignatureGeneratedShellBadKey) {
     LOG(INFO) << "Generating a mismatched private key.";
@@ -306,26 +229,64 @@
     fclose(fprikey);
     RSA_free(rsa);
   }
+  int signature_size = GetSignatureSize(private_key_path);
+  test_utils::ScopedTempFile hash_file("hash.XXXXXX");
+  string signature_size_string;
+  if (signature_test == kSignatureGeneratedShellRotateCl1 ||
+      signature_test == kSignatureGeneratedShellRotateCl2)
+    signature_size_string =
+        base::StringPrintf("%d:%d", signature_size, signature_size);
+  else
+    signature_size_string = base::StringPrintf("%d", signature_size);
+  string delta_generator_path = GetBuildArtifactsPath("delta_generator");
+  ASSERT_EQ(0,
+            System(base::StringPrintf(
+                "%s -in_file=%s -signature_size=%s -out_hash_file=%s",
+                delta_generator_path.c_str(),
+                payload_path.c_str(),
+                signature_size_string.c_str(),
+                hash_file.path().c_str())));
 
-  vector<string> private_key_paths = {private_key_path};
+  // Sign the hash
+  brillo::Blob hash, signature;
+  ASSERT_TRUE(utils::ReadFile(hash_file.path(), &hash));
+  ASSERT_TRUE(PayloadSigner::SignHash(hash, private_key_path, &signature));
+
+  test_utils::ScopedTempFile sig_file("signature.XXXXXX");
+  ASSERT_TRUE(test_utils::WriteFileVector(sig_file.path(), signature));
+  string sig_files = sig_file.path();
+
+  test_utils::ScopedTempFile sig_file2("signature.XXXXXX");
   if (signature_test == kSignatureGeneratedShellRotateCl1 ||
       signature_test == kSignatureGeneratedShellRotateCl2) {
-    private_key_paths.push_back(
-        GetBuildArtifactsPath(kUnittestPrivateKey2Path));
+    ASSERT_TRUE(PayloadSigner::SignHash(
+        hash, GetBuildArtifactsPath(kUnittestPrivateKey2Path), &signature));
+    ASSERT_TRUE(test_utils::WriteFileVector(sig_file2.path(), signature));
+    // Append second sig file to first path
+    sig_files += ":" + sig_file2.path();
   }
 
-  std::string public_key;
-  if (signature_test == kSignatureGeneratedShellRotateCl2) {
-    public_key = GetBuildArtifactsPath(kUnittestPublicKey2Path);
-  } else if (signature_test == kSignatureGeneratedShellECKey) {
-    public_key = GetBuildArtifactsPath(kUnittestPublicKeyECPath);
+  ASSERT_EQ(0,
+            System(base::StringPrintf(
+                "%s -in_file=%s -payload_signature_file=%s -out_file=%s",
+                delta_generator_path.c_str(),
+                payload_path.c_str(),
+                sig_files.c_str(),
+                payload_path.c_str())));
+  int verify_result = System(base::StringPrintf(
+      "%s -in_file=%s -public_key=%s -public_key_version=%d",
+      delta_generator_path.c_str(),
+      payload_path.c_str(),
+      (signature_test == kSignatureGeneratedShellRotateCl2
+           ? GetBuildArtifactsPath(kUnittestPublicKey2Path)
+           : GetBuildArtifactsPath(kUnittestPublicKeyPath))
+          .c_str(),
+      signature_test == kSignatureGeneratedShellRotateCl2 ? 2 : 1));
+  if (signature_test == kSignatureGeneratedShellBadKey) {
+    ASSERT_NE(0, verify_result);
   } else {
-    public_key = GetBuildArtifactsPath(kUnittestPublicKeyPath);
+    ASSERT_EQ(0, verify_result);
   }
-
-  bool verification_success = signature_test != kSignatureGeneratedShellBadKey;
-  SignGeneratedShellPayloadWithKeys(
-      payload_path, private_key_paths, public_key, verification_success);
 }
 
 static void GenerateDeltaFile(bool full_kernel,
@@ -570,9 +531,8 @@
 
   if (signature_test == kSignatureGeneratedPlaceholder ||
       signature_test == kSignatureGeneratedPlaceholderMismatch) {
-    size_t signature_size;
-    ASSERT_TRUE(PayloadSigner::GetMaximumSignatureSize(
-        GetBuildArtifactsPath(kUnittestPrivateKeyPath), &signature_size));
+    int signature_size =
+        GetSignatureSize(GetBuildArtifactsPath(kUnittestPrivateKeyPath));
     LOG(INFO) << "Inserting placeholder signature.";
     ASSERT_TRUE(InsertSignaturePlaceholder(
         signature_size, state->delta_path, &state->metadata_size));
@@ -595,7 +555,6 @@
     LOG(INFO) << "Signing payload.";
     SignGeneratedPayload(state->delta_path, &state->metadata_size);
   } else if (signature_test == kSignatureGeneratedShell ||
-             signature_test == kSignatureGeneratedShellECKey ||
              signature_test == kSignatureGeneratedShellBadKey ||
              signature_test == kSignatureGeneratedShellRotateCl1 ||
              signature_test == kSignatureGeneratedShellRotateCl2) {
@@ -638,15 +597,14 @@
       else
         EXPECT_EQ(1, sigs_message.signatures_size());
       const Signatures::Signature& signature = sigs_message.signatures(0);
+      EXPECT_EQ(1U, signature.version());
 
+      uint64_t expected_sig_data_length = 0;
       vector<string> key_paths{GetBuildArtifactsPath(kUnittestPrivateKeyPath)};
-      if (signature_test == kSignatureGeneratedShellECKey) {
-        key_paths = {GetBuildArtifactsPath(kUnittestPrivateKeyECPath)};
-      } else if (signature_test == kSignatureGeneratedShellRotateCl1 ||
-                 signature_test == kSignatureGeneratedShellRotateCl2) {
+      if (signature_test == kSignatureGeneratedShellRotateCl1 ||
+          signature_test == kSignatureGeneratedShellRotateCl2) {
         key_paths.push_back(GetBuildArtifactsPath(kUnittestPrivateKey2Path));
       }
-      uint64_t expected_sig_data_length = 0;
       EXPECT_TRUE(PayloadSigner::SignatureBlobLength(
           key_paths, &expected_sig_data_length));
       EXPECT_EQ(expected_sig_data_length, manifest.signatures_size());
@@ -759,9 +717,7 @@
   ASSERT_TRUE(PayloadSigner::GetMetadataSignature(
       state->delta.data(),
       state->metadata_size,
-      (signature_test == kSignatureGeneratedShellECKey)
-          ? GetBuildArtifactsPath(kUnittestPrivateKeyECPath)
-          : GetBuildArtifactsPath(kUnittestPrivateKeyPath),
+      GetBuildArtifactsPath(kUnittestPrivateKeyPath),
       &install_plan->payloads[0].metadata_signature));
   EXPECT_FALSE(install_plan->payloads[0].metadata_signature.empty());
 
@@ -772,12 +728,9 @@
                                   install_plan,
                                   &install_plan->payloads[0],
                                   false /* interactive */);
-  string public_key_path = signature_test == kSignatureGeneratedShellECKey
-                               ? GetBuildArtifactsPath(kUnittestPublicKeyECPath)
-                               : GetBuildArtifactsPath(kUnittestPublicKeyPath);
+  string public_key_path = GetBuildArtifactsPath(kUnittestPublicKeyPath);
   EXPECT_TRUE(utils::FileExists(public_key_path.c_str()));
   (*performer)->set_public_key_path(public_key_path);
-  (*performer)->set_update_certificates_path("");
 
   EXPECT_EQ(static_cast<off_t>(state->image_size),
             HashCalculator::RawHashOfFile(
@@ -1107,17 +1060,6 @@
 }
 
 TEST(DeltaPerformerIntegrationTest,
-     RunAsRootSmallImageSignGeneratedShellECKeyTest) {
-  DoSmallImageTest(false,
-                   false,
-                   false,
-                   -1,
-                   kSignatureGeneratedShellECKey,
-                   false,
-                   kInPlaceMinorPayloadVersion);
-}
-
-TEST(DeltaPerformerIntegrationTest,
      RunAsRootSmallImageSignGeneratedShellBadKeyTest) {
   DoSmallImageTest(false,
                    false,
diff --git a/payload_consumer/delta_performer_unittest.cc b/payload_consumer/delta_performer_unittest.cc
index e9022ba..b7a38cc 100644
--- a/payload_consumer/delta_performer_unittest.cc
+++ b/payload_consumer/delta_performer_unittest.cc
@@ -159,11 +159,6 @@
     install_plan_.target_slot = 1;
     EXPECT_CALL(mock_delegate_, ShouldCancel(_))
         .WillRepeatedly(testing::Return(false));
-    performer_.set_update_certificates_path("");
-    // Set the public key corresponding to the unittest private key.
-    string public_key_path = GetBuildArtifactsPath(kUnittestPublicKeyPath);
-    EXPECT_TRUE(utils::FileExists(public_key_path.c_str()));
-    performer_.set_public_key_path(public_key_path);
   }
 
   // Test helper placed where it can easily be friended from DeltaPerformer.
@@ -393,6 +388,12 @@
       expected_error = ErrorCode::kSuccess;
     }
 
+    // Use the public key corresponding to the private key used above to
+    // sign the metadata.
+    string public_key_path = GetBuildArtifactsPath(kUnittestPublicKeyPath);
+    EXPECT_TRUE(utils::FileExists(public_key_path.c_str()));
+    performer_.set_public_key_path(public_key_path);
+
     // Init actual_error with an invalid value so that we make sure
     // ParsePayloadMetadata properly populates it in all cases.
     actual_error = ErrorCode::kUmaReportedMax;
@@ -919,6 +920,7 @@
   brillo::Blob payload_data = GeneratePayload(
       {}, {}, true, kBrilloMajorPayloadVersion, kSourceMinorPayloadVersion);
   install_plan_.hash_checks_mandatory = true;
+  performer_.set_public_key_path(GetBuildArtifactsPath(kUnittestPublicKeyPath));
   ErrorCode error;
   EXPECT_EQ(MetadataParseResult::kSuccess,
             performer_.ParsePayloadMetadata(payload_data, &error));
diff --git a/payload_consumer/install_plan.cc b/payload_consumer/install_plan.cc
index 766b27c..2e7b6d4 100644
--- a/payload_consumer/install_plan.cc
+++ b/payload_consumer/install_plan.cc
@@ -19,7 +19,6 @@
 #include <base/format_macros.h>
 #include <base/logging.h>
 #include <base/strings/string_number_conversions.h>
-#include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
 
 #include "update_engine/common/utils.h"
@@ -81,18 +80,11 @@
         base::StringPrintf(", system_version: %s", system_version.c_str());
   }
 
-  string url_str = download_url;
-  if (base::StartsWith(
-          url_str, "fd://", base::CompareCase::INSENSITIVE_ASCII)) {
-    int fd = std::stoi(url_str.substr(strlen("fd://")));
-    url_str = utils::GetFilePath(fd);
-  }
-
   LOG(INFO) << "InstallPlan: " << (is_resume ? "resume" : "new_update")
             << version_str
             << ", source_slot: " << BootControlInterface::SlotName(source_slot)
             << ", target_slot: " << BootControlInterface::SlotName(target_slot)
-            << ", url: " << url_str << payloads_str << partitions_str
+            << ", url: " << download_url << payloads_str << partitions_str
             << ", hash_checks_mandatory: "
             << utils::ToString(hash_checks_mandatory)
             << ", powerwash_required: " << utils::ToString(powerwash_required)
diff --git a/payload_consumer/payload_metadata.cc b/payload_consumer/payload_metadata.cc
index 0952646..3739767 100644
--- a/payload_consumer/payload_metadata.cc
+++ b/payload_consumer/payload_metadata.cc
@@ -159,7 +159,7 @@
 ErrorCode PayloadMetadata::ValidateMetadataSignature(
     const brillo::Blob& payload,
     const string& metadata_signature,
-    const PayloadVerifier& payload_verifier) const {
+    const string& pem_public_key) const {
   if (payload.size() < metadata_size_ + metadata_signature_size_)
     return ErrorCode::kDownloadMetadataSignatureError;
 
@@ -202,18 +202,31 @@
   }
 
   if (!metadata_signature_blob.empty()) {
-    brillo::Blob decrypted_signature;
-    if (!payload_verifier.VerifyRawSignature(
-            metadata_signature_blob, metadata_hash, &decrypted_signature)) {
-      LOG(ERROR) << "Manifest hash verification failed. Decrypted hash = ";
-      utils::HexDumpVector(decrypted_signature);
-      LOG(ERROR) << "Calculated hash before padding = ";
-      utils::HexDumpVector(metadata_hash);
+    brillo::Blob expected_metadata_hash;
+    if (!PayloadVerifier::GetRawHashFromSignature(
+            metadata_signature_blob, pem_public_key, &expected_metadata_hash)) {
+      LOG(ERROR) << "Unable to compute expected hash from metadata signature";
+      return ErrorCode::kDownloadMetadataSignatureError;
+    }
+
+    brillo::Blob padded_metadata_hash = metadata_hash;
+    if (!PayloadVerifier::PadRSASHA256Hash(&padded_metadata_hash,
+                                           expected_metadata_hash.size())) {
+      LOG(ERROR) << "Failed to pad the SHA256 hash to "
+                 << expected_metadata_hash.size() << " bytes.";
+      return ErrorCode::kDownloadMetadataSignatureVerificationError;
+    }
+
+    if (padded_metadata_hash != expected_metadata_hash) {
+      LOG(ERROR) << "Manifest hash verification failed. Expected hash = ";
+      utils::HexDumpVector(expected_metadata_hash);
+      LOG(ERROR) << "Calculated hash = ";
+      utils::HexDumpVector(padded_metadata_hash);
       return ErrorCode::kDownloadMetadataSignatureMismatch;
     }
   } else {
-    if (!payload_verifier.VerifySignature(metadata_signature_protobuf,
-                                          metadata_hash)) {
+    if (!PayloadVerifier::VerifySignature(
+            metadata_signature_protobuf, pem_public_key, metadata_hash)) {
       LOG(ERROR) << "Manifest hash verification failed.";
       return ErrorCode::kDownloadMetadataSignatureMismatch;
     }
diff --git a/payload_consumer/payload_metadata.h b/payload_consumer/payload_metadata.h
index 75ef8f9..1b4c5c8 100644
--- a/payload_consumer/payload_metadata.h
+++ b/payload_consumer/payload_metadata.h
@@ -27,7 +27,6 @@
 
 #include "update_engine/common/error_code.h"
 #include "update_engine/common/platform_constants.h"
-#include "update_engine/payload_consumer/payload_verifier.h"
 #include "update_engine/update_metadata.pb.h"
 
 namespace chromeos_update_engine {
@@ -66,10 +65,9 @@
   // metadata is parsed so that a man-in-the-middle attack on the SSL connection
   // to the payload server doesn't exploit any vulnerability in the code that
   // parses the protocol buffer.
-  ErrorCode ValidateMetadataSignature(
-      const brillo::Blob& payload,
-      const std::string& metadata_signature,
-      const PayloadVerifier& payload_verifier) const;
+  ErrorCode ValidateMetadataSignature(const brillo::Blob& payload,
+                                      const std::string& metadata_signature,
+                                      const std::string& pem_public_key) const;
 
   // Returns the major payload version. If the version was not yet parsed,
   // returns zero.
diff --git a/payload_consumer/payload_verifier.cc b/payload_consumer/payload_verifier.cc
index 24e337e..3a3ccbf 100644
--- a/payload_consumer/payload_verifier.cc
+++ b/payload_consumer/payload_verifier.cc
@@ -25,7 +25,6 @@
 #include "update_engine/common/constants.h"
 #include "update_engine/common/hash_calculator.h"
 #include "update_engine/common/utils.h"
-#include "update_engine/payload_consumer/certificate_parser_interface.h"
 #include "update_engine/update_metadata.pb.h"
 
 using std::string;
@@ -52,52 +51,9 @@
 
 }  // namespace
 
-std::unique_ptr<PayloadVerifier> PayloadVerifier::CreateInstance(
-    const std::string& pem_public_key) {
-  std::unique_ptr<BIO, decltype(&BIO_free)> bp(
-      BIO_new_mem_buf(pem_public_key.data(), pem_public_key.size()), BIO_free);
-  if (!bp) {
-    LOG(ERROR) << "Failed to read " << pem_public_key << " into buffer.";
-    return nullptr;
-  }
-
-  auto pub_key = std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>(
-      PEM_read_bio_PUBKEY(bp.get(), nullptr, nullptr, nullptr), EVP_PKEY_free);
-  if (!pub_key) {
-    LOG(ERROR) << "Failed to parse the public key in: " << pem_public_key;
-    return nullptr;
-  }
-
-  std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>> keys;
-  keys.emplace_back(std::move(pub_key));
-  return std::unique_ptr<PayloadVerifier>(new PayloadVerifier(std::move(keys)));
-}
-
-std::unique_ptr<PayloadVerifier> PayloadVerifier::CreateInstanceFromZipPath(
-    const std::string& certificate_zip_path) {
-  auto parser = CreateCertificateParser();
-  if (!parser) {
-    LOG(ERROR) << "Failed to create certificate parser from "
-               << certificate_zip_path;
-    return nullptr;
-  }
-
-  std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>> public_keys;
-  if (!parser->ReadPublicKeysFromCertificates(certificate_zip_path,
-                                              &public_keys) ||
-      public_keys.empty()) {
-    LOG(ERROR) << "Failed to parse public keys in: " << certificate_zip_path;
-    return nullptr;
-  }
-
-  return std::unique_ptr<PayloadVerifier>(
-      new PayloadVerifier(std::move(public_keys)));
-}
-
-bool PayloadVerifier::VerifySignature(
-    const string& signature_proto, const brillo::Blob& sha256_hash_data) const {
-  TEST_AND_RETURN_FALSE(!public_keys_.empty());
-
+bool PayloadVerifier::VerifySignature(const string& signature_proto,
+                                      const string& pem_public_key,
+                                      const brillo::Blob& sha256_hash_data) {
   Signatures signatures;
   LOG(INFO) << "signature blob size = " << signature_proto.size();
   TEST_AND_RETURN_FALSE(signatures.ParseFromString(signature_proto));
@@ -111,104 +67,48 @@
   // Tries every signature in the signature blob.
   for (int i = 0; i < signatures.signatures_size(); i++) {
     const Signatures::Signature& signature = signatures.signatures(i);
-    brillo::Blob sig_data;
-    if (signature.has_unpadded_signature_size()) {
-      TEST_AND_RETURN_FALSE(signature.unpadded_signature_size() <=
-                            signature.data().size());
-      LOG(INFO) << "Truncating the signature to its unpadded size: "
-                << signature.unpadded_signature_size() << ".";
-      sig_data.assign(
-          signature.data().begin(),
-          signature.data().begin() + signature.unpadded_signature_size());
-    } else {
-      sig_data.assign(signature.data().begin(), signature.data().end());
-    }
-
+    brillo::Blob sig_data(signature.data().begin(), signature.data().end());
     brillo::Blob sig_hash_data;
-    if (VerifyRawSignature(sig_data, sha256_hash_data, &sig_hash_data)) {
+    if (!GetRawHashFromSignature(sig_data, pem_public_key, &sig_hash_data))
+      continue;
+
+    brillo::Blob padded_hash_data = sha256_hash_data;
+    if (PadRSASHA256Hash(&padded_hash_data, sig_hash_data.size()) &&
+        padded_hash_data == sig_hash_data) {
       LOG(INFO) << "Verified correct signature " << i + 1 << " out of "
                 << signatures.signatures_size() << " signatures.";
       return true;
     }
-    if (!sig_hash_data.empty()) {
-      tested_hashes.push_back(sig_hash_data);
-    }
+    tested_hashes.push_back(sig_hash_data);
   }
   LOG(ERROR) << "None of the " << signatures.signatures_size()
              << " signatures is correct. Expected hash before padding:";
   utils::HexDumpVector(sha256_hash_data);
-  LOG(ERROR) << "But found RSA decrypted hashes:";
+  LOG(ERROR) << "But found decrypted hashes:";
   for (const auto& sig_hash_data : tested_hashes) {
     utils::HexDumpVector(sig_hash_data);
   }
   return false;
 }
 
-bool PayloadVerifier::VerifyRawSignature(
-    const brillo::Blob& sig_data,
-    const brillo::Blob& sha256_hash_data,
-    brillo::Blob* decrypted_sig_data) const {
-  TEST_AND_RETURN_FALSE(!public_keys_.empty());
-
-  for (const auto& public_key : public_keys_) {
-    int key_type = EVP_PKEY_id(public_key.get());
-    if (key_type == EVP_PKEY_RSA) {
-      brillo::Blob sig_hash_data;
-      if (!GetRawHashFromSignature(
-              sig_data, public_key.get(), &sig_hash_data)) {
-        LOG(WARNING)
-            << "Failed to get the raw hash with RSA key. Trying other keys.";
-        continue;
-      }
-
-      if (decrypted_sig_data != nullptr) {
-        *decrypted_sig_data = sig_hash_data;
-      }
-
-      brillo::Blob padded_hash_data = sha256_hash_data;
-      TEST_AND_RETURN_FALSE(
-          PadRSASHA256Hash(&padded_hash_data, sig_hash_data.size()));
-
-      if (padded_hash_data == sig_hash_data) {
-        return true;
-      }
-    }
-
-    if (key_type == EVP_PKEY_EC) {
-      EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(public_key.get());
-      TEST_AND_RETURN_FALSE(ec_key != nullptr);
-      if (ECDSA_verify(0,
-                       sha256_hash_data.data(),
-                       sha256_hash_data.size(),
-                       sig_data.data(),
-                       sig_data.size(),
-                       ec_key) == 1) {
-        return true;
-      }
-    }
-
-    LOG(ERROR) << "Unsupported key type " << key_type;
-    return false;
-  }
-  LOG(INFO) << "Failed to verify the signature with " << public_keys_.size()
-            << " keys.";
-  return false;
-}
-
-bool PayloadVerifier::GetRawHashFromSignature(
-    const brillo::Blob& sig_data,
-    const EVP_PKEY* public_key,
-    brillo::Blob* out_hash_data) const {
+bool PayloadVerifier::GetRawHashFromSignature(const brillo::Blob& sig_data,
+                                              const string& pem_public_key,
+                                              brillo::Blob* out_hash_data) {
   // The code below executes the equivalent of:
   //
-  // openssl rsautl -verify -pubin -inkey <(echo pem_public_key)
+  // openssl rsautl -verify -pubin -inkey <(echo |pem_public_key|)
   //   -in |sig_data| -out |out_hash_data|
-  RSA* rsa = EVP_PKEY_get0_RSA(public_key);
+
+  BIO* bp = BIO_new_mem_buf(pem_public_key.data(), pem_public_key.size());
+  char dummy_password[] = {' ', 0};  // Ensure no password is read from stdin.
+  RSA* rsa = PEM_read_bio_RSA_PUBKEY(bp, nullptr, nullptr, dummy_password);
+  BIO_free(bp);
 
   TEST_AND_RETURN_FALSE(rsa != nullptr);
   unsigned int keysize = RSA_size(rsa);
   if (sig_data.size() > 2 * keysize) {
     LOG(ERROR) << "Signature size is too big for public key size.";
+    RSA_free(rsa);
     return false;
   }
 
@@ -216,6 +116,7 @@
   brillo::Blob hash_data(keysize);
   int decrypt_size = RSA_public_decrypt(
       sig_data.size(), sig_data.data(), hash_data.data(), rsa, RSA_NO_PADDING);
+  RSA_free(rsa);
   TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
                         decrypt_size <= static_cast<int>(hash_data.size()));
   hash_data.resize(decrypt_size);
diff --git a/payload_consumer/payload_verifier.h b/payload_consumer/payload_verifier.h
index bc5231f..af8e05f 100644
--- a/payload_consumer/payload_verifier.h
+++ b/payload_consumer/payload_verifier.h
@@ -17,24 +17,38 @@
 #ifndef UPDATE_ENGINE_PAYLOAD_CONSUMER_PAYLOAD_VERIFIER_H_
 #define UPDATE_ENGINE_PAYLOAD_CONSUMER_PAYLOAD_VERIFIER_H_
 
-#include <memory>
 #include <string>
-#include <utility>
-#include <vector>
 
+#include <base/macros.h>
 #include <brillo/secure_blob.h>
-#include <openssl/evp.h>
 
 #include "update_engine/update_metadata.pb.h"
 
-// This class holds the public keys and implements methods used for payload
-// signature verification. See payload_generator/payload_signer.h for payload
-// signing.
+// This class encapsulates methods used for payload signature verification.
+// See payload_generator/payload_signer.h for payload signing.
 
 namespace chromeos_update_engine {
 
 class PayloadVerifier {
  public:
+  // Interprets |signature_proto| as a protocol buffer containing the Signatures
+  // message and decrypts each signature data using the |pem_public_key|.
+  // |pem_public_key| should be a PEM format RSA public key data.
+  // Pads the 32 bytes |sha256_hash_data| to 256 or 512 bytes according to the
+  // PKCS#1 v1.5 standard; and returns whether *any* of the decrypted hashes
+  // matches the padded hash data. In case of any error parsing the signatures
+  // or the public key, returns false.
+  static bool VerifySignature(const std::string& signature_proto,
+                              const std::string& pem_public_key,
+                              const brillo::Blob& sha256_hash_data);
+
+  // Decrypts |sig_data| with the given |pem_public_key| and populates
+  // |out_hash_data| with the decoded raw hash. |pem_public_key| should be a PEM
+  // format RSA public key data. Returns true if successful, false otherwise.
+  static bool GetRawHashFromSignature(const brillo::Blob& sig_data,
+                                      const std::string& pem_public_key,
+                                      brillo::Blob* out_hash_data);
+
   // Pads a SHA256 hash so that it may be encrypted/signed with RSA2048 or
   // RSA4096 using the PKCS#1 v1.5 scheme.
   // hash should be a pointer to vector of exactly 256 bits. |rsa_size| must be
@@ -43,46 +57,9 @@
   // Returns true on success, false otherwise.
   static bool PadRSASHA256Hash(brillo::Blob* hash, size_t rsa_size);
 
-  // Parses the input as a PEM encoded public string. And creates a
-  // PayloadVerifier with that public key for signature verification.
-  static std::unique_ptr<PayloadVerifier> CreateInstance(
-      const std::string& pem_public_key);
-
-  // Extracts the public keys from the certificates contained in the input
-  // zip file. And creates a PayloadVerifier with these public keys.
-  static std::unique_ptr<PayloadVerifier> CreateInstanceFromZipPath(
-      const std::string& certificate_zip_path);
-
-  // Interprets |signature_proto| as a protocol buffer containing the
-  // |Signatures| message and decrypts each signature data using the stored
-  // public key. Pads the 32 bytes |sha256_hash_data| to 256 or 512 bytes
-  // according to the PKCS#1 v1.5 standard; and returns whether *any* of the
-  // decrypted hashes matches the padded hash data. In case of any error parsing
-  // the signatures, returns false.
-  bool VerifySignature(const std::string& signature_proto,
-                       const brillo::Blob& sha256_hash_data) const;
-
-  // Verifies if |sig_data| is a raw signature of the hash |sha256_hash_data|.
-  // If PayloadVerifier is using RSA as the public key, further puts the
-  // decrypted data of |sig_data| into |decrypted_sig_data|.
-  bool VerifyRawSignature(const brillo::Blob& sig_data,
-                          const brillo::Blob& sha256_hash_data,
-                          brillo::Blob* decrypted_sig_data) const;
-
  private:
-  explicit PayloadVerifier(
-      std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>>&&
-          public_keys)
-      : public_keys_(std::move(public_keys)) {}
-
-  // Decrypts |sig_data| with the given |public_key| and populates
-  // |out_hash_data| with the decoded raw hash. Returns true if successful,
-  // false otherwise.
-  bool GetRawHashFromSignature(const brillo::Blob& sig_data,
-                               const EVP_PKEY* public_key,
-                               brillo::Blob* out_hash_data) const;
-
-  std::vector<std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>> public_keys_;
+  // This should never be constructed
+  DISALLOW_IMPLICIT_CONSTRUCTORS(PayloadVerifier);
 };
 
 }  // namespace chromeos_update_engine
diff --git a/payload_generator/deflate_utils.cc b/payload_generator/deflate_utils.cc
index 01402dd..a7a0503 100644
--- a/payload_generator/deflate_utils.cc
+++ b/payload_generator/deflate_utils.cc
@@ -74,15 +74,6 @@
   return false;
 }
 
-bool IsRegularFile(const FilesystemInterface::File& file) {
-  // If inode is 0, then stat information is invalid for some psuedo files
-  if (file.file_stat.st_ino != 0 &&
-      (file.file_stat.st_mode & S_IFMT) == S_IFREG) {
-    return true;
-  }
-  return false;
-}
-
 // Realigns subfiles |files| of a splitted file |file| into its correct
 // positions. This can be used for squashfs, zip, apk, etc.
 bool RealignSplittedFiles(const FilesystemInterface::File& file,
@@ -274,9 +265,7 @@
   result_files->reserve(tmp_files.size());
 
   for (auto& file : tmp_files) {
-    auto is_regular_file = IsRegularFile(file);
-
-    if (is_regular_file && IsSquashfsImage(part.path, file)) {
+    if (IsSquashfsImage(part.path, file)) {
       // Read the image into a file.
       base::FilePath path;
       TEST_AND_RETURN_FALSE(base::CreateTemporaryFile(&path));
@@ -306,7 +295,7 @@
       }
     }
 
-    if (is_regular_file && extract_deflates) {
+    if (extract_deflates) {
       // Search for deflates if the file is in zip or gzip format.
       // .zvoice files may eventually move out of rootfs. If that happens,
       // remove ".zvoice" (crbug.com/782918).
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index f035ff1..3cb891f 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -54,15 +54,18 @@
 namespace {
 
 void ParseSignatureSizes(const string& signature_sizes_flag,
-                         vector<size_t>* signature_sizes) {
+                         vector<int>* signature_sizes) {
   signature_sizes->clear();
   vector<string> split_strings = base::SplitString(
       signature_sizes_flag, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
   for (const string& str : split_strings) {
-    size_t size = 0;
-    bool parsing_successful = base::StringToSizeT(str, &size);
+    int size = 0;
+    bool parsing_successful = base::StringToInt(str, &size);
     LOG_IF(FATAL, !parsing_successful) << "Invalid signature size: " << str;
 
+    LOG_IF(FATAL, size != 256 && size != 512)
+        << "Only signature sizes of 256 or 512 bytes are supported.";
+
     signature_sizes->push_back(size);
   }
 }
@@ -99,7 +102,7 @@
   return true;
 }
 
-void CalculateHashForSigning(const vector<size_t>& sizes,
+void CalculateHashForSigning(const vector<int>& sizes,
                              const string& out_hash_file,
                              const string& out_metadata_hash_file,
                              const string& in_file) {
@@ -135,7 +138,6 @@
 
 void SignPayload(const string& in_file,
                  const string& out_file,
-                 const vector<size_t>& signature_sizes,
                  const string& payload_signature_file,
                  const string& metadata_signature_file,
                  const string& out_metadata_size_file) {
@@ -149,7 +151,6 @@
   SignatureFileFlagToBlobs(metadata_signature_file, &metadata_signatures);
   uint64_t final_metadata_size;
   CHECK(PayloadSigner::AddSignatureToPayload(in_file,
-                                             signature_sizes,
                                              payload_signatures,
                                              metadata_signatures,
                                              out_file,
@@ -420,13 +421,6 @@
                 "",
                 "An info file specifying dynamic partition metadata. "
                 "Only allowed in major version 2 or newer.");
-  DEFINE_bool(disable_fec_computation,
-              false,
-              "Disables the fec data computation on device.");
-  DEFINE_string(
-      out_maximum_signature_size_file,
-      "",
-      "Path to the output maximum signature size given a private key.");
 
   brillo::FlagHelper::Init(
       argc,
@@ -448,34 +442,8 @@
   // Initialize the Xz compressor.
   XzCompressInit();
 
-  if (!FLAGS_out_maximum_signature_size_file.empty()) {
-    LOG_IF(FATAL, FLAGS_private_key.empty())
-        << "Private key is not provided when calculating the maximum signature "
-           "size.";
-
-    size_t maximum_signature_size;
-    if (!PayloadSigner::GetMaximumSignatureSize(FLAGS_private_key,
-                                                &maximum_signature_size)) {
-      LOG(ERROR) << "Failed to get the maximum signature size of private key: "
-                 << FLAGS_private_key;
-      return 1;
-    }
-    // Write the size string to output file.
-    string signature_size_string = std::to_string(maximum_signature_size);
-    if (!utils::WriteFile(FLAGS_out_maximum_signature_size_file.c_str(),
-                          signature_size_string.c_str(),
-                          signature_size_string.size())) {
-      PLOG(ERROR) << "Failed to write the maximum signature size to "
-                  << FLAGS_out_maximum_signature_size_file << ".";
-      return 1;
-    }
-    return 0;
-  }
-
-  vector<size_t> signature_sizes;
-  if (!FLAGS_signature_size.empty()) {
-    ParseSignatureSizes(FLAGS_signature_size, &signature_sizes);
-  }
+  vector<int> signature_sizes;
+  ParseSignatureSizes(FLAGS_signature_size, &signature_sizes);
 
   if (!FLAGS_out_hash_file.empty() || !FLAGS_out_metadata_hash_file.empty()) {
     CHECK(FLAGS_out_metadata_size_file.empty());
@@ -488,7 +456,6 @@
   if (!FLAGS_payload_signature_file.empty()) {
     SignPayload(FLAGS_in_file,
                 FLAGS_out_file,
-                signature_sizes,
                 FLAGS_payload_signature_file,
                 FLAGS_metadata_signature_file,
                 FLAGS_out_metadata_size_file);
@@ -560,8 +527,6 @@
         << "Partition name can't be empty, see --partition_names.";
     payload_config.target.partitions.emplace_back(partition_names[i]);
     payload_config.target.partitions.back().path = new_partitions[i];
-    payload_config.target.partitions.back().disable_fec_computation =
-        FLAGS_disable_fec_computation;
     if (i < new_mapfiles.size())
       payload_config.target.partitions.back().mapfile_path = new_mapfiles[i];
   }
diff --git a/payload_generator/payload_generation_config.cc b/payload_generator/payload_generation_config.cc
index 88cca30..648fe8b 100644
--- a/payload_generator/payload_generation_config.cc
+++ b/payload_generator/payload_generation_config.cc
@@ -141,34 +141,25 @@
   for (const auto& group_name : group_names) {
     DynamicPartitionGroup* group = metadata->add_groups();
     group->set_name(group_name);
-    if (!store.GetString("super_" + group_name + "_group_size", &buf) &&
-        !store.GetString(group_name + "_size", &buf)) {
-      LOG(ERROR) << "Missing super_" << group_name + "_group_size or "
-                 << group_name << "_size.";
+    if (!store.GetString(group_name + "_size", &buf)) {
+      LOG(ERROR) << "Missing " << group_name + "_size.";
       return false;
     }
 
     uint64_t max_size;
     if (!base::StringToUint64(buf, &max_size)) {
-      LOG(ERROR) << "Group size for " << group_name << " = " << buf
-                 << " is not an integer.";
+      LOG(ERROR) << group_name << "_size=" << buf << " is not an integer.";
       return false;
     }
     group->set_size(max_size);
 
-    if (store.GetString("super_" + group_name + "_partition_list", &buf) ||
-        store.GetString(group_name + "_partition_list", &buf)) {
+    if (store.GetString(group_name + "_partition_list", &buf)) {
       auto partition_names = brillo::string_utils::Split(buf, " ");
       for (const auto& partition_name : partition_names) {
         group->add_partition_names()->assign(partition_name);
       }
     }
   }
-
-  bool snapshot_enabled = false;
-  store.GetBoolean("virtual_ab", &snapshot_enabled);
-  metadata->set_snapshot_enabled(snapshot_enabled);
-
   dynamic_partition_metadata = std::move(metadata);
   return true;
 }
diff --git a/payload_generator/payload_generation_config.h b/payload_generator/payload_generation_config.h
index e90edde..584ac7b 100644
--- a/payload_generator/payload_generation_config.h
+++ b/payload_generator/payload_generation_config.h
@@ -116,9 +116,6 @@
 
   PostInstallConfig postinstall;
   VerityConfig verity;
-
-  // Enables the on device fec data computation by default.
-  bool disable_fec_computation = false;
 };
 
 // The ImageConfig struct describes a pair of binaries kernel and rootfs and the
diff --git a/payload_generator/payload_generation_config_android.cc b/payload_generator/payload_generation_config_android.cc
index d950092..90c053f 100644
--- a/payload_generator/payload_generation_config_android.cc
+++ b/payload_generator/payload_generation_config_android.cc
@@ -63,13 +63,11 @@
   part->verity.hash_tree_extent = ExtentForBytes(
       hashtree.hash_block_size, hashtree.tree_offset, hashtree.tree_size);
 
-  if (!part->disable_fec_computation) {
-    part->verity.fec_data_extent =
-        ExtentForBytes(hashtree.data_block_size, 0, hashtree.fec_offset);
-    part->verity.fec_extent = ExtentForBytes(
-        hashtree.data_block_size, hashtree.fec_offset, hashtree.fec_size);
-    part->verity.fec_roots = hashtree.fec_num_roots;
-  }
+  part->verity.fec_data_extent =
+      ExtentForBytes(hashtree.data_block_size, 0, hashtree.fec_offset);
+  part->verity.fec_extent = ExtentForBytes(
+      hashtree.data_block_size, hashtree.fec_offset, hashtree.fec_size);
+  part->verity.fec_roots = hashtree.fec_num_roots;
   return true;
 }
 
@@ -207,8 +205,7 @@
               ExtentForRange(hash_start_block, tree_size / block_size);
         }
         fec_ecc_metadata ecc_data;
-        if (!part.disable_fec_computation && fh.get_ecc_metadata(ecc_data) &&
-            ecc_data.valid) {
+        if (fh.get_ecc_metadata(ecc_data) && ecc_data.valid) {
           TEST_AND_RETURN_FALSE(block_size == FEC_BLOCKSIZE);
           part.verity.fec_data_extent = ExtentForRange(0, ecc_data.blocks);
           part.verity.fec_extent =
diff --git a/payload_generator/payload_generation_config_android_unittest.cc b/payload_generator/payload_generation_config_android_unittest.cc
index 44eaf55..53378c2 100644
--- a/payload_generator/payload_generation_config_android_unittest.cc
+++ b/payload_generator/payload_generation_config_android_unittest.cc
@@ -160,24 +160,6 @@
   EXPECT_EQ(2u, verity.fec_roots);
 }
 
-TEST_F(PayloadGenerationConfigAndroidTest, LoadVerityConfigDisableFecTest) {
-  brillo::Blob part = GetAVBPartition();
-  test_utils::WriteFileVector(temp_file_.path(), part);
-  image_config_.partitions[0].disable_fec_computation = true;
-  EXPECT_TRUE(image_config_.LoadImageSize());
-  EXPECT_TRUE(image_config_.partitions[0].OpenFilesystem());
-  EXPECT_TRUE(image_config_.LoadVerityConfig());
-  const VerityConfig& verity = image_config_.partitions[0].verity;
-  EXPECT_FALSE(verity.IsEmpty());
-  EXPECT_EQ(ExtentForRange(0, 2), verity.hash_tree_data_extent);
-  EXPECT_EQ(ExtentForRange(2, 1), verity.hash_tree_extent);
-  EXPECT_EQ("sha1", verity.hash_tree_algorithm);
-  brillo::Blob salt(kHashTreeSalt, std::end(kHashTreeSalt));
-  EXPECT_EQ(salt, verity.hash_tree_salt);
-  EXPECT_EQ(0u, verity.fec_data_extent.num_blocks());
-  EXPECT_EQ(0u, verity.fec_extent.num_blocks());
-}
-
 TEST_F(PayloadGenerationConfigAndroidTest,
        LoadVerityConfigInvalidHashTreeTest) {
   brillo::Blob part = GetAVBPartition();
diff --git a/payload_generator/payload_generation_config_unittest.cc b/payload_generator/payload_generation_config_unittest.cc
index aca9655..70a3df3 100644
--- a/payload_generator/payload_generation_config_unittest.cc
+++ b/payload_generator/payload_generation_config_unittest.cc
@@ -59,7 +59,7 @@
   ASSERT_TRUE(
       store.LoadFromString("super_partition_groups=group_a group_b\n"
                            "group_a_size=3221225472\n"
-                           "group_a_partition_list=system system_ext\n"
+                           "group_a_partition_list=system product_services\n"
                            "group_b_size=2147483648\n"
                            "group_b_partition_list=vendor\n"));
   EXPECT_TRUE(image_config.LoadDynamicPartitionMetadata(store));
@@ -72,7 +72,7 @@
   EXPECT_EQ(3221225472u, group_a.size());
   ASSERT_EQ(2, group_a.partition_names_size());
   EXPECT_EQ("system", group_a.partition_names(0));
-  EXPECT_EQ("system_ext", group_a.partition_names(1));
+  EXPECT_EQ("product_services", group_a.partition_names(1));
 
   const auto& group_b = image_config.dynamic_partition_metadata->groups(1);
   EXPECT_EQ("group_b", group_b.name());
@@ -108,17 +108,17 @@
 
   PartitionConfig system("system");
   system.size = 2147483648u;
-  PartitionConfig system_ext("system_ext");
-  system_ext.size = 1073741824u;
+  PartitionConfig product_services("product_services");
+  product_services.size = 1073741824u;
 
   image_config.partitions.push_back(std::move(system));
-  image_config.partitions.push_back(std::move(system_ext));
+  image_config.partitions.push_back(std::move(product_services));
 
   brillo::KeyValueStore store;
   ASSERT_TRUE(
       store.LoadFromString("super_partition_groups=foo\n"
                            "foo_size=3221225472\n"
-                           "foo_partition_list=system system_ext\n"));
+                           "foo_partition_list=system product_services\n"));
   EXPECT_TRUE(image_config.LoadDynamicPartitionMetadata(store));
   EXPECT_NE(nullptr, image_config.dynamic_partition_metadata);
 
diff --git a/payload_generator/payload_signer.cc b/payload_generator/payload_signer.cc
index 72780b1..92313dc 100644
--- a/payload_generator/payload_signer.cc
+++ b/payload_generator/payload_signer.cc
@@ -18,7 +18,6 @@
 
 #include <endian.h>
 
-#include <memory>
 #include <utility>
 
 #include <base/logging.h>
@@ -47,29 +46,23 @@
 namespace chromeos_update_engine {
 
 namespace {
+
+// The payload verifier will check all the signatures included in the payload
+// regardless of the version field. Old version of the verifier require the
+// version field to be included and be 1.
+const uint32_t kSignatureMessageLegacyVersion = 1;
+
 // Given raw |signatures|, packs them into a protobuf and serializes it into a
 // string. Returns true on success, false otherwise.
 bool ConvertSignaturesToProtobuf(const vector<brillo::Blob>& signatures,
-                                 const vector<size_t>& padded_signature_sizes,
                                  string* out_serialized_signature) {
-  TEST_AND_RETURN_FALSE(signatures.size() == padded_signature_sizes.size());
   // Pack it into a protobuf
   Signatures out_message;
-  for (size_t i = 0; i < signatures.size(); i++) {
-    const auto& signature = signatures[i];
-    const auto& padded_signature_size = padded_signature_sizes[i];
-    TEST_AND_RETURN_FALSE(padded_signature_size >= signature.size());
+  for (const brillo::Blob& signature : signatures) {
     Signatures::Signature* sig_message = out_message.add_signatures();
-    // Skip assigning the same version number because we don't need to be
-    // compatible with old major version 1 client anymore.
-
-    // TODO(Xunchang) don't need to set the unpadded_signature_size field for
-    // RSA key signed signatures.
-    sig_message->set_unpadded_signature_size(signature.size());
-    brillo::Blob padded_signature = signature;
-    padded_signature.insert(
-        padded_signature.end(), padded_signature_size - signature.size(), 0);
-    sig_message->set_data(padded_signature.data(), padded_signature.size());
+    // Set all the signatures with the same version number.
+    sig_message->set_version(kSignatureMessageLegacyVersion);
+    sig_message->set_data(signature.data(), signature.size());
   }
 
   // Serialize protobuf
@@ -210,35 +203,8 @@
   return true;
 }
 
-std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> CreatePrivateKeyFromPath(
-    const string& private_key_path) {
-  FILE* fprikey = fopen(private_key_path.c_str(), "rb");
-  if (!fprikey) {
-    PLOG(ERROR) << "Failed to read " << private_key_path;
-    return {nullptr, nullptr};
-  }
-
-  auto private_key = std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>(
-      PEM_read_PrivateKey(fprikey, nullptr, nullptr, nullptr), EVP_PKEY_free);
-  fclose(fprikey);
-  return private_key;
-}
-
 }  // namespace
 
-bool PayloadSigner::GetMaximumSignatureSize(const string& private_key_path,
-                                            size_t* signature_size) {
-  *signature_size = 0;
-  auto private_key = CreatePrivateKeyFromPath(private_key_path);
-  if (!private_key) {
-    LOG(ERROR) << "Failed to create private key from " << private_key_path;
-    return false;
-  }
-
-  *signature_size = EVP_PKEY_size(private_key.get());
-  return true;
-}
-
 void PayloadSigner::AddSignatureToManifest(uint64_t signature_blob_offset,
                                            uint64_t signature_blob_length,
                                            bool add_dummy_op,
@@ -289,18 +255,14 @@
   string public_key;
   TEST_AND_RETURN_FALSE(utils::ReadFile(public_key_path, &public_key));
   TEST_AND_RETURN_FALSE(payload_hash.size() == kSHA256Size);
-
-  auto payload_verifier = PayloadVerifier::CreateInstance(public_key);
-  TEST_AND_RETURN_FALSE(payload_verifier != nullptr);
-
   TEST_AND_RETURN_FALSE(
-      payload_verifier->VerifySignature(signature, payload_hash));
+      PayloadVerifier::VerifySignature(signature, public_key, payload_hash));
   if (metadata_signature_size) {
     signature.assign(payload.begin() + metadata_size,
                      payload.begin() + metadata_size + metadata_signature_size);
     TEST_AND_RETURN_FALSE(metadata_hash.size() == kSHA256Size);
     TEST_AND_RETURN_FALSE(
-        payload_verifier->VerifySignature(signature, metadata_hash));
+        PayloadVerifier::VerifySignature(signature, public_key, metadata_hash));
   }
   return true;
 }
@@ -316,61 +278,29 @@
   // openssl rsautl -raw -sign -inkey |private_key_path|
   //   -in |padded_hash| -out |out_signature|
 
-  auto private_key = CreatePrivateKeyFromPath(private_key_path);
-  if (!private_key) {
-    LOG(ERROR) << "Failed to create private key from " << private_key_path;
+  FILE* fprikey = fopen(private_key_path.c_str(), "rb");
+  TEST_AND_RETURN_FALSE(fprikey != nullptr);
+  RSA* rsa = PEM_read_RSAPrivateKey(fprikey, nullptr, nullptr, nullptr);
+  fclose(fprikey);
+  TEST_AND_RETURN_FALSE(rsa != nullptr);
+
+  brillo::Blob padded_hash = hash;
+  PayloadVerifier::PadRSASHA256Hash(&padded_hash, RSA_size(rsa));
+
+  brillo::Blob signature(RSA_size(rsa));
+  ssize_t signature_size = RSA_private_encrypt(padded_hash.size(),
+                                               padded_hash.data(),
+                                               signature.data(),
+                                               rsa,
+                                               RSA_NO_PADDING);
+  RSA_free(rsa);
+  if (signature_size < 0) {
+    LOG(ERROR) << "Signing hash failed: "
+               << ERR_error_string(ERR_get_error(), nullptr);
     return false;
   }
-
-  int key_type = EVP_PKEY_id(private_key.get());
-  brillo::Blob signature;
-  if (key_type == EVP_PKEY_RSA) {
-    RSA* rsa = EVP_PKEY_get0_RSA(private_key.get());
-    TEST_AND_RETURN_FALSE(rsa != nullptr);
-
-    brillo::Blob padded_hash = hash;
-    PayloadVerifier::PadRSASHA256Hash(&padded_hash, RSA_size(rsa));
-
-    signature.resize(RSA_size(rsa));
-    ssize_t signature_size = RSA_private_encrypt(padded_hash.size(),
-                                                 padded_hash.data(),
-                                                 signature.data(),
-                                                 rsa,
-                                                 RSA_NO_PADDING);
-
-    if (signature_size < 0) {
-      LOG(ERROR) << "Signing hash failed: "
-                 << ERR_error_string(ERR_get_error(), nullptr);
-      return false;
-    }
-    TEST_AND_RETURN_FALSE(static_cast<size_t>(signature_size) ==
-                          signature.size());
-  } else if (key_type == EVP_PKEY_EC) {
-    EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(private_key.get());
-    TEST_AND_RETURN_FALSE(ec_key != nullptr);
-
-    signature.resize(ECDSA_size(ec_key));
-    unsigned int signature_size;
-    if (ECDSA_sign(0,
-                   hash.data(),
-                   hash.size(),
-                   signature.data(),
-                   &signature_size,
-                   ec_key) != 1) {
-      LOG(ERROR) << "Signing hash failed: "
-                 << ERR_error_string(ERR_get_error(), nullptr);
-      return false;
-    }
-
-    // NIST P-256
-    LOG(ERROR) << "signature max size " << signature.size() << " size "
-               << signature_size;
-    TEST_AND_RETURN_FALSE(signature.size() >= signature_size);
-    signature.resize(signature_size);
-  } else {
-    LOG(ERROR) << "key_type " << key_type << " isn't supported for signing";
-    return false;
-  }
+  TEST_AND_RETURN_FALSE(static_cast<size_t>(signature_size) ==
+                        signature.size());
   out_signature->swap(signature);
   return true;
 }
@@ -379,19 +309,13 @@
                                      const vector<string>& private_key_paths,
                                      string* out_serialized_signature) {
   vector<brillo::Blob> signatures;
-  vector<size_t> padded_signature_sizes;
   for (const string& path : private_key_paths) {
     brillo::Blob signature;
     TEST_AND_RETURN_FALSE(SignHash(hash_data, path, &signature));
     signatures.push_back(signature);
-
-    size_t padded_signature_size;
-    TEST_AND_RETURN_FALSE(
-        GetMaximumSignatureSize(path, &padded_signature_size));
-    padded_signature_sizes.push_back(padded_signature_size);
   }
-  TEST_AND_RETURN_FALSE(ConvertSignaturesToProtobuf(
-      signatures, padded_signature_sizes, out_serialized_signature));
+  TEST_AND_RETURN_FALSE(
+      ConvertSignaturesToProtobuf(signatures, out_serialized_signature));
   return true;
 }
 
@@ -428,7 +352,7 @@
 }
 
 bool PayloadSigner::HashPayloadForSigning(const string& payload_path,
-                                          const vector<size_t>& signature_sizes,
+                                          const vector<int>& signature_sizes,
                                           brillo::Blob* out_payload_hash_data,
                                           brillo::Blob* out_metadata_hash) {
   // Create a signature blob with signatures filled with 0.
@@ -438,8 +362,7 @@
     signatures.emplace_back(signature_size, 0);
   }
   string signature;
-  TEST_AND_RETURN_FALSE(
-      ConvertSignaturesToProtobuf(signatures, signature_sizes, &signature));
+  TEST_AND_RETURN_FALSE(ConvertSignaturesToProtobuf(signatures, &signature));
 
   brillo::Blob payload;
   uint64_t metadata_size, signatures_offset;
@@ -463,7 +386,6 @@
 
 bool PayloadSigner::AddSignatureToPayload(
     const string& payload_path,
-    const vector<size_t>& padded_signature_sizes,
     const vector<brillo::Blob>& payload_signatures,
     const vector<brillo::Blob>& metadata_signatures,
     const string& signed_payload_path,
@@ -472,11 +394,11 @@
 
   // Loads the payload and adds the signature op to it.
   string payload_signature, metadata_signature;
-  TEST_AND_RETURN_FALSE(ConvertSignaturesToProtobuf(
-      payload_signatures, padded_signature_sizes, &payload_signature));
+  TEST_AND_RETURN_FALSE(
+      ConvertSignaturesToProtobuf(payload_signatures, &payload_signature));
   if (!metadata_signatures.empty()) {
-    TEST_AND_RETURN_FALSE(ConvertSignaturesToProtobuf(
-        metadata_signatures, padded_signature_sizes, &metadata_signature));
+    TEST_AND_RETURN_FALSE(
+        ConvertSignaturesToProtobuf(metadata_signatures, &metadata_signature));
   }
   brillo::Blob payload;
   uint64_t signatures_offset;
diff --git a/payload_generator/payload_signer.h b/payload_generator/payload_signer.h
index bd1e32f..7854e12 100644
--- a/payload_generator/payload_signer.h
+++ b/payload_generator/payload_signer.h
@@ -91,7 +91,7 @@
   //
   // The changes to payload are not preserved or written to disk.
   static bool HashPayloadForSigning(const std::string& payload_path,
-                                    const std::vector<size_t>& signature_sizes,
+                                    const std::vector<int>& signature_sizes,
                                     brillo::Blob* out_payload_hash_data,
                                     brillo::Blob* out_metadata_hash);
 
@@ -105,7 +105,6 @@
   // otherwise.
   static bool AddSignatureToPayload(
       const std::string& payload_path,
-      const std::vector<size_t>& padded_signature_sizes,
       const std::vector<brillo::Blob>& payload_signatures,
       const std::vector<brillo::Blob>& metadata_signatures,
       const std::string& signed_payload_path,
@@ -123,13 +122,6 @@
   static bool ExtractPayloadProperties(const std::string& payload_path,
                                        brillo::KeyValueStore* properties);
 
-  // This function calculates the maximum size, in bytes, of a signature signed
-  // by private_key_path. For an RSA key, this returns the number of bytes
-  // needed to represent the modulus. For an EC key, this returns the maximum
-  // size of a DER-encoded ECDSA signature.
-  static bool GetMaximumSignatureSize(const std::string& private_key_path,
-                                      size_t* signature_size);
-
  private:
   // This should never be constructed
   DISALLOW_IMPLICIT_CONSTRUCTORS(PayloadSigner);
diff --git a/payload_generator/payload_signer_unittest.cc b/payload_generator/payload_signer_unittest.cc
index bf7100b..75fc694 100644
--- a/payload_generator/payload_signer_unittest.cc
+++ b/payload_generator/payload_signer_unittest.cc
@@ -46,8 +46,6 @@
 const char* kUnittestPublicKey2Path = "unittest_key2.pub.pem";
 const char* kUnittestPrivateKeyRSA4096Path = "unittest_key_RSA4096.pem";
 const char* kUnittestPublicKeyRSA4096Path = "unittest_key_RSA4096.pub.pem";
-const char* kUnittestPrivateKeyECPath = "unittest_key_EC.pem";
-const char* kUnittestPublicKeyECPath = "unittest_key_EC.pub.pem";
 
 // Some data and its corresponding hash and signature:
 const char kDataToSign[] = "This is some data to sign.";
@@ -117,6 +115,7 @@
   EXPECT_TRUE(signatures.ParseFromString(signature));
   EXPECT_EQ(1, signatures.signatures_size());
   const Signatures::Signature& sig = signatures.signatures(0);
+  EXPECT_EQ(1U, sig.version());
   const string& sig_data = sig.data();
   ASSERT_EQ(arraysize(kDataSignature), sig_data.size());
   for (size_t i = 0; i < arraysize(kDataSignature); i++) {
@@ -129,20 +128,22 @@
   SignSampleData(&signature,
                  {GetBuildArtifactsPath(kUnittestPrivateKeyPath),
                   GetBuildArtifactsPath(kUnittestPrivateKey2Path),
-                  GetBuildArtifactsPath(kUnittestPrivateKeyRSA4096Path),
-                  GetBuildArtifactsPath(kUnittestPrivateKeyECPath)});
+                  GetBuildArtifactsPath(kUnittestPrivateKeyRSA4096Path)});
 
   // Either public key should pass the verification.
-  for (const auto& path : {kUnittestPublicKeyPath,
-                           kUnittestPublicKey2Path,
-                           kUnittestPublicKeyRSA4096Path,
-                           kUnittestPublicKeyECPath}) {
-    string public_key;
-    EXPECT_TRUE(utils::ReadFile(GetBuildArtifactsPath(path), &public_key));
-    auto payload_verifier = PayloadVerifier::CreateInstance(public_key);
-    EXPECT_TRUE(payload_verifier != nullptr);
-    EXPECT_TRUE(payload_verifier->VerifySignature(signature, hash_data_));
-  }
+  string public_key;
+  EXPECT_TRUE(utils::ReadFile(GetBuildArtifactsPath(kUnittestPublicKeyPath),
+                              &public_key));
+  EXPECT_TRUE(
+      PayloadVerifier::VerifySignature(signature, public_key, hash_data_));
+  EXPECT_TRUE(utils::ReadFile(GetBuildArtifactsPath(kUnittestPublicKey2Path),
+                              &public_key));
+  EXPECT_TRUE(
+      PayloadVerifier::VerifySignature(signature, public_key, hash_data_));
+  EXPECT_TRUE(utils::ReadFile(
+      GetBuildArtifactsPath(kUnittestPublicKeyRSA4096Path), &public_key));
+  EXPECT_TRUE(
+      PayloadVerifier::VerifySignature(signature, public_key, hash_data_));
 }
 
 TEST_F(PayloadSignerTest, VerifySignatureTest) {
@@ -152,17 +153,13 @@
   string public_key;
   EXPECT_TRUE(utils::ReadFile(GetBuildArtifactsPath(kUnittestPublicKeyPath),
                               &public_key));
-  auto payload_verifier = PayloadVerifier::CreateInstance(public_key);
-  EXPECT_TRUE(payload_verifier != nullptr);
-  EXPECT_TRUE(payload_verifier->VerifySignature(signature, hash_data_));
-
+  EXPECT_TRUE(
+      PayloadVerifier::VerifySignature(signature, public_key, hash_data_));
   // Passing the invalid key should fail the verification.
-  public_key.clear();
   EXPECT_TRUE(utils::ReadFile(GetBuildArtifactsPath(kUnittestPublicKey2Path),
                               &public_key));
-  payload_verifier = PayloadVerifier::CreateInstance(public_key);
-  EXPECT_TRUE(payload_verifier != nullptr);
-  EXPECT_FALSE(payload_verifier->VerifySignature(signature, hash_data_));
+  EXPECT_TRUE(
+      PayloadVerifier::VerifySignature(signature, public_key, hash_data_));
 }
 
 TEST_F(PayloadSignerTest, SkipMetadataSignatureTest) {
@@ -174,7 +171,7 @@
   uint64_t metadata_size;
   EXPECT_TRUE(payload.WritePayload(
       payload_file.path(), "/dev/null", "", &metadata_size));
-  const vector<size_t> sizes = {256};
+  const vector<int> sizes = {256};
   brillo::Blob unsigned_payload_hash, unsigned_metadata_hash;
   EXPECT_TRUE(PayloadSigner::HashPayloadForSigning(payload_file.path(),
                                                    sizes,
diff --git a/scripts/brillo_update_payload b/scripts/brillo_update_payload
index d9c18ff..f535185 100755
--- a/scripts/brillo_update_payload
+++ b/scripts/brillo_update_payload
@@ -28,16 +28,12 @@
 #  check       verify a payload using paycheck (static testing)
 #
 #  Generate command arguments:
-#  --payload                  generated unsigned payload output file
-#  --source_image             if defined, generate a delta payload from the
-#                             specified image to the target_image
-#  --target_image             the target image that should be sent to clients
-#  --metadata_size_file       if defined, generate a file containing the size
-#                             of the ayload metadata in bytes to the specified
-#                             file
-#  --disable_fec_computation  Disable the on device fec data computation for
-#                             incremental update. This feature is enabled by
-#                             default
+#  --payload             generated unsigned payload output file
+#  --source_image        if defined, generate a delta payload from the specified
+#                        image to the target_image
+#  --target_image        the target image that should be sent to clients
+#  --metadata_size_file  if defined, generate a file containing the size of the
+#                        payload metadata in bytes to the specified file
 #
 #  Hash command arguments:
 #  --unsigned_payload    the input unsigned payload to generate the hash from
@@ -186,9 +182,6 @@
     "Optional: The maximum unix timestamp of the OS allowed to apply this \
 payload, should be set to a number higher than the build timestamp of the \
 system running on the device, 0 if not specified."
-  DEFINE_string disable_fec_computation "" \
-    "Optional: Disables the on device fec data computation for incremental \
-update. This feature is enabled by default."
 fi
 if [[ "${COMMAND}" == "hash" || "${COMMAND}" == "sign" ]]; then
   DEFINE_string unsigned_payload "" "Path to the input unsigned payload."
@@ -281,7 +274,7 @@
   local option_key="$2"
   local default_value="${3:-}"
   local value
-  if value=$(grep "^${option_key}=" "${file_txt}" | tail -n 1); then
+  if value=$(look "${option_key}=" "${file_txt}" | tail -n 1); then
     if value=$(echo "${value}" | cut -f 2- -d "=" | grep -E "^[0-9]+$"); then
       echo "${value}"
       return
@@ -334,25 +327,6 @@
 trap cleanup_on_error INT TERM ERR
 trap cleanup_on_exit EXIT
 
-# extract_file <zip_file> <entry_name> <destination>
-#
-# Extracts |entry_name| from |zip_file| to |destination|.
-extract_file() {
-  local zip_file="$1"
-  local entry_name="$2"
-  local destination="$3"
-
-  # unzip -p won't report error upon ENOSPC. Therefore, create a temp directory
-  # as the destination of the unzip, and move the file to the intended
-  # destination.
-  local output_directory=$(
-    mktemp --directory --tmpdir="${FLAGS_work_dir}" "TEMP.XXXXXX")
-  unzip "${zip_file}" "${entry_name}" -d "${output_directory}" ||
-    { rm -rf "${output_directory}"; die "Failed to extract ${entry_name}"; }
-
-  mv "${output_directory}/${entry_name}" "${destination}"
-  rm -rf "${output_directory}"
-}
 
 # extract_image <image> <partitions_array> [partitions_order]
 #
@@ -443,7 +417,7 @@
     fi
   done
   [[ -n "${path_in_zip}" ]] || die "Failed to find ${part}.img"
-  extract_file "${image}" "${path_in_zip}/${part}.img" "${part_file}"
+  unzip -p "${image}" "${path_in_zip}/${part}.img" >"${part_file}"
 
   # If the partition is stored as an Android sparse image file, we need to
   # convert them to a raw image for the update.
@@ -457,9 +431,8 @@
   fi
 
   # Extract the .map file (if one is available).
-  if unzip -l "${image}" "${path_in_zip}/${part}.map" > /dev/null; then
-    extract_file "${image}" "${path_in_zip}/${part}.map" "${part_map_file}"
-  fi
+  unzip -p "${image}" "${path_in_zip}/${part}.map" >"${part_map_file}" \
+    2>/dev/null || true
 
   # delta_generator only supports images multiple of 4 KiB. For target images
   # we pad the data with zeros if needed, but for source images we truncate
@@ -493,8 +466,7 @@
   local ab_partitions_list
   ab_partitions_list=$(create_tempfile "ab_partitions_list.XXXXXX")
   CLEANUP_FILES+=("${ab_partitions_list}")
-  if unzip -l "${image}" "META/ab_partitions.txt" > /dev/null; then
-    extract_file "${image}" "META/ab_partitions.txt" "${ab_partitions_list}"
+  if unzip -p "${image}" "META/ab_partitions.txt" >"${ab_partitions_list}"; then
     if grep -v -E '^[a-zA-Z0-9_-]*$' "${ab_partitions_list}" >&2; then
       die "Invalid partition names found in the partition list."
     fi
@@ -519,9 +491,8 @@
     # Source image
     local ue_config=$(create_tempfile "ue_config.XXXXXX")
     CLEANUP_FILES+=("${ue_config}")
-    if unzip -l "${image}" "META/update_engine_config.txt" > /dev/null; then
-      extract_file "${image}" "META/update_engine_config.txt" "${ue_config}"
-    else
+    if ! unzip -p "${image}" "META/update_engine_config.txt" \
+        >"${ue_config}"; then
       warn "No update_engine_config.txt found. Assuming pre-release image, \
 using payload minor version 2"
     fi
@@ -542,16 +513,14 @@
     # Target image
     local postinstall_config=$(create_tempfile "postinstall_config.XXXXXX")
     CLEANUP_FILES+=("${postinstall_config}")
-    if unzip -l "${image}" "META/postinstall_config.txt" > /dev/null; then
-      extract_file "${image}" "META/postinstall_config.txt" \
-        "${postinstall_config}"
+    if unzip -p "${image}" "META/postinstall_config.txt" \
+        >"${postinstall_config}"; then
       POSTINSTALL_CONFIG_FILE="${postinstall_config}"
     fi
     local dynamic_partitions_info=$(create_tempfile "dynamic_partitions_info.XXXXXX")
     CLEANUP_FILES+=("${dynamic_partitions_info}")
-    if unzip -l "${image}" "META/dynamic_partitions_info.txt" > /dev/null; then
-      extract_file "${image}" "META/dynamic_partitions_info.txt" \
-        "${dynamic_partitions_info}"
+    if unzip -p "${image}" "META/dynamic_partitions_info.txt" \
+        >"${dynamic_partitions_info}"; then
       DYNAMIC_PARTITION_INFO_FILE="${dynamic_partitions_info}"
     fi
   fi
@@ -663,10 +632,6 @@
     if [[ -n "${FORCE_MINOR_VERSION}" ]]; then
       GENERATOR_ARGS+=( --minor_version="${FORCE_MINOR_VERSION}" )
     fi
-    if [[ -n "${FLAGS_disable_fec_computation}" ]]; then
-      GENERATOR_ARGS+=(
-        --disable_fec_computation="${FLAGS_disable_fec_computation}" )
-    fi
   fi
 
   if [[ -n "${FORCE_MAJOR_VERSION}" ]]; then
diff --git a/scripts/update_device.py b/scripts/update_device.py
index 49f766d..5c19b89 100755
--- a/scripts/update_device.py
+++ b/scripts/update_device.py
@@ -83,24 +83,17 @@
   # Android OTA package file paths.
   OTA_PAYLOAD_BIN = 'payload.bin'
   OTA_PAYLOAD_PROPERTIES_TXT = 'payload_properties.txt'
-  SECONDARY_OTA_PAYLOAD_BIN = 'secondary/payload.bin'
-  SECONDARY_OTA_PAYLOAD_PROPERTIES_TXT = 'secondary/payload_properties.txt'
 
-  def __init__(self, otafilename, secondary_payload=False):
+  def __init__(self, otafilename):
     self.otafilename = otafilename
 
     otazip = zipfile.ZipFile(otafilename, 'r')
-    payload_entry = (self.SECONDARY_OTA_PAYLOAD_BIN if secondary_payload else
-                     self.OTA_PAYLOAD_BIN)
-    payload_info = otazip.getinfo(payload_entry)
+    payload_info = otazip.getinfo(self.OTA_PAYLOAD_BIN)
     self.offset = payload_info.header_offset
     self.offset += zipfile.sizeFileHeader
     self.offset += len(payload_info.extra) + len(payload_info.filename)
     self.size = payload_info.file_size
-
-    property_entry = (self.SECONDARY_OTA_PAYLOAD_PROPERTIES_TXT if
-                      secondary_payload else self.OTA_PAYLOAD_PROPERTIES_TXT)
-    self.properties = otazip.read(property_entry)
+    self.properties = otazip.read(self.OTA_PAYLOAD_PROPERTIES_TXT)
 
 
 class UpdateHandler(BaseHTTPServer.BaseHTTPRequestHandler):
@@ -285,9 +278,9 @@
   return t
 
 
-def AndroidUpdateCommand(ota_filename, secondary, payload_url, extra_headers):
+def AndroidUpdateCommand(ota_filename, payload_url, extra_headers):
   """Return the command to run to start the update in the Android device."""
-  ota = AndroidOTAPackage(ota_filename, secondary)
+  ota = AndroidOTAPackage(ota_filename)
   headers = ota.properties
   headers += 'USER_AGENT=Dalvik (something, something)\n'
   headers += 'NETWORK_ID=0\n'
@@ -370,8 +363,6 @@
                       help='Override the public key used to verify payload.')
   parser.add_argument('--extra-headers', type=str, default='',
                       help='Extra headers to pass to the device.')
-  parser.add_argument('--secondary', action='store_true',
-                      help='Update with the secondary payload in the package.')
   args = parser.parse_args()
   logging.basicConfig(
       level=logging.WARNING if args.no_verbose else logging.INFO)
@@ -407,7 +398,7 @@
     # command.
     payload_url = 'http://127.0.0.1:%d/payload' % DEVICE_PORT
     if use_omaha and zipfile.is_zipfile(args.otafile):
-      ota = AndroidOTAPackage(args.otafile, args.secondary)
+      ota = AndroidOTAPackage(args.otafile)
       serving_range = (ota.offset, ota.size)
     else:
       serving_range = (0, os.stat(args.otafile).st_size)
@@ -435,8 +426,8 @@
       update_cmd = \
           OmahaUpdateCommand('http://127.0.0.1:%d/update' % DEVICE_PORT)
     else:
-      update_cmd = AndroidUpdateCommand(args.otafile, args.secondary,
-                                        payload_url, args.extra_headers)
+      update_cmd = \
+          AndroidUpdateCommand(args.otafile, payload_url, args.extra_headers)
     cmds.append(['shell', 'su', '0'] + update_cmd)
 
     for cmd in cmds:
diff --git a/scripts/update_payload/update_metadata_pb2.py b/scripts/update_payload/update_metadata_pb2.py
index cb8f4c2..7f1648b 100644
--- a/scripts/update_payload/update_metadata_pb2.py
+++ b/scripts/update_payload/update_metadata_pb2.py
@@ -1,27 +1,19 @@
-# -*- coding: utf-8 -*-
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
 # source: update_metadata.proto
 
-import sys
-_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
 from google.protobuf import descriptor as _descriptor
 from google.protobuf import message as _message
 from google.protobuf import reflection as _reflection
-from google.protobuf import symbol_database as _symbol_database
+from google.protobuf import descriptor_pb2
 # @@protoc_insertion_point(imports)
 
-_sym_db = _symbol_database.Default()
-
 
 
 
 DESCRIPTOR = _descriptor.FileDescriptor(
   name='update_metadata.proto',
   package='chromeos_update_engine',
-  syntax='proto2',
-  serialized_options=_b('H\003'),
-  serialized_pb=_b('\n\x15update_metadata.proto\x12\x16\x63hromeos_update_engine\"1\n\x06\x45xtent\x12\x13\n\x0bstart_block\x18\x01 \x01(\x04\x12\x12\n\nnum_blocks\x18\x02 \x01(\x04\"z\n\nSignatures\x12@\n\nsignatures\x18\x01 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x1a*\n\tSignature\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"+\n\rPartitionInfo\x12\x0c\n\x04size\x18\x01 \x01(\x04\x12\x0c\n\x04hash\x18\x02 \x01(\x0c\"w\n\tImageInfo\x12\r\n\x05\x62oard\x18\x01 \x01(\t\x12\x0b\n\x03key\x18\x02 \x01(\t\x12\x0f\n\x07\x63hannel\x18\x03 \x01(\t\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x15\n\rbuild_channel\x18\x05 \x01(\t\x12\x15\n\rbuild_version\x18\x06 \x01(\t\"\xee\x03\n\x10InstallOperation\x12;\n\x04type\x18\x01 \x02(\x0e\x32-.chromeos_update_engine.InstallOperation.Type\x12\x13\n\x0b\x64\x61ta_offset\x18\x02 \x01(\x04\x12\x13\n\x0b\x64\x61ta_length\x18\x03 \x01(\x04\x12\x33\n\x0bsrc_extents\x18\x04 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_length\x18\x05 \x01(\x04\x12\x33\n\x0b\x64st_extents\x18\x06 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\ndst_length\x18\x07 \x01(\x04\x12\x18\n\x10\x64\x61ta_sha256_hash\x18\x08 \x01(\x0c\x12\x17\n\x0fsrc_sha256_hash\x18\t \x01(\x0c\"\xad\x01\n\x04Type\x12\x0b\n\x07REPLACE\x10\x00\x12\x0e\n\nREPLACE_BZ\x10\x01\x12\x0c\n\x04MOVE\x10\x02\x1a\x02\x08\x01\x12\x0e\n\x06\x42SDIFF\x10\x03\x1a\x02\x08\x01\x12\x0f\n\x0bSOURCE_COPY\x10\x04\x12\x11\n\rSOURCE_BSDIFF\x10\x05\x12\x0e\n\nREPLACE_XZ\x10\x08\x12\x08\n\x04ZERO\x10\x06\x12\x0b\n\x07\x44ISCARD\x10\x07\x12\x11\n\rBROTLI_BSDIFF\x10\n\x12\x0c\n\x08PUFFDIFF\x10\t\"\xd7\x05\n\x0fPartitionUpdate\x12\x16\n\x0epartition_name\x18\x01 \x02(\t\x12\x17\n\x0frun_postinstall\x18\x02 \x01(\x08\x12\x18\n\x10postinstall_path\x18\x03 \x01(\t\x12\x17\n\x0f\x66ilesystem_type\x18\x04 \x01(\t\x12M\n\x17new_partition_signature\x18\x05 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x12\x41\n\x12old_partition_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x41\n\x12new_partition_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12<\n\noperations\x18\x08 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x1c\n\x14postinstall_optional\x18\t \x01(\x08\x12=\n\x15hash_tree_data_extent\x18\n \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x38\n\x10hash_tree_extent\x18\x0b \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x1b\n\x13hash_tree_algorithm\x18\x0c \x01(\t\x12\x16\n\x0ehash_tree_salt\x18\r \x01(\x0c\x12\x37\n\x0f\x66\x65\x63_data_extent\x18\x0e \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\nfec_extent\x18\x0f \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x14\n\tfec_roots\x18\x10 \x01(\r:\x01\x32\"L\n\x15\x44ynamicPartitionGroup\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04size\x18\x02 \x01(\x04\x12\x17\n\x0fpartition_names\x18\x03 \x03(\t\"s\n\x18\x44ynamicPartitionMetadata\x12=\n\x06groups\x18\x01 \x03(\x0b\x32-.chromeos_update_engine.DynamicPartitionGroup\x12\x18\n\x10snapshot_enabled\x18\x02 \x01(\x08\"\xb1\x06\n\x14\x44\x65ltaArchiveManifest\x12\x44\n\x12install_operations\x18\x01 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12K\n\x19kernel_install_operations\x18\x02 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x18\n\nblock_size\x18\x03 \x01(\r:\x04\x34\x30\x39\x36\x12\x19\n\x11signatures_offset\x18\x04 \x01(\x04\x12\x17\n\x0fsignatures_size\x18\x05 \x01(\x04\x12>\n\x0fold_kernel_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12>\n\x0fnew_kernel_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12>\n\x0fold_rootfs_info\x18\x08 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12>\n\x0fnew_rootfs_info\x18\t \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x39\n\x0eold_image_info\x18\n \x01(\x0b\x32!.chromeos_update_engine.ImageInfo\x12\x39\n\x0enew_image_info\x18\x0b \x01(\x0b\x32!.chromeos_update_engine.ImageInfo\x12\x18\n\rminor_version\x18\x0c \x01(\r:\x01\x30\x12;\n\npartitions\x18\r \x03(\x0b\x32\'.chromeos_update_engine.PartitionUpdate\x12\x15\n\rmax_timestamp\x18\x0e \x01(\x03\x12T\n\x1a\x64ynamic_partition_metadata\x18\x0f \x01(\x0b\x32\x30.chromeos_update_engine.DynamicPartitionMetadataB\x02H\x03')
-)
+  serialized_pb='\n\x15update_metadata.proto\x12\x16\x63hromeos_update_engine\"1\n\x06\x45xtent\x12\x13\n\x0bstart_block\x18\x01 \x01(\x04\x12\x12\n\nnum_blocks\x18\x02 \x01(\x04\"z\n\nSignatures\x12@\n\nsignatures\x18\x01 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x1a*\n\tSignature\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"+\n\rPartitionInfo\x12\x0c\n\x04size\x18\x01 \x01(\x04\x12\x0c\n\x04hash\x18\x02 \x01(\x0c\"w\n\tImageInfo\x12\r\n\x05\x62oard\x18\x01 \x01(\t\x12\x0b\n\x03key\x18\x02 \x01(\t\x12\x0f\n\x07\x63hannel\x18\x03 \x01(\t\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x15\n\rbuild_channel\x18\x05 \x01(\t\x12\x15\n\rbuild_version\x18\x06 \x01(\t\"\xe6\x03\n\x10InstallOperation\x12;\n\x04type\x18\x01 \x02(\x0e\x32-.chromeos_update_engine.InstallOperation.Type\x12\x13\n\x0b\x64\x61ta_offset\x18\x02 \x01(\x04\x12\x13\n\x0b\x64\x61ta_length\x18\x03 \x01(\x04\x12\x33\n\x0bsrc_extents\x18\x04 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_length\x18\x05 \x01(\x04\x12\x33\n\x0b\x64st_extents\x18\x06 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\ndst_length\x18\x07 \x01(\x04\x12\x18\n\x10\x64\x61ta_sha256_hash\x18\x08 \x01(\x0c\x12\x17\n\x0fsrc_sha256_hash\x18\t \x01(\x0c\"\xa5\x01\n\x04Type\x12\x0b\n\x07REPLACE\x10\x00\x12\x0e\n\nREPLACE_BZ\x10\x01\x12\x08\n\x04MOVE\x10\x02\x12\n\n\x06\x42SDIFF\x10\x03\x12\x0f\n\x0bSOURCE_COPY\x10\x04\x12\x11\n\rSOURCE_BSDIFF\x10\x05\x12\x0e\n\nREPLACE_XZ\x10\x08\x12\x08\n\x04ZERO\x10\x06\x12\x0b\n\x07\x44ISCARD\x10\x07\x12\x11\n\rBROTLI_BSDIFF\x10\n\x12\x0c\n\x08PUFFDIFF\x10\t\"\xd7\x05\n\x0fPartitionUpdate\x12\x16\n\x0epartition_name\x18\x01 \x02(\t\x12\x17\n\x0frun_postinstall\x18\x02 \x01(\x08\x12\x18\n\x10postinstall_path\x18\x03 \x01(\t\x12\x17\n\x0f\x66ilesystem_type\x18\x04 \x01(\t\x12M\n\x17new_partition_signature\x18\x05 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x12\x41\n\x12old_partition_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x41\n\x12new_partition_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12<\n\noperations\x18\x08 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x1c\n\x14postinstall_optional\x18\t \x01(\x08\x12=\n\x15hash_tree_data_extent\x18\n \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x38\n\x10hash_tree_extent\x18\x0b \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x1b\n\x13hash_tree_algorithm\x18\x0c \x01(\t\x12\x16\n\x0ehash_tree_salt\x18\r \x01(\x0c\x12\x37\n\x0f\x66\x65\x63_data_extent\x18\x0e \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\nfec_extent\x18\x0f \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x14\n\tfec_roots\x18\x10 \x01(\r:\x01\x32\"L\n\x15\x44ynamicPartitionGroup\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04size\x18\x02 \x01(\x04\x12\x17\n\x0fpartition_names\x18\x03 \x03(\t\"Y\n\x18\x44ynamicPartitionMetadata\x12=\n\x06groups\x18\x01 \x03(\x0b\x32-.chromeos_update_engine.DynamicPartitionGroup\"\xb1\x06\n\x14\x44\x65ltaArchiveManifest\x12\x44\n\x12install_operations\x18\x01 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12K\n\x19kernel_install_operations\x18\x02 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x18\n\nblock_size\x18\x03 \x01(\r:\x04\x34\x30\x39\x36\x12\x19\n\x11signatures_offset\x18\x04 \x01(\x04\x12\x17\n\x0fsignatures_size\x18\x05 \x01(\x04\x12>\n\x0fold_kernel_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12>\n\x0fnew_kernel_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12>\n\x0fold_rootfs_info\x18\x08 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12>\n\x0fnew_rootfs_info\x18\t \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x39\n\x0eold_image_info\x18\n \x01(\x0b\x32!.chromeos_update_engine.ImageInfo\x12\x39\n\x0enew_image_info\x18\x0b \x01(\x0b\x32!.chromeos_update_engine.ImageInfo\x12\x18\n\rminor_version\x18\x0c \x01(\r:\x01\x30\x12;\n\npartitions\x18\r \x03(\x0b\x32\'.chromeos_update_engine.PartitionUpdate\x12\x15\n\rmax_timestamp\x18\x0e \x01(\x03\x12T\n\x1a\x64ynamic_partition_metadata\x18\x0f \x01(\x0b\x32\x30.chromeos_update_engine.DynamicPartitionMetadataB\x02H\x03')
 
 
 
@@ -33,55 +25,54 @@
   values=[
     _descriptor.EnumValueDescriptor(
       name='REPLACE', index=0, number=0,
-      serialized_options=None,
+      options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='REPLACE_BZ', index=1, number=1,
-      serialized_options=None,
+      options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='MOVE', index=2, number=2,
-      serialized_options=_b('\010\001'),
+      options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='BSDIFF', index=3, number=3,
-      serialized_options=_b('\010\001'),
+      options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='SOURCE_COPY', index=4, number=4,
-      serialized_options=None,
+      options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='SOURCE_BSDIFF', index=5, number=5,
-      serialized_options=None,
+      options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='REPLACE_XZ', index=6, number=8,
-      serialized_options=None,
+      options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='ZERO', index=7, number=6,
-      serialized_options=None,
+      options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='DISCARD', index=8, number=7,
-      serialized_options=None,
+      options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='BROTLI_BSDIFF', index=9, number=10,
-      serialized_options=None,
+      options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
       name='PUFFDIFF', index=10, number=9,
-      serialized_options=None,
+      options=None,
       type=None),
   ],
   containing_type=None,
-  serialized_options=None,
+  options=None,
   serialized_start=712,
-  serialized_end=885,
+  serialized_end=877,
 )
-_sym_db.RegisterEnumDescriptor(_INSTALLOPERATION_TYPE)
 
 
 _EXTENT = _descriptor.Descriptor(
@@ -97,26 +88,23 @@
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='num_blocks', full_name='chromeos_update_engine.Extent.num_blocks', index=1,
       number=2, type=4, cpp_type=4, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
   ],
-  serialized_options=None,
+  options=None,
   is_extendable=False,
-  syntax='proto2',
   extension_ranges=[],
-  oneofs=[
-  ],
   serialized_start=49,
   serialized_end=98,
 )
@@ -135,26 +123,23 @@
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='data', full_name='chromeos_update_engine.Signatures.Signature.data', index=1,
       number=2, type=12, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b(""),
+      has_default_value=False, default_value="",
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
   ],
-  serialized_options=None,
+  options=None,
   is_extendable=False,
-  syntax='proto2',
   extension_ranges=[],
-  oneofs=[
-  ],
   serialized_start=180,
   serialized_end=222,
 )
@@ -172,19 +157,16 @@
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
   ],
   extensions=[
   ],
   nested_types=[_SIGNATURES_SIGNATURE, ],
   enum_types=[
   ],
-  serialized_options=None,
+  options=None,
   is_extendable=False,
-  syntax='proto2',
   extension_ranges=[],
-  oneofs=[
-  ],
   serialized_start=100,
   serialized_end=222,
 )
@@ -203,26 +185,23 @@
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='hash', full_name='chromeos_update_engine.PartitionInfo.hash', index=1,
       number=2, type=12, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b(""),
+      has_default_value=False, default_value="",
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
   ],
-  serialized_options=None,
+  options=None,
   is_extendable=False,
-  syntax='proto2',
   extension_ranges=[],
-  oneofs=[
-  ],
   serialized_start=224,
   serialized_end=267,
 )
@@ -238,57 +217,54 @@
     _descriptor.FieldDescriptor(
       name='board', full_name='chromeos_update_engine.ImageInfo.board', index=0,
       number=1, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
+      has_default_value=False, default_value=unicode("", "utf-8"),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='key', full_name='chromeos_update_engine.ImageInfo.key', index=1,
       number=2, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
+      has_default_value=False, default_value=unicode("", "utf-8"),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='channel', full_name='chromeos_update_engine.ImageInfo.channel', index=2,
       number=3, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
+      has_default_value=False, default_value=unicode("", "utf-8"),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='version', full_name='chromeos_update_engine.ImageInfo.version', index=3,
       number=4, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
+      has_default_value=False, default_value=unicode("", "utf-8"),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='build_channel', full_name='chromeos_update_engine.ImageInfo.build_channel', index=4,
       number=5, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
+      has_default_value=False, default_value=unicode("", "utf-8"),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='build_version', full_name='chromeos_update_engine.ImageInfo.build_version', index=5,
       number=6, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
+      has_default_value=False, default_value=unicode("", "utf-8"),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
   ],
-  serialized_options=None,
+  options=None,
   is_extendable=False,
-  syntax='proto2',
   extension_ranges=[],
-  oneofs=[
-  ],
   serialized_start=269,
   serialized_end=388,
 )
@@ -307,63 +283,63 @@
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='data_offset', full_name='chromeos_update_engine.InstallOperation.data_offset', index=1,
       number=2, type=4, cpp_type=4, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='data_length', full_name='chromeos_update_engine.InstallOperation.data_length', index=2,
       number=3, type=4, cpp_type=4, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='src_extents', full_name='chromeos_update_engine.InstallOperation.src_extents', index=3,
       number=4, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='src_length', full_name='chromeos_update_engine.InstallOperation.src_length', index=4,
       number=5, type=4, cpp_type=4, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='dst_extents', full_name='chromeos_update_engine.InstallOperation.dst_extents', index=5,
       number=6, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='dst_length', full_name='chromeos_update_engine.InstallOperation.dst_length', index=6,
       number=7, type=4, cpp_type=4, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='data_sha256_hash', full_name='chromeos_update_engine.InstallOperation.data_sha256_hash', index=7,
       number=8, type=12, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b(""),
+      has_default_value=False, default_value="",
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='src_sha256_hash', full_name='chromeos_update_engine.InstallOperation.src_sha256_hash', index=8,
       number=9, type=12, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b(""),
+      has_default_value=False, default_value="",
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
   ],
   extensions=[
   ],
@@ -371,14 +347,11 @@
   enum_types=[
     _INSTALLOPERATION_TYPE,
   ],
-  serialized_options=None,
+  options=None,
   is_extendable=False,
-  syntax='proto2',
   extension_ranges=[],
-  oneofs=[
-  ],
   serialized_start=391,
-  serialized_end=885,
+  serialized_end=877,
 )
 
 
@@ -392,129 +365,126 @@
     _descriptor.FieldDescriptor(
       name='partition_name', full_name='chromeos_update_engine.PartitionUpdate.partition_name', index=0,
       number=1, type=9, cpp_type=9, label=2,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
+      has_default_value=False, default_value=unicode("", "utf-8"),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='run_postinstall', full_name='chromeos_update_engine.PartitionUpdate.run_postinstall', index=1,
       number=2, type=8, cpp_type=7, label=1,
       has_default_value=False, default_value=False,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='postinstall_path', full_name='chromeos_update_engine.PartitionUpdate.postinstall_path', index=2,
       number=3, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
+      has_default_value=False, default_value=unicode("", "utf-8"),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='filesystem_type', full_name='chromeos_update_engine.PartitionUpdate.filesystem_type', index=3,
       number=4, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
+      has_default_value=False, default_value=unicode("", "utf-8"),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='new_partition_signature', full_name='chromeos_update_engine.PartitionUpdate.new_partition_signature', index=4,
       number=5, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='old_partition_info', full_name='chromeos_update_engine.PartitionUpdate.old_partition_info', index=5,
       number=6, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='new_partition_info', full_name='chromeos_update_engine.PartitionUpdate.new_partition_info', index=6,
       number=7, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='operations', full_name='chromeos_update_engine.PartitionUpdate.operations', index=7,
       number=8, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='postinstall_optional', full_name='chromeos_update_engine.PartitionUpdate.postinstall_optional', index=8,
       number=9, type=8, cpp_type=7, label=1,
       has_default_value=False, default_value=False,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='hash_tree_data_extent', full_name='chromeos_update_engine.PartitionUpdate.hash_tree_data_extent', index=9,
       number=10, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='hash_tree_extent', full_name='chromeos_update_engine.PartitionUpdate.hash_tree_extent', index=10,
       number=11, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='hash_tree_algorithm', full_name='chromeos_update_engine.PartitionUpdate.hash_tree_algorithm', index=11,
       number=12, type=9, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
+      has_default_value=False, default_value=unicode("", "utf-8"),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='hash_tree_salt', full_name='chromeos_update_engine.PartitionUpdate.hash_tree_salt', index=12,
       number=13, type=12, cpp_type=9, label=1,
-      has_default_value=False, default_value=_b(""),
+      has_default_value=False, default_value="",
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='fec_data_extent', full_name='chromeos_update_engine.PartitionUpdate.fec_data_extent', index=13,
       number=14, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='fec_extent', full_name='chromeos_update_engine.PartitionUpdate.fec_extent', index=14,
       number=15, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='fec_roots', full_name='chromeos_update_engine.PartitionUpdate.fec_roots', index=15,
       number=16, type=13, cpp_type=3, label=1,
       has_default_value=True, default_value=2,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
   ],
-  serialized_options=None,
+  options=None,
   is_extendable=False,
-  syntax='proto2',
   extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=888,
-  serialized_end=1615,
+  serialized_start=880,
+  serialized_end=1607,
 )
 
 
@@ -528,38 +498,35 @@
     _descriptor.FieldDescriptor(
       name='name', full_name='chromeos_update_engine.DynamicPartitionGroup.name', index=0,
       number=1, type=9, cpp_type=9, label=2,
-      has_default_value=False, default_value=_b("").decode('utf-8'),
+      has_default_value=False, default_value=unicode("", "utf-8"),
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='size', full_name='chromeos_update_engine.DynamicPartitionGroup.size', index=1,
       number=2, type=4, cpp_type=4, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='partition_names', full_name='chromeos_update_engine.DynamicPartitionGroup.partition_names', index=2,
       number=3, type=9, cpp_type=9, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
   ],
-  serialized_options=None,
+  options=None,
   is_extendable=False,
-  syntax='proto2',
   extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1617,
-  serialized_end=1693,
+  serialized_start=1609,
+  serialized_end=1685,
 )
 
 
@@ -576,28 +543,18 @@
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
-    _descriptor.FieldDescriptor(
-      name='snapshot_enabled', full_name='chromeos_update_engine.DynamicPartitionMetadata.snapshot_enabled', index=1,
-      number=2, type=8, cpp_type=7, label=1,
-      has_default_value=False, default_value=False,
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
   ],
-  serialized_options=None,
+  options=None,
   is_extendable=False,
-  syntax='proto2',
   extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1695,
-  serialized_end=1810,
+  serialized_start=1687,
+  serialized_end=1776,
 )
 
 
@@ -614,127 +571,124 @@
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='kernel_install_operations', full_name='chromeos_update_engine.DeltaArchiveManifest.kernel_install_operations', index=1,
       number=2, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='block_size', full_name='chromeos_update_engine.DeltaArchiveManifest.block_size', index=2,
       number=3, type=13, cpp_type=3, label=1,
       has_default_value=True, default_value=4096,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='signatures_offset', full_name='chromeos_update_engine.DeltaArchiveManifest.signatures_offset', index=3,
       number=4, type=4, cpp_type=4, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='signatures_size', full_name='chromeos_update_engine.DeltaArchiveManifest.signatures_size', index=4,
       number=5, type=4, cpp_type=4, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='old_kernel_info', full_name='chromeos_update_engine.DeltaArchiveManifest.old_kernel_info', index=5,
       number=6, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='new_kernel_info', full_name='chromeos_update_engine.DeltaArchiveManifest.new_kernel_info', index=6,
       number=7, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='old_rootfs_info', full_name='chromeos_update_engine.DeltaArchiveManifest.old_rootfs_info', index=7,
       number=8, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='new_rootfs_info', full_name='chromeos_update_engine.DeltaArchiveManifest.new_rootfs_info', index=8,
       number=9, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='old_image_info', full_name='chromeos_update_engine.DeltaArchiveManifest.old_image_info', index=9,
       number=10, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='new_image_info', full_name='chromeos_update_engine.DeltaArchiveManifest.new_image_info', index=10,
       number=11, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='minor_version', full_name='chromeos_update_engine.DeltaArchiveManifest.minor_version', index=11,
       number=12, type=13, cpp_type=3, label=1,
       has_default_value=True, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='partitions', full_name='chromeos_update_engine.DeltaArchiveManifest.partitions', index=12,
       number=13, type=11, cpp_type=10, label=3,
       has_default_value=False, default_value=[],
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='max_timestamp', full_name='chromeos_update_engine.DeltaArchiveManifest.max_timestamp', index=13,
       number=14, type=3, cpp_type=2, label=1,
       has_default_value=False, default_value=0,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
     _descriptor.FieldDescriptor(
       name='dynamic_partition_metadata', full_name='chromeos_update_engine.DeltaArchiveManifest.dynamic_partition_metadata', index=14,
       number=15, type=11, cpp_type=10, label=1,
       has_default_value=False, default_value=None,
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
-      serialized_options=None, file=DESCRIPTOR),
+      options=None),
   ],
   extensions=[
   ],
   nested_types=[],
   enum_types=[
   ],
-  serialized_options=None,
+  options=None,
   is_extendable=False,
-  syntax='proto2',
   extension_ranges=[],
-  oneofs=[
-  ],
-  serialized_start=1813,
-  serialized_end=2630,
+  serialized_start=1779,
+  serialized_end=2596,
 )
 
-_SIGNATURES_SIGNATURE.containing_type = _SIGNATURES
+_SIGNATURES_SIGNATURE.containing_type = _SIGNATURES;
 _SIGNATURES.fields_by_name['signatures'].message_type = _SIGNATURES_SIGNATURE
 _INSTALLOPERATION.fields_by_name['type'].enum_type = _INSTALLOPERATION_TYPE
 _INSTALLOPERATION.fields_by_name['src_extents'].message_type = _EXTENT
 _INSTALLOPERATION.fields_by_name['dst_extents'].message_type = _EXTENT
-_INSTALLOPERATION_TYPE.containing_type = _INSTALLOPERATION
+_INSTALLOPERATION_TYPE.containing_type = _INSTALLOPERATION;
 _PARTITIONUPDATE.fields_by_name['new_partition_signature'].message_type = _SIGNATURES_SIGNATURE
 _PARTITIONUPDATE.fields_by_name['old_partition_info'].message_type = _PARTITIONINFO
 _PARTITIONUPDATE.fields_by_name['new_partition_info'].message_type = _PARTITIONINFO
@@ -763,81 +717,68 @@
 DESCRIPTOR.message_types_by_name['DynamicPartitionGroup'] = _DYNAMICPARTITIONGROUP
 DESCRIPTOR.message_types_by_name['DynamicPartitionMetadata'] = _DYNAMICPARTITIONMETADATA
 DESCRIPTOR.message_types_by_name['DeltaArchiveManifest'] = _DELTAARCHIVEMANIFEST
-_sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
-Extent = _reflection.GeneratedProtocolMessageType('Extent', (_message.Message,), {
-  'DESCRIPTOR' : _EXTENT,
-  '__module__' : 'update_metadata_pb2'
+class Extent(_message.Message):
+  __metaclass__ = _reflection.GeneratedProtocolMessageType
+  DESCRIPTOR = _EXTENT
+
   # @@protoc_insertion_point(class_scope:chromeos_update_engine.Extent)
-  })
-_sym_db.RegisterMessage(Extent)
 
-Signatures = _reflection.GeneratedProtocolMessageType('Signatures', (_message.Message,), {
+class Signatures(_message.Message):
+  __metaclass__ = _reflection.GeneratedProtocolMessageType
 
-  'Signature' : _reflection.GeneratedProtocolMessageType('Signature', (_message.Message,), {
-    'DESCRIPTOR' : _SIGNATURES_SIGNATURE,
-    '__module__' : 'update_metadata_pb2'
+  class Signature(_message.Message):
+    __metaclass__ = _reflection.GeneratedProtocolMessageType
+    DESCRIPTOR = _SIGNATURES_SIGNATURE
+
     # @@protoc_insertion_point(class_scope:chromeos_update_engine.Signatures.Signature)
-    })
-  ,
-  'DESCRIPTOR' : _SIGNATURES,
-  '__module__' : 'update_metadata_pb2'
+  DESCRIPTOR = _SIGNATURES
+
   # @@protoc_insertion_point(class_scope:chromeos_update_engine.Signatures)
-  })
-_sym_db.RegisterMessage(Signatures)
-_sym_db.RegisterMessage(Signatures.Signature)
 
-PartitionInfo = _reflection.GeneratedProtocolMessageType('PartitionInfo', (_message.Message,), {
-  'DESCRIPTOR' : _PARTITIONINFO,
-  '__module__' : 'update_metadata_pb2'
+class PartitionInfo(_message.Message):
+  __metaclass__ = _reflection.GeneratedProtocolMessageType
+  DESCRIPTOR = _PARTITIONINFO
+
   # @@protoc_insertion_point(class_scope:chromeos_update_engine.PartitionInfo)
-  })
-_sym_db.RegisterMessage(PartitionInfo)
 
-ImageInfo = _reflection.GeneratedProtocolMessageType('ImageInfo', (_message.Message,), {
-  'DESCRIPTOR' : _IMAGEINFO,
-  '__module__' : 'update_metadata_pb2'
+class ImageInfo(_message.Message):
+  __metaclass__ = _reflection.GeneratedProtocolMessageType
+  DESCRIPTOR = _IMAGEINFO
+
   # @@protoc_insertion_point(class_scope:chromeos_update_engine.ImageInfo)
-  })
-_sym_db.RegisterMessage(ImageInfo)
 
-InstallOperation = _reflection.GeneratedProtocolMessageType('InstallOperation', (_message.Message,), {
-  'DESCRIPTOR' : _INSTALLOPERATION,
-  '__module__' : 'update_metadata_pb2'
+class InstallOperation(_message.Message):
+  __metaclass__ = _reflection.GeneratedProtocolMessageType
+  DESCRIPTOR = _INSTALLOPERATION
+
   # @@protoc_insertion_point(class_scope:chromeos_update_engine.InstallOperation)
-  })
-_sym_db.RegisterMessage(InstallOperation)
 
-PartitionUpdate = _reflection.GeneratedProtocolMessageType('PartitionUpdate', (_message.Message,), {
-  'DESCRIPTOR' : _PARTITIONUPDATE,
-  '__module__' : 'update_metadata_pb2'
+class PartitionUpdate(_message.Message):
+  __metaclass__ = _reflection.GeneratedProtocolMessageType
+  DESCRIPTOR = _PARTITIONUPDATE
+
   # @@protoc_insertion_point(class_scope:chromeos_update_engine.PartitionUpdate)
-  })
-_sym_db.RegisterMessage(PartitionUpdate)
 
-DynamicPartitionGroup = _reflection.GeneratedProtocolMessageType('DynamicPartitionGroup', (_message.Message,), {
-  'DESCRIPTOR' : _DYNAMICPARTITIONGROUP,
-  '__module__' : 'update_metadata_pb2'
+class DynamicPartitionGroup(_message.Message):
+  __metaclass__ = _reflection.GeneratedProtocolMessageType
+  DESCRIPTOR = _DYNAMICPARTITIONGROUP
+
   # @@protoc_insertion_point(class_scope:chromeos_update_engine.DynamicPartitionGroup)
-  })
-_sym_db.RegisterMessage(DynamicPartitionGroup)
 
-DynamicPartitionMetadata = _reflection.GeneratedProtocolMessageType('DynamicPartitionMetadata', (_message.Message,), {
-  'DESCRIPTOR' : _DYNAMICPARTITIONMETADATA,
-  '__module__' : 'update_metadata_pb2'
+class DynamicPartitionMetadata(_message.Message):
+  __metaclass__ = _reflection.GeneratedProtocolMessageType
+  DESCRIPTOR = _DYNAMICPARTITIONMETADATA
+
   # @@protoc_insertion_point(class_scope:chromeos_update_engine.DynamicPartitionMetadata)
-  })
-_sym_db.RegisterMessage(DynamicPartitionMetadata)
 
-DeltaArchiveManifest = _reflection.GeneratedProtocolMessageType('DeltaArchiveManifest', (_message.Message,), {
-  'DESCRIPTOR' : _DELTAARCHIVEMANIFEST,
-  '__module__' : 'update_metadata_pb2'
+class DeltaArchiveManifest(_message.Message):
+  __metaclass__ = _reflection.GeneratedProtocolMessageType
+  DESCRIPTOR = _DELTAARCHIVEMANIFEST
+
   # @@protoc_insertion_point(class_scope:chromeos_update_engine.DeltaArchiveManifest)
-  })
-_sym_db.RegisterMessage(DeltaArchiveManifest)
 
 
-DESCRIPTOR._options = None
-_INSTALLOPERATION_TYPE.values_by_name["MOVE"]._options = None
-_INSTALLOPERATION_TYPE.values_by_name["BSDIFF"]._options = None
+DESCRIPTOR.has_options = True
+DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), 'H\003')
 # @@protoc_insertion_point(module_scope)
diff --git a/service_delegate_android_interface.h b/service_delegate_android_interface.h
index 6bd75b6..5267bb0 100644
--- a/service_delegate_android_interface.h
+++ b/service_delegate_android_interface.h
@@ -47,13 +47,6 @@
       const std::vector<std::string>& key_value_pair_headers,
       brillo::ErrorPtr* error) = 0;
 
-  virtual bool ApplyPayload(
-      int fd,
-      int64_t payload_offset,
-      int64_t payload_size,
-      const std::vector<std::string>& key_value_pair_headers,
-      brillo::ErrorPtr* error) = 0;
-
   // Suspend an ongoing update. Returns true if there was an update ongoing and
   // it was suspended. In case of failure, it returns false and sets |error|
   // accordingly.
diff --git a/sideload_logging_android.cc b/sideload_logging_android.cc
deleted file mode 100644
index f82259f..0000000
--- a/sideload_logging_android.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-//
-// Copyright (C) 2019 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/sideload_logging_android.h"
-
-#include <android-base/logging.h>
-
-namespace chromeos_update_engine {
-
-void SetupAndroidLogging(char* argv[]) {
-  android::base::InitLogging(argv, android::base::StdioLogger);
-}
-
-}  // namespace chromeos_update_engine
diff --git a/sideload_logging_android.h b/sideload_logging_android.h
deleted file mode 100644
index 0bb8714..0000000
--- a/sideload_logging_android.h
+++ /dev/null
@@ -1,25 +0,0 @@
-//
-// Copyright (C) 2019 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.
-//
-
-#pragma once
-
-namespace chromeos_update_engine {
-
-// Some depending modules uses logging functions from android-base.
-// Redirect android-base logging to stdio, which redirects to /tmp/recovery.log.
-void SetupAndroidLogging(char* argv[]);
-
-}  // namespace chromeos_update_engine
diff --git a/sideload_main.cc b/sideload_main.cc
index 29d6f2c..818fa5c 100644
--- a/sideload_main.cc
+++ b/sideload_main.cc
@@ -36,7 +36,6 @@
 #include "update_engine/common/subprocess.h"
 #include "update_engine/common/terminator.h"
 #include "update_engine/common/utils.h"
-#include "update_engine/sideload_logging_android.h"
 #include "update_engine/update_attempter_android.h"
 
 using std::string;
@@ -197,7 +196,6 @@
 
   chromeos_update_engine::Terminator::Init();
   chromeos_update_engine::SetupLogging();
-  chromeos_update_engine::SetupAndroidLogging(argv);
   brillo::FlagHelper::Init(argc, argv, "Update Engine Sideload");
 
   LOG(INFO) << "Update Engine Sideloading starting";
diff --git a/test_config.xml b/test_config.xml
deleted file mode 100644
index 2639e7f..0000000
--- a/test_config.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 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.
--->
-<configuration description="Config to run update_engine_unittests on device">
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-suite-tag" value="apct-native" />
-    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
-        <option name="cleanup" value="true" />
-        <option name="push" value="update_engine_unittests->/data/local/tmp/update_engine_unittests" />
-    </target_preparer>
-
-    <test class="com.android.tradefed.testtype.GTest" >
-        <option name="native-test-device-path" value="/data/local/tmp" />
-        <!-- The following rules avoid test runner from calling the following helper executables
-             directly as gtests. -->
-        <option name="file-exclusion-filter-regex" value=".*/delta_generator$" />
-        <option name="file-exclusion-filter-regex" value=".*/test_http_server$" />
-        <option name="file-exclusion-filter-regex" value=".*/test_subprocess$" />
-        <option name="module-name" value="update_engine_unittests" />
-    </test>
-</configuration>
diff --git a/unittest_key_EC.pem b/unittest_key_EC.pem
deleted file mode 100644
index 9e65a68..0000000
--- a/unittest_key_EC.pem
+++ /dev/null
@@ -1,5 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGaguGj8Yb1KkqKHd
-ISblUsjtOCbzAuVpX81i02sm8FWhRANCAARBnuotwKOsuvjH6iwTDhOAi7Q5pLWz
-xDkZjg2pcfbfi9FFTvLYETas7B2W6fx9PUezUmHTFTDV2JZuMYYFdZOw
------END PRIVATE KEY-----
diff --git a/update_attempter_android.cc b/update_attempter_android.cc
index 5bffc42..1cc8505 100644
--- a/update_attempter_android.cc
+++ b/update_attempter_android.cc
@@ -22,7 +22,6 @@
 #include <utility>
 
 #include <android-base/properties.h>
-#include <android-base/unique_fd.h>
 #include <base/bind.h>
 #include <base/logging.h>
 #include <base/strings/string_number_conversions.h>
@@ -39,7 +38,6 @@
 #include "update_engine/metrics_reporter_interface.h"
 #include "update_engine/metrics_utils.h"
 #include "update_engine/network_selector.h"
-#include "update_engine/payload_consumer/certificate_parser_interface.h"
 #include "update_engine/payload_consumer/delta_performer.h"
 #include "update_engine/payload_consumer/download_action.h"
 #include "update_engine/payload_consumer/file_descriptor.h"
@@ -47,7 +45,6 @@
 #include "update_engine/payload_consumer/filesystem_verifier_action.h"
 #include "update_engine/payload_consumer/payload_constants.h"
 #include "update_engine/payload_consumer/payload_metadata.h"
-#include "update_engine/payload_consumer/payload_verifier.h"
 #include "update_engine/payload_consumer/postinstall_runner_action.h"
 #include "update_engine/update_boot_flags_action.h"
 #include "update_engine/update_status_utils.h"
@@ -58,7 +55,6 @@
 #include "update_engine/libcurl_http_fetcher.h"
 #endif
 
-using android::base::unique_fd;
 using base::Bind;
 using base::Time;
 using base::TimeDelta;
@@ -292,19 +288,6 @@
   return true;
 }
 
-bool UpdateAttempterAndroid::ApplyPayload(
-    int fd,
-    int64_t payload_offset,
-    int64_t payload_size,
-    const vector<string>& key_value_pair_headers,
-    brillo::ErrorPtr* error) {
-  payload_fd_.reset(dup(fd));
-  const string payload_url = "fd://" + std::to_string(payload_fd_.get());
-
-  return ApplyPayload(
-      payload_url, payload_offset, payload_size, key_value_pair_headers, error);
-}
-
 bool UpdateAttempterAndroid::SuspendUpdate(brillo::ErrorPtr* error) {
   if (!processor_->IsRunning())
     return LogAndSetError(error, FROM_HERE, "No ongoing update to suspend.");
@@ -412,16 +395,12 @@
   }
   fd->Close();
 
-  auto payload_verifier = PayloadVerifier::CreateInstanceFromZipPath(
-      constants::kUpdateCertificatesPath);
-  if (!payload_verifier) {
-    return LogAndSetError(error,
-                          FROM_HERE,
-                          "Failed to create the payload verifier from " +
-                              std::string(constants::kUpdateCertificatesPath));
+  string public_key;
+  if (!utils::ReadFile(constants::kUpdatePayloadPublicKeyPath, &public_key)) {
+    return LogAndSetError(error, FROM_HERE, "Failed to read public key.");
   }
-  errorcode = payload_metadata.ValidateMetadataSignature(
-      metadata, "", *payload_verifier);
+  errorcode =
+      payload_metadata.ValidateMetadataSignature(metadata, "", public_key);
   if (errorcode != ErrorCode::kSuccess) {
     return LogAndSetError(error,
                           FROM_HERE,
@@ -604,7 +583,6 @@
       (error_code == ErrorCode::kSuccess ? UpdateStatus::UPDATED_NEED_REBOOT
                                          : UpdateStatus::IDLE);
   SetStatusAndNotify(new_status);
-  payload_fd_.reset();
 
   // The network id is only applicable to one download attempt and once it's
   // done the network id should not be re-used anymore.
@@ -756,15 +734,11 @@
         total_bytes_downloaded;
 
     int download_overhead_percentage = 0;
-    if (total_bytes_downloaded >= payload_size) {
-      CHECK_GT(payload_size, 0);
+    if (current_bytes_downloaded > 0) {
       download_overhead_percentage =
-          (total_bytes_downloaded - payload_size) * 100ull / payload_size;
-    } else {
-      LOG(WARNING) << "Downloaded bytes " << total_bytes_downloaded
-                   << " is smaller than the payload size " << payload_size;
+          (total_bytes_downloaded - current_bytes_downloaded) * 100ull /
+          current_bytes_downloaded;
     }
-
     metrics_reporter_->ReportSuccessfulUpdateMetrics(
         static_cast<int>(attempt_number),
         0,  // update abandoned count
diff --git a/update_attempter_android.h b/update_attempter_android.h
index 7e1949d..c4710ad 100644
--- a/update_attempter_android.h
+++ b/update_attempter_android.h
@@ -23,7 +23,6 @@
 #include <string>
 #include <vector>
 
-#include <android-base/unique_fd.h>
 #include <base/time/time.h>
 
 #include "update_engine/client_library/include/update_engine/update_status.h"
@@ -66,11 +65,6 @@
                     int64_t payload_size,
                     const std::vector<std::string>& key_value_pair_headers,
                     brillo::ErrorPtr* error) override;
-  bool ApplyPayload(int fd,
-                    int64_t payload_offset,
-                    int64_t payload_size,
-                    const std::vector<std::string>& key_value_pair_headers,
-                    brillo::ErrorPtr* error) override;
   bool SuspendUpdate(brillo::ErrorPtr* error) override;
   bool ResumeUpdate(brillo::ErrorPtr* error) override;
   bool CancelUpdate(brillo::ErrorPtr* error) override;
@@ -197,8 +191,6 @@
 
   std::unique_ptr<MetricsReporterInterface> metrics_reporter_;
 
-  ::android::base::unique_fd payload_fd_;
-
   DISALLOW_COPY_AND_ASSIGN(UpdateAttempterAndroid);
 };
 
diff --git a/update_attempter_android_unittest.cc b/update_attempter_android_unittest.cc
index 721b735..3be0b7e 100644
--- a/update_attempter_android_unittest.cc
+++ b/update_attempter_android_unittest.cc
@@ -18,7 +18,6 @@
 
 #include <memory>
 #include <string>
-#include <utility>
 
 #include <android-base/properties.h>
 #include <base/time/time.h>
@@ -58,11 +57,6 @@
     update_attempter_android_.status_ = status;
   }
 
-  void AddPayload(InstallPlan::Payload&& payload) {
-    update_attempter_android_.install_plan_.payloads.push_back(
-        std::move(payload));
-  }
-
   UpdateAttempterAndroid update_attempter_android_{
       &daemon_state_, &prefs_, &boot_control_, &hardware_};
 
@@ -149,13 +143,9 @@
       .Times(1);
   EXPECT_CALL(*metrics_reporter_,
               ReportSuccessfulUpdateMetrics(
-                  2, 0, _, 50, _, _, duration, duration_uptime, 3, _))
+                  2, 0, _, _, _, _, duration, duration_uptime, 3, _))
       .Times(1);
 
-  // Adds a payload of 50 bytes to the InstallPlan.
-  InstallPlan::Payload payload;
-  payload.size = 50;
-  AddPayload(std::move(payload));
   SetUpdateStatus(UpdateStatus::UPDATE_AVAILABLE);
   update_attempter_android_.ProcessingDone(nullptr, ErrorCode::kSuccess);
 
@@ -189,20 +179,15 @@
                   _,
                   _,
                   _,
-                  50,
+                  _,
                   test_utils::DownloadSourceMatcher(total_bytes),
-                  80,
+                  125,
                   _,
                   _,
                   _,
                   _))
       .Times(1);
 
-  // Adds a payload of 50 bytes to the InstallPlan.
-  InstallPlan::Payload payload;
-  payload.size = 50;
-  AddPayload(std::move(payload));
-
   // The first update fails after receiving 50 bytes in total.
   update_attempter_android_.BytesReceived(30, 50, 200);
   update_attempter_android_.ProcessingDone(nullptr, ErrorCode::kError);
@@ -214,7 +199,7 @@
       metrics_utils::GetPersistedValue(kPrefsTotalBytesDownloaded, &prefs_));
 
   // The second update succeeds after receiving 40 bytes, which leads to a
-  // overhead of (90 - 50) / 50 = 80%.
+  // overhead of 50 / 40 = 125%.
   update_attempter_android_.BytesReceived(40, 40, 50);
   update_attempter_android_.ProcessingDone(nullptr, ErrorCode::kSuccess);
   // Both prefs should be cleared.
diff --git a/update_engine.rc b/update_engine.rc
index b9f80fc..90ca4c6 100644
--- a/update_engine.rc
+++ b/update_engine.rc
@@ -2,7 +2,7 @@
     class late_start
     user root
     group root system wakelock inet cache media_rw
-    writepid /dev/cpuset/system-background/tasks /dev/blkio/background/tasks
+    writepid /dev/cpuset/system-background/tasks
     disabled
 
 on property:ro.boot.slot_suffix=*
diff --git a/update_metadata.proto b/update_metadata.proto
index 9bc0d8a..7e8e7d4 100644
--- a/update_metadata.proto
+++ b/update_metadata.proto
@@ -126,17 +126,8 @@
 
 message Signatures {
   message Signature {
-    optional uint32 version = 1 [deprecated = true];
+    optional uint32 version = 1;
     optional bytes data = 2;
-
-    // The DER encoded signature size of EC keys is nondeterministic for
-    // different input of sha256 hash. However, we need the size of the
-    // serialized signatures protobuf string to be fixed before signing;
-    // because this size is part of the content to be signed. Therefore, we
-    // always pad the signature data to the maximum possible signature size of
-    // a given key. And the payload verifier will truncate the signature to
-    // its correct size based on the value of |unpadded_signature_size|.
-    optional fixed32 unpadded_signature_size = 3;
   }
   repeated Signature signatures = 1;
 }
@@ -311,12 +302,6 @@
   // - If an updatable group is in the manifest but not on the device, the group
   //   is added to the device.
   repeated DynamicPartitionGroup groups = 1;
-
-  // Whether dynamic partitions have snapshots during the update. If this is
-  // set to true, the update_engine daemon creates snapshots for all dynamic
-  // partitions if possible. If this is unset, the update_engine daemon MUST
-  // NOT create snapshots for dynamic partitions.
-  optional bool snapshot_enabled = 2;
 }
 
 message DeltaArchiveManifest {