Breaking up disk_flags.cc: Move out GeneratePersistentBootconfig

Bug: 281125332
Test: launch_cvd --noresume
Change-Id: I23d343771ff04e572d3eda4e0bd1b0098ea4d845
diff --git a/host/commands/assemble_cvd/Android.bp b/host/commands/assemble_cvd/Android.bp
index 0faea7f..b69ac93 100644
--- a/host/commands/assemble_cvd/Android.bp
+++ b/host/commands/assemble_cvd/Android.bp
@@ -25,6 +25,7 @@
         "boot_config.cc",
         "boot_image_utils.cc",
         "clean.cc",
+        "disk/generate_persistent_bootconfig.cpp",
         "disk/kernel_ramdisk_repacker.cpp",
         "disk_builder.cpp",
         "disk_flags.cc",
diff --git a/host/commands/assemble_cvd/disk/disk.h b/host/commands/assemble_cvd/disk/disk.h
index 2fa794d..0784402 100644
--- a/host/commands/assemble_cvd/disk/disk.h
+++ b/host/commands/assemble_cvd/disk/disk.h
@@ -30,4 +30,11 @@
                  KernelRamdiskRepacker>
 KernelRamdiskRepackerComponent();
 
+class GeneratePersistentBootconfig : public SetupFeature {};
+
+fruit::Component<fruit::Required<const CuttlefishConfig,
+                                 const CuttlefishConfig::InstanceSpecific>,
+                 GeneratePersistentBootconfig>
+GeneratePersistentBootconfigComponent();
+
 }  // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/disk/generate_persistent_bootconfig.cpp b/host/commands/assemble_cvd/disk/generate_persistent_bootconfig.cpp
new file mode 100644
index 0000000..4624ed4
--- /dev/null
+++ b/host/commands/assemble_cvd/disk/generate_persistent_bootconfig.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2023 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 "host/commands/assemble_cvd/disk/disk.h"
+
+#include <string>
+#include <unordered_set>
+
+#include <fruit/fruit.h>
+
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/files.h"
+#include "common/libs/utils/result.h"
+#include "common/libs/utils/size_utils.h"
+#include "host/libs/config/bootconfig_args.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/data_image.h"
+#include "host/libs/config/feature.h"
+#include "host/libs/vm_manager/gem5_manager.h"
+
+// Taken from external/avb/avbtool.py; this define is not in the headers
+#define MAX_AVB_METADATA_SIZE 69632ul
+
+namespace cuttlefish {
+
+class GeneratePersistentBootconfigImpl : public GeneratePersistentBootconfig {
+ public:
+  INJECT(GeneratePersistentBootconfigImpl(
+      const CuttlefishConfig& config,
+      const CuttlefishConfig::InstanceSpecific& instance))
+      : config_(config), instance_(instance) {}
+
+  // SetupFeature
+  std::string Name() const override { return "GeneratePersistentBootconfig"; }
+  bool Enabled() const override { return (!instance_.protected_vm()); }
+
+ private:
+  std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
+  Result<void> ResultSetup() override {
+    //  Cuttlefish for the time being won't be able to support OTA from a
+    //  non-bootconfig kernel to a bootconfig-kernel (or vice versa) IF the
+    //  device is stopped (via stop_cvd). This is rarely an issue since OTA
+    //  testing run on cuttlefish is done within one launch cycle of the device.
+    //  If this ever becomes an issue, this code will have to be rewritten.
+    if (!instance_.bootconfig_supported()) {
+      return {};
+    }
+    const auto bootconfig_path = instance_.persistent_bootconfig_path();
+    if (!FileExists(bootconfig_path)) {
+      CF_EXPECT(CreateBlankImage(bootconfig_path, 1 /* mb */, "none"),
+                "Failed to create image at " << bootconfig_path);
+    }
+
+    auto bootconfig_fd = SharedFD::Open(bootconfig_path, O_RDWR);
+    CF_EXPECT(bootconfig_fd->IsOpen(),
+              "Unable to open bootconfig file: " << bootconfig_fd->StrError());
+
+    const auto bootconfig_args =
+        CF_EXPECT(BootconfigArgsFromConfig(config_, instance_));
+    const auto bootconfig =
+        CF_EXPECT(BootconfigArgsString(bootconfig_args, "\n")) + "\n";
+
+    LOG(DEBUG) << "bootconfig size is " << bootconfig.size();
+    ssize_t bytesWritten = WriteAll(bootconfig_fd, bootconfig);
+    CF_EXPECT(WriteAll(bootconfig_fd, bootconfig) == bootconfig.size(),
+              "Failed to write bootconfig to \"" << bootconfig_path << "\"");
+    LOG(DEBUG) << "Bootconfig parameters from vendor boot image and config are "
+               << ReadFile(bootconfig_path);
+
+    CF_EXPECT(bootconfig_fd->Truncate(bootconfig.size()) == 0,
+              "`truncate --size=" << bootconfig.size() << " bytes "
+                                  << bootconfig_path
+                                  << "` failed:" << bootconfig_fd->StrError());
+
+    if (config_.vm_manager() == vm_manager::Gem5Manager::name()) {
+      const off_t bootconfig_size_bytes_gem5 =
+          AlignToPowerOf2(bytesWritten, PARTITION_SIZE_SHIFT);
+      CF_EXPECT(bootconfig_fd->Truncate(bootconfig_size_bytes_gem5) == 0);
+      bootconfig_fd->Close();
+    } else {
+      bootconfig_fd->Close();
+      const off_t bootconfig_size_bytes = AlignToPowerOf2(
+          MAX_AVB_METADATA_SIZE + bootconfig.size(), PARTITION_SIZE_SHIFT);
+
+      auto avbtool_path = HostBinaryPath("avbtool");
+      Command bootconfig_hash_footer_cmd(avbtool_path);
+      bootconfig_hash_footer_cmd.AddParameter("add_hash_footer");
+      bootconfig_hash_footer_cmd.AddParameter("--image");
+      bootconfig_hash_footer_cmd.AddParameter(bootconfig_path);
+      bootconfig_hash_footer_cmd.AddParameter("--partition_size");
+      bootconfig_hash_footer_cmd.AddParameter(bootconfig_size_bytes);
+      bootconfig_hash_footer_cmd.AddParameter("--partition_name");
+      bootconfig_hash_footer_cmd.AddParameter("bootconfig");
+      bootconfig_hash_footer_cmd.AddParameter("--key");
+      bootconfig_hash_footer_cmd.AddParameter(
+          DefaultHostArtifactsPath("etc/cvd_avb_testkey.pem"));
+      bootconfig_hash_footer_cmd.AddParameter("--algorithm");
+      bootconfig_hash_footer_cmd.AddParameter("SHA256_RSA4096");
+      int success = bootconfig_hash_footer_cmd.Start().Wait();
+      CF_EXPECT(
+          success == 0,
+          "Unable to run append hash footer. Exited with status " << success);
+    }
+    return {};
+  }
+
+  const CuttlefishConfig& config_;
+  const CuttlefishConfig::InstanceSpecific& instance_;
+};
+
+fruit::Component<fruit::Required<const CuttlefishConfig,
+                                 const CuttlefishConfig::InstanceSpecific>,
+                 GeneratePersistentBootconfig>
+GeneratePersistentBootconfigComponent() {
+  return fruit::createComponent()
+      .addMultibinding<SetupFeature, GeneratePersistentBootconfigImpl>()
+      .bind<GeneratePersistentBootconfig, GeneratePersistentBootconfigImpl>();
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/assemble_cvd/disk_flags.cc b/host/commands/assemble_cvd/disk_flags.cc
index 538b1db..fa6a584 100644
--- a/host/commands/assemble_cvd/disk_flags.cc
+++ b/host/commands/assemble_cvd/disk_flags.cc
@@ -44,10 +44,6 @@
 #include "host/libs/config/instance_nums.h"
 #include "host/libs/vm_manager/gem5_manager.h"
 
-
-// Taken from external/avb/avbtool.py; this define is not in the headers
-#define MAX_AVB_METADATA_SIZE 69632ul
-
 DECLARE_string(system_image_dir);
 
 DEFINE_string(boot_image, CF_DEFAULTS_BOOT_IMAGE,
@@ -577,95 +573,6 @@
   KernelRamdiskRepacker& bir_;
 };
 
-class GeneratePersistentBootconfig : public SetupFeature {
- public:
-  INJECT(GeneratePersistentBootconfig(
-      const CuttlefishConfig& config,
-      const CuttlefishConfig::InstanceSpecific& instance))
-      : config_(config), instance_(instance) {}
-
-  // SetupFeature
-  std::string Name() const override {
-    return "GeneratePersistentBootconfig";
-  }
-  bool Enabled() const override {
-    return (!instance_.protected_vm());
-  }
-
- private:
-  std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
-  Result<void> ResultSetup() override {
-    //  Cuttlefish for the time being won't be able to support OTA from a
-    //  non-bootconfig kernel to a bootconfig-kernel (or vice versa) IF the
-    //  device is stopped (via stop_cvd). This is rarely an issue since OTA
-    //  testing run on cuttlefish is done within one launch cycle of the device.
-    //  If this ever becomes an issue, this code will have to be rewritten.
-    if(!instance_.bootconfig_supported()) {
-      return {};
-    }
-    const auto bootconfig_path = instance_.persistent_bootconfig_path();
-    if (!FileExists(bootconfig_path)) {
-      CF_EXPECT(CreateBlankImage(bootconfig_path, 1 /* mb */, "none"),
-                "Failed to create image at " << bootconfig_path);
-    }
-
-    auto bootconfig_fd = SharedFD::Open(bootconfig_path, O_RDWR);
-    CF_EXPECT(bootconfig_fd->IsOpen(),
-              "Unable to open bootconfig file: " << bootconfig_fd->StrError());
-
-    const auto bootconfig_args =
-        CF_EXPECT(BootconfigArgsFromConfig(config_, instance_));
-    const auto bootconfig =
-        CF_EXPECT(BootconfigArgsString(bootconfig_args, "\n")) + "\n";
-
-    LOG(DEBUG) << "bootconfig size is " << bootconfig.size();
-    ssize_t bytesWritten = WriteAll(bootconfig_fd, bootconfig);
-    CF_EXPECT(WriteAll(bootconfig_fd, bootconfig) == bootconfig.size(),
-              "Failed to write bootconfig to \"" << bootconfig_path << "\"");
-    LOG(DEBUG) << "Bootconfig parameters from vendor boot image and config are "
-               << ReadFile(bootconfig_path);
-
-    CF_EXPECT(bootconfig_fd->Truncate(bootconfig.size()) == 0,
-              "`truncate --size=" << bootconfig.size() << " bytes "
-                                  << bootconfig_path
-                                  << "` failed:" << bootconfig_fd->StrError());
-
-    if (config_.vm_manager() == Gem5Manager::name()) {
-      const off_t bootconfig_size_bytes_gem5 =
-          AlignToPowerOf2(bytesWritten, PARTITION_SIZE_SHIFT);
-      CF_EXPECT(bootconfig_fd->Truncate(bootconfig_size_bytes_gem5) == 0);
-      bootconfig_fd->Close();
-    } else {
-      bootconfig_fd->Close();
-      const off_t bootconfig_size_bytes = AlignToPowerOf2(
-          MAX_AVB_METADATA_SIZE + bootconfig.size(), PARTITION_SIZE_SHIFT);
-
-      auto avbtool_path = HostBinaryPath("avbtool");
-      Command bootconfig_hash_footer_cmd(avbtool_path);
-      bootconfig_hash_footer_cmd.AddParameter("add_hash_footer");
-      bootconfig_hash_footer_cmd.AddParameter("--image");
-      bootconfig_hash_footer_cmd.AddParameter(bootconfig_path);
-      bootconfig_hash_footer_cmd.AddParameter("--partition_size");
-      bootconfig_hash_footer_cmd.AddParameter(bootconfig_size_bytes);
-      bootconfig_hash_footer_cmd.AddParameter("--partition_name");
-      bootconfig_hash_footer_cmd.AddParameter("bootconfig");
-      bootconfig_hash_footer_cmd.AddParameter("--key");
-      bootconfig_hash_footer_cmd.AddParameter(
-          DefaultHostArtifactsPath("etc/cvd_avb_testkey.pem"));
-      bootconfig_hash_footer_cmd.AddParameter("--algorithm");
-      bootconfig_hash_footer_cmd.AddParameter("SHA256_RSA4096");
-      int success = bootconfig_hash_footer_cmd.Start().Wait();
-      CF_EXPECT(
-          success == 0,
-          "Unable to run append hash footer. Exited with status " << success);
-    }
-    return {};
-  }
-
-  const CuttlefishConfig& config_;
-  const CuttlefishConfig::InstanceSpecific& instance_;
-};
-
 class GeneratePersistentVbmeta : public SetupFeature {
  public:
   INJECT(GeneratePersistentVbmeta(
@@ -1063,7 +970,7 @@
       .addMultibinding<SetupFeature, InitializePstore>()
       .addMultibinding<SetupFeature, InitializeSdCard>()
       .addMultibinding<SetupFeature, InitializeFactoryResetProtected>()
-      .addMultibinding<SetupFeature, GeneratePersistentBootconfig>()
+      .install(GeneratePersistentBootconfigComponent)
       .addMultibinding<SetupFeature, GeneratePersistentVbmeta>()
       .addMultibinding<SetupFeature, InitializeInstanceCompositeDisk>()
       .install(InitializeDataImageComponent)