Separated server_loop.cpp into pieces
The file is to get longer. Separated the file proactively into:
1. header
2. The method implementation that existed
3. The new methods for snapshot-related features
Bug: N/A
Test: m -j 50
cvd start && cvd stop
Change-Id: I8e5b95f287011c39b7528160b1c24d0f06a88eb4
diff --git a/host/commands/run_cvd/Android.bp b/host/commands/run_cvd/Android.bp
index d6b9440..1269e87 100644
--- a/host/commands/run_cvd/Android.bp
+++ b/host/commands/run_cvd/Android.bp
@@ -47,6 +47,8 @@
"reporting.cpp",
"process_monitor.cc",
"server_loop.cpp",
+ "server_loop_impl.cpp",
+ "server_loop_impl_snapshot.cpp",
"validate.cpp",
],
shared_libs: [
diff --git a/host/commands/run_cvd/server_loop.cpp b/host/commands/run_cvd/server_loop.cpp
index e137553..0f9c21e 100644
--- a/host/commands/run_cvd/server_loop.cpp
+++ b/host/commands/run_cvd/server_loop.cpp
@@ -16,384 +16,22 @@
#include "host/commands/run_cvd/server_loop.h"
-#include <unistd.h>
-
-#include <algorithm>
-#include <memory>
-#include <string>
-
#include <fruit/fruit.h>
-#include <gflags/gflags.h>
-#include "common/libs/fs/shared_buf.h"
-#include "common/libs/utils/files.h"
-#include "common/libs/utils/subprocess.h"
-#include "host/commands/run_cvd/runner_defs.h"
-#include "host/libs/command_util/util.h"
-#include "host/libs/config/command_source.h"
+#include "host/commands/run_cvd/server_loop_impl.h"
#include "host/libs/config/cuttlefish_config.h"
-#include "host/libs/config/data_image.h"
#include "host/libs/config/feature.h"
#include "host/libs/config/inject.h"
-#include "run_cvd.pb.h"
namespace cuttlefish {
-namespace {
-
-bool CreateQcowOverlay(const std::string& crosvm_path,
- const std::string& backing_file,
- const std::string& output_overlay_path) {
- Command crosvm_qcow2_cmd(crosvm_path);
- crosvm_qcow2_cmd.AddParameter("create_qcow2");
- crosvm_qcow2_cmd.AddParameter("--backing-file");
- crosvm_qcow2_cmd.AddParameter(backing_file);
- crosvm_qcow2_cmd.AddParameter(output_overlay_path);
- int success = crosvm_qcow2_cmd.Start().Wait();
- if (success != 0) {
- LOG(ERROR) << "Unable to run crosvm create_qcow2. Exited with status "
- << success;
- return false;
- }
- return true;
-}
-
-class ServerLoopImpl : public ServerLoop,
- public SetupFeature,
- public LateInjected {
- public:
- INJECT(ServerLoopImpl(const CuttlefishConfig& config,
- const CuttlefishConfig::InstanceSpecific& instance))
- : config_(config), instance_(instance) {}
-
- Result<void> LateInject(fruit::Injector<>& injector) override {
- command_sources_ = injector.getMultibindings<CommandSource>();
- return {};
- }
-
- // ServerLoop
- Result<void> Run() override {
- // Monitor and restart host processes supporting the CVD
- ProcessMonitor::Properties process_monitor_properties;
- process_monitor_properties.RestartSubprocesses(
- instance_.restart_subprocesses());
-
- for (auto& command_source : command_sources_) {
- if (command_source->Enabled()) {
- auto commands = CF_EXPECT(command_source->Commands());
- process_monitor_properties.AddCommands(std::move(commands));
- }
- }
-
- ProcessMonitor process_monitor(std::move(process_monitor_properties));
-
- CF_EXPECT(process_monitor.StartAndMonitorProcesses());
-
- while (true) {
- // TODO: use select to handle simultaneous connections.
- auto client = SharedFD::Accept(*server_);
- while (client->IsOpen()) {
- auto launcher_action_with_info_result =
- ReadLauncherActionFromFd(client);
- if (!launcher_action_with_info_result.ok()) {
- LOG(ERROR) << "Reading launcher command from monitor failed.";
- LOG(DEBUG) << launcher_action_with_info_result.error().Trace();
- break;
- }
- auto launcher_action = std::move(*launcher_action_with_info_result);
- if (launcher_action.action != LauncherAction::kExtended) {
- HandleActionWithNoData(launcher_action.action, client,
- process_monitor);
- continue;
- }
- auto result = HandleExtended(launcher_action, client);
- if (!result.ok()) {
- LOG(ERROR) << "Failed to handle suspend request.";
- LOG(DEBUG) << result.error().Trace();
- }
- // extended operations for now are 1 time request-response exchanges.
- // thus, we will close the client FD.
- client->Close();
- }
- }
- }
-
- // SetupFeature
- std::string Name() const override { return "ServerLoop"; }
-
- private:
- bool Enabled() const override { return true; }
- std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
- Result<void> ResultSetup() override {
- auto launcher_monitor_path = instance_.launcher_monitor_socket_path();
- server_ = SharedFD::SocketLocalServer(launcher_monitor_path.c_str(), false,
- SOCK_STREAM, 0666);
- CF_EXPECTF(server_->IsOpen(), "Error when opening launcher server: {}",
- server_->StrError());
- return {};
- }
-
- Result<void> HandleExtended(const LauncherActionInfo& action_info,
- const SharedFD& client) {
- CF_EXPECT(action_info.action == LauncherAction::kExtended);
- switch (action_info.type) {
- case ExtendedActionType::kSuspend: {
- CF_EXPECT(HandleSuspend(action_info.serialized_data, client));
- return {};
- }
- case ExtendedActionType::kResume: {
- CF_EXPECT(HandleResume(action_info.serialized_data, client));
- return {};
- }
- default:
- return CF_ERR("Unsupported ExtendedActionType");
- }
- }
-
- Result<void> HandleSuspend(const std::string& serialized_data,
- const SharedFD& client) {
- run_cvd::ExtendedLauncherAction extended_action;
- CF_EXPECT(extended_action.ParseFromString(serialized_data),
- "Failed to load ExtendedLauncherAction proto.");
- CF_EXPECT_EQ(extended_action.actions_case(),
- run_cvd::ExtendedLauncherAction::ActionsCase::kSuspend);
- LOG(INFO) << "Suspend is requested but not yet implemented.";
- auto response = LauncherResponse::kSuccess;
- CF_EXPECT_EQ(client->Write(&response, sizeof(response)), sizeof(response),
- "Failed to wrote the suspend response.");
- return {};
- }
-
- Result<void> HandleResume(const std::string& serialized_data,
- const SharedFD& client) {
- run_cvd::ExtendedLauncherAction extended_action;
- CF_EXPECT(extended_action.ParseFromString(serialized_data),
- "Failed to load ExtendedLauncherAction proto.");
- CF_EXPECT_EQ(extended_action.actions_case(),
- run_cvd::ExtendedLauncherAction::ActionsCase::kResume);
- LOG(INFO) << "Resume is requested but not yet implemented.";
- auto response = LauncherResponse::kSuccess;
- CF_EXPECT_EQ(client->Write(&response, sizeof(response)), sizeof(response),
- "Failed to wrote the suspend response.");
- return {};
- }
-
- void HandleActionWithNoData(const LauncherAction action,
- const SharedFD& client,
- ProcessMonitor& process_monitor) {
- switch (action) {
- case LauncherAction::kStop: {
- auto stop = process_monitor.StopMonitoredProcesses();
- if (stop.ok()) {
- auto response = LauncherResponse::kSuccess;
- client->Write(&response, sizeof(response));
- std::exit(0);
- } else {
- LOG(ERROR) << "Failed to stop subprocesses:\n"
- << stop.error().Message();
- LOG(DEBUG) << "Failed to stop subprocesses:\n"
- << stop.error().Trace();
- auto response = LauncherResponse::kError;
- client->Write(&response, sizeof(response));
- }
- break;
- }
- case LauncherAction::kStatus: {
- // TODO(schuffelen): Return more information on a side channel
- auto response = LauncherResponse::kSuccess;
- client->Write(&response, sizeof(response));
- break;
- }
- case LauncherAction::kPowerwash: {
- LOG(INFO) << "Received a Powerwash request from the monitor socket";
- const auto& disks = instance_.virtual_disk_paths();
- auto overlay = instance_.PerInstancePath("overlay.img");
- if (std::find(disks.begin(), disks.end(), overlay) == disks.end()) {
- LOG(ERROR) << "Powerwash unsupported with --use_overlay=false";
- auto response = LauncherResponse::kError;
- client->Write(&response, sizeof(response));
- break;
- }
-
- auto stop = process_monitor.StopMonitoredProcesses();
- if (!stop.ok()) {
- LOG(ERROR) << "Stopping processes failed:\n"
- << stop.error().Message();
- LOG(DEBUG) << "Stopping processes failed:\n" << stop.error().Trace();
- auto response = LauncherResponse::kError;
- client->Write(&response, sizeof(response));
- break;
- }
- if (!PowerwashFiles()) {
- LOG(ERROR) << "Powerwashing files failed.";
- auto response = LauncherResponse::kError;
- client->Write(&response, sizeof(response));
- break;
- }
- auto response = LauncherResponse::kSuccess;
- client->Write(&response, sizeof(response));
-
- RestartRunCvd(client->UNMANAGED_Dup());
- // RestartRunCvd should not return, so something went wrong.
- response = LauncherResponse::kError;
- client->Write(&response, sizeof(response));
- LOG(FATAL) << "run_cvd in a bad state";
- break;
- }
- case LauncherAction::kRestart: {
- auto stop = process_monitor.StopMonitoredProcesses();
- if (!stop.ok()) {
- LOG(ERROR) << "Stopping processes failed:\n"
- << stop.error().Message();
- LOG(DEBUG) << "Stopping processes failed:\n" << stop.error().Trace();
- auto response = LauncherResponse::kError;
- client->Write(&response, sizeof(response));
- break;
- }
- DeleteFifos();
-
- auto response = LauncherResponse::kSuccess;
- client->Write(&response, sizeof(response));
- RestartRunCvd(client->UNMANAGED_Dup());
- // RestartRunCvd should not return, so something went wrong.
- response = LauncherResponse::kError;
- client->Write(&response, sizeof(response));
- LOG(FATAL) << "run_cvd in a bad state";
- break;
- }
- default:
- LOG(ERROR) << "Unrecognized launcher action: "
- << static_cast<char>(action);
- auto response = LauncherResponse::kError;
- client->Write(&response, sizeof(response));
- break;
- }
- }
-
- void DeleteFifos() {
- // TODO(schuffelen): Create these FIFOs in assemble_cvd instead of run_cvd.
- std::vector<std::string> pipes = {
- instance_.kernel_log_pipe_name(),
- instance_.console_in_pipe_name(),
- instance_.console_out_pipe_name(),
- instance_.logcat_pipe_name(),
- instance_.PerInstanceInternalPath("keymaster_fifo_vm.in"),
- instance_.PerInstanceInternalPath("keymaster_fifo_vm.out"),
- instance_.PerInstanceInternalPath("keymint_fifo_vm.in"),
- instance_.PerInstanceInternalPath("keymint_fifo_vm.out"),
- instance_.PerInstanceInternalPath("gatekeeper_fifo_vm.in"),
- instance_.PerInstanceInternalPath("gatekeeper_fifo_vm.out"),
- instance_.PerInstanceInternalPath("oemlock_fifo_vm.in"),
- instance_.PerInstanceInternalPath("oemlock_fifo_vm.out"),
- instance_.PerInstanceInternalPath("bt_fifo_vm.in"),
- instance_.PerInstanceInternalPath("bt_fifo_vm.out"),
- instance_.PerInstanceInternalPath("uwb_fifo_vm.in"),
- instance_.PerInstanceInternalPath("uwb_fifo_vm.out"),
- instance_.PerInstanceInternalPath("gnsshvc_fifo_vm.in"),
- instance_.PerInstanceInternalPath("gnsshvc_fifo_vm.out"),
- instance_.PerInstanceInternalPath("locationhvc_fifo_vm.in"),
- instance_.PerInstanceInternalPath("locationhvc_fifo_vm.out"),
- instance_.PerInstanceInternalPath("confui_fifo_vm.in"),
- instance_.PerInstanceInternalPath("confui_fifo_vm.out"),
- };
- for (const auto& pipe : pipes) {
- unlink(pipe.c_str());
- }
- }
-
- bool PowerwashFiles() {
- DeleteFifos();
-
- // TODO(b/269669405): Figure out why this file is not being deleted
- unlink(instance_.PerInstanceInternalUdsPath("crosvm_control.sock").c_str());
-
- // TODO(schuffelen): Clean up duplication with assemble_cvd
- unlink(instance_.PerInstancePath("NVChip").c_str());
-
- auto kregistry_path = instance_.access_kregistry_path();
- unlink(kregistry_path.c_str());
- CreateBlankImage(kregistry_path, 2 /* mb */, "none");
-
- auto hwcomposer_pmem_path = instance_.hwcomposer_pmem_path();
- unlink(hwcomposer_pmem_path.c_str());
- CreateBlankImage(hwcomposer_pmem_path, 2 /* mb */, "none");
-
- auto pstore_path = instance_.pstore_path();
- unlink(pstore_path.c_str());
- CreateBlankImage(pstore_path, 2 /* mb */, "none");
-
- auto sdcard_path = instance_.sdcard_path();
- auto sdcard_size = FileSize(sdcard_path);
- unlink(sdcard_path.c_str());
- // round up
- auto sdcard_mb_size = (sdcard_size + (1 << 20) - 1) / (1 << 20);
- LOG(DEBUG) << "Size in mb is " << sdcard_mb_size;
- CreateBlankImage(sdcard_path, sdcard_mb_size, "sdcard");
-
- struct OverlayFile {
- std::string name;
- std::string composite_disk_path;
-
- OverlayFile(std::string name, std::string composite_disk_path)
- : name(std::move(name)), composite_disk_path(std::move(composite_disk_path)) {}
- };
- std::vector<OverlayFile> overlay_files{
- OverlayFile("overlay.img", instance_.os_composite_disk_path())
- };
- if (instance_.ap_boot_flow() != CuttlefishConfig::InstanceSpecific::APBootFlow::None) {
- overlay_files.emplace_back(
- OverlayFile("ap_overlay.img", instance_.ap_composite_disk_path()));
- }
- for (const auto& overlay_file : overlay_files) {
- auto overlay_path = instance_.PerInstancePath(overlay_file.name.c_str());
- auto composite_disk_path = overlay_file.composite_disk_path.c_str();
-
- unlink(overlay_path.c_str());
- if (!CreateQcowOverlay(instance_.crosvm_binary(), composite_disk_path, overlay_path)) {
- LOG(ERROR) << "CreateQcowOverlay failed";
- return false;
- }
- }
- return true;
- }
-
- void RestartRunCvd(int notification_fd) {
- auto config_path = config_.AssemblyPath("cuttlefish_config.json");
- auto followup_stdin = SharedFD::MemfdCreate("pseudo_stdin");
- WriteAll(followup_stdin, config_path + "\n");
- followup_stdin->LSeek(0, SEEK_SET);
- followup_stdin->UNMANAGED_Dup2(0);
-
- auto argv_vec = gflags::GetArgvs();
- std::unique_ptr<char*[]> argv(new char*[argv_vec.size() + 2]);
- for (size_t i = 0; i < argv_vec.size(); i++) {
- argv[i] = argv_vec[i].data();
- }
- // Will take precedence over any earlier arguments.
- std::string reboot_notification =
- "-reboot_notification_fd=" + std::to_string(notification_fd);
- argv[argv_vec.size()] = reboot_notification.data();
- argv[argv_vec.size() + 1] = nullptr;
-
- execv("/proc/self/exe", argv.get());
- // execve should not return, so something went wrong.
- PLOG(ERROR) << "execv returned: ";
- }
-
- const CuttlefishConfig& config_;
- const CuttlefishConfig::InstanceSpecific& instance_;
- std::vector<CommandSource*> command_sources_;
- SharedFD server_;
-};
-
-} // namespace
-
ServerLoop::~ServerLoop() = default;
fruit::Component<fruit::Required<const CuttlefishConfig,
const CuttlefishConfig::InstanceSpecific>,
ServerLoop>
serverLoopComponent() {
+ using run_cvd_impl::ServerLoopImpl;
return fruit::createComponent()
.bind<ServerLoop, ServerLoopImpl>()
.addMultibinding<LateInjected, ServerLoopImpl>()
diff --git a/host/commands/run_cvd/server_loop.h b/host/commands/run_cvd/server_loop.h
index 9a116d2..b8ae076 100644
--- a/host/commands/run_cvd/server_loop.h
+++ b/host/commands/run_cvd/server_loop.h
@@ -18,8 +18,6 @@
#include <fruit/fruit.h>
-#include "common/libs/fs/shared_fd.h"
-#include "host/commands/run_cvd/process_monitor.h"
#include "host/libs/config/cuttlefish_config.h"
namespace cuttlefish {
diff --git a/host/commands/run_cvd/server_loop_impl.cpp b/host/commands/run_cvd/server_loop_impl.cpp
new file mode 100644
index 0000000..57f4274
--- /dev/null
+++ b/host/commands/run_cvd/server_loop_impl.cpp
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2017 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/run_cvd/server_loop_impl.h"
+
+#include <unistd.h>
+
+#include <memory>
+#include <string>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <gflags/gflags.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/subprocess.h"
+#include "host/commands/run_cvd/process_monitor.h"
+#include "host/commands/run_cvd/runner_defs.h"
+#include "host/libs/command_util/util.h"
+#include "host/libs/config/command_source.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/data_image.h"
+#include "host/libs/config/inject.h"
+
+namespace cuttlefish {
+namespace run_cvd_impl {
+
+bool ServerLoopImpl::CreateQcowOverlay(const std::string& crosvm_path,
+ const std::string& backing_file,
+ const std::string& output_overlay_path) {
+ Command crosvm_qcow2_cmd(crosvm_path);
+ crosvm_qcow2_cmd.AddParameter("create_qcow2");
+ crosvm_qcow2_cmd.AddParameter("--backing-file");
+ crosvm_qcow2_cmd.AddParameter(backing_file);
+ crosvm_qcow2_cmd.AddParameter(output_overlay_path);
+ int success = crosvm_qcow2_cmd.Start().Wait();
+ if (success != 0) {
+ LOG(ERROR) << "Unable to run crosvm create_qcow2. Exited with status "
+ << success;
+ return false;
+ }
+ return true;
+}
+
+ServerLoopImpl::ServerLoopImpl(
+ const CuttlefishConfig& config,
+ const CuttlefishConfig::InstanceSpecific& instance)
+ : config_(config), instance_(instance) {}
+
+Result<void> ServerLoopImpl::LateInject(fruit::Injector<>& injector) {
+ command_sources_ = injector.getMultibindings<CommandSource>();
+ return {};
+}
+
+Result<void> ServerLoopImpl::Run() {
+ // Monitor and restart host processes supporting the CVD
+ ProcessMonitor::Properties process_monitor_properties;
+ process_monitor_properties.RestartSubprocesses(
+ instance_.restart_subprocesses());
+
+ for (auto& command_source : command_sources_) {
+ if (command_source->Enabled()) {
+ auto commands = CF_EXPECT(command_source->Commands());
+ process_monitor_properties.AddCommands(std::move(commands));
+ }
+ }
+ ProcessMonitor process_monitor(std::move(process_monitor_properties));
+
+ CF_EXPECT(process_monitor.StartAndMonitorProcesses());
+
+ while (true) {
+ // TODO: use select to handle simultaneous connections.
+ auto client = SharedFD::Accept(*server_);
+ while (client->IsOpen()) {
+ auto launcher_action_with_info_result = ReadLauncherActionFromFd(client);
+ if (!launcher_action_with_info_result.ok()) {
+ LOG(ERROR) << "Reading launcher command from monitor failed.";
+ LOG(DEBUG) << launcher_action_with_info_result.error().Trace();
+ break;
+ }
+ auto launcher_action = std::move(*launcher_action_with_info_result);
+ if (launcher_action.action != LauncherAction::kExtended) {
+ HandleActionWithNoData(launcher_action.action, client, process_monitor);
+ continue;
+ }
+ auto result = HandleExtended(launcher_action, client);
+ if (!result.ok()) {
+ LOG(ERROR) << "Failed to handle suspend request.";
+ LOG(DEBUG) << result.error().Trace();
+ }
+ // extended operations for now are 1 time request-response exchanges.
+ // thus, we will close the client FD.
+ client->Close();
+ }
+ }
+}
+
+Result<void> ServerLoopImpl::ResultSetup() {
+ auto launcher_monitor_path = instance_.launcher_monitor_socket_path();
+ server_ = SharedFD::SocketLocalServer(launcher_monitor_path.c_str(), false,
+ SOCK_STREAM, 0666);
+ CF_EXPECTF(server_->IsOpen(), "Error when opening launcher server: {}",
+ server_->StrError());
+ return {};
+}
+
+void ServerLoopImpl::HandleActionWithNoData(const LauncherAction action,
+ const SharedFD& client,
+ ProcessMonitor& process_monitor) {
+ switch (action) {
+ case LauncherAction::kStop: {
+ auto stop = process_monitor.StopMonitoredProcesses();
+ if (stop.ok()) {
+ auto response = LauncherResponse::kSuccess;
+ client->Write(&response, sizeof(response));
+ std::exit(0);
+ } else {
+ LOG(ERROR) << "Failed to stop subprocesses:\n"
+ << stop.error().Message();
+ LOG(DEBUG) << "Failed to stop subprocesses:\n" << stop.error().Trace();
+ auto response = LauncherResponse::kError;
+ client->Write(&response, sizeof(response));
+ }
+ break;
+ }
+ case LauncherAction::kStatus: {
+ // TODO(schuffelen): Return more information on a side channel
+ auto response = LauncherResponse::kSuccess;
+ client->Write(&response, sizeof(response));
+ break;
+ }
+ case LauncherAction::kPowerwash: {
+ LOG(INFO) << "Received a Powerwash request from the monitor socket";
+ const auto& disks = instance_.virtual_disk_paths();
+ auto overlay = instance_.PerInstancePath("overlay.img");
+ if (std::find(disks.begin(), disks.end(), overlay) == disks.end()) {
+ LOG(ERROR) << "Powerwash unsupported with --use_overlay=false";
+ auto response = LauncherResponse::kError;
+ client->Write(&response, sizeof(response));
+ break;
+ }
+
+ auto stop = process_monitor.StopMonitoredProcesses();
+ if (!stop.ok()) {
+ LOG(ERROR) << "Stopping processes failed:\n" << stop.error().Message();
+ LOG(DEBUG) << "Stopping processes failed:\n" << stop.error().Trace();
+ auto response = LauncherResponse::kError;
+ client->Write(&response, sizeof(response));
+ break;
+ }
+ if (!PowerwashFiles()) {
+ LOG(ERROR) << "Powerwashing files failed.";
+ auto response = LauncherResponse::kError;
+ client->Write(&response, sizeof(response));
+ break;
+ }
+ auto response = LauncherResponse::kSuccess;
+ client->Write(&response, sizeof(response));
+
+ RestartRunCvd(client->UNMANAGED_Dup());
+ // RestartRunCvd should not return, so something went wrong.
+ response = LauncherResponse::kError;
+ client->Write(&response, sizeof(response));
+ LOG(FATAL) << "run_cvd in a bad state";
+ break;
+ }
+ case LauncherAction::kRestart: {
+ auto stop = process_monitor.StopMonitoredProcesses();
+ if (!stop.ok()) {
+ LOG(ERROR) << "Stopping processes failed:\n" << stop.error().Message();
+ LOG(DEBUG) << "Stopping processes failed:\n" << stop.error().Trace();
+ auto response = LauncherResponse::kError;
+ client->Write(&response, sizeof(response));
+ break;
+ }
+ DeleteFifos();
+
+ auto response = LauncherResponse::kSuccess;
+ client->Write(&response, sizeof(response));
+ RestartRunCvd(client->UNMANAGED_Dup());
+ // RestartRunCvd should not return, so something went wrong.
+ response = LauncherResponse::kError;
+ client->Write(&response, sizeof(response));
+ LOG(FATAL) << "run_cvd in a bad state";
+ break;
+ }
+ default:
+ LOG(ERROR) << "Unrecognized launcher action: "
+ << static_cast<char>(action);
+ auto response = LauncherResponse::kError;
+ client->Write(&response, sizeof(response));
+ break;
+ }
+}
+
+void ServerLoopImpl::DeleteFifos() {
+ // TODO(schuffelen): Create these FIFOs in assemble_cvd instead of run_cvd.
+ std::vector<std::string> pipes = {
+ instance_.kernel_log_pipe_name(),
+ instance_.console_in_pipe_name(),
+ instance_.console_out_pipe_name(),
+ instance_.logcat_pipe_name(),
+ instance_.PerInstanceInternalPath("keymaster_fifo_vm.in"),
+ instance_.PerInstanceInternalPath("keymaster_fifo_vm.out"),
+ instance_.PerInstanceInternalPath("keymint_fifo_vm.in"),
+ instance_.PerInstanceInternalPath("keymint_fifo_vm.out"),
+ instance_.PerInstanceInternalPath("gatekeeper_fifo_vm.in"),
+ instance_.PerInstanceInternalPath("gatekeeper_fifo_vm.out"),
+ instance_.PerInstanceInternalPath("oemlock_fifo_vm.in"),
+ instance_.PerInstanceInternalPath("oemlock_fifo_vm.out"),
+ instance_.PerInstanceInternalPath("bt_fifo_vm.in"),
+ instance_.PerInstanceInternalPath("bt_fifo_vm.out"),
+ instance_.PerInstanceInternalPath("uwb_fifo_vm.in"),
+ instance_.PerInstanceInternalPath("uwb_fifo_vm.out"),
+ instance_.PerInstanceInternalPath("gnsshvc_fifo_vm.in"),
+ instance_.PerInstanceInternalPath("gnsshvc_fifo_vm.out"),
+ instance_.PerInstanceInternalPath("locationhvc_fifo_vm.in"),
+ instance_.PerInstanceInternalPath("locationhvc_fifo_vm.out"),
+ instance_.PerInstanceInternalPath("confui_fifo_vm.in"),
+ instance_.PerInstanceInternalPath("confui_fifo_vm.out"),
+ };
+ for (const auto& pipe : pipes) {
+ unlink(pipe.c_str());
+ }
+}
+
+bool ServerLoopImpl::PowerwashFiles() {
+ DeleteFifos();
+
+ // TODO(b/269669405): Figure out why this file is not being deleted
+ unlink(instance_.PerInstanceInternalUdsPath("crosvm_control.sock").c_str());
+
+ // TODO(schuffelen): Clean up duplication with assemble_cvd
+ unlink(instance_.PerInstancePath("NVChip").c_str());
+
+ auto kregistry_path = instance_.access_kregistry_path();
+ unlink(kregistry_path.c_str());
+ CreateBlankImage(kregistry_path, 2 /* mb */, "none");
+
+ auto hwcomposer_pmem_path = instance_.hwcomposer_pmem_path();
+ unlink(hwcomposer_pmem_path.c_str());
+ CreateBlankImage(hwcomposer_pmem_path, 2 /* mb */, "none");
+
+ auto pstore_path = instance_.pstore_path();
+ unlink(pstore_path.c_str());
+ CreateBlankImage(pstore_path, 2 /* mb */, "none");
+
+ auto sdcard_path = instance_.sdcard_path();
+ auto sdcard_size = FileSize(sdcard_path);
+ unlink(sdcard_path.c_str());
+ // round up
+ auto sdcard_mb_size = (sdcard_size + (1 << 20) - 1) / (1 << 20);
+ LOG(DEBUG) << "Size in mb is " << sdcard_mb_size;
+ CreateBlankImage(sdcard_path, sdcard_mb_size, "sdcard");
+
+ struct OverlayFile {
+ std::string name;
+ std::string composite_disk_path;
+
+ OverlayFile(std::string name, std::string composite_disk_path)
+ : name(std::move(name)),
+ composite_disk_path(std::move(composite_disk_path)) {}
+ };
+ std::vector<OverlayFile> overlay_files{
+ OverlayFile("overlay.img", instance_.os_composite_disk_path())};
+ if (instance_.ap_boot_flow() !=
+ CuttlefishConfig::InstanceSpecific::APBootFlow::None) {
+ overlay_files.emplace_back(
+ OverlayFile("ap_overlay.img", instance_.ap_composite_disk_path()));
+ }
+ for (const auto& overlay_file : overlay_files) {
+ auto overlay_path = instance_.PerInstancePath(overlay_file.name.c_str());
+ auto composite_disk_path = overlay_file.composite_disk_path.c_str();
+
+ unlink(overlay_path.c_str());
+ if (!CreateQcowOverlay(instance_.crosvm_binary(), composite_disk_path,
+ overlay_path)) {
+ LOG(ERROR) << "CreateQcowOverlay failed";
+ return false;
+ }
+ }
+ return true;
+}
+
+void ServerLoopImpl::RestartRunCvd(int notification_fd) {
+ auto config_path = config_.AssemblyPath("cuttlefish_config.json");
+ auto followup_stdin = SharedFD::MemfdCreate("pseudo_stdin");
+ WriteAll(followup_stdin, config_path + "\n");
+ followup_stdin->LSeek(0, SEEK_SET);
+ followup_stdin->UNMANAGED_Dup2(0);
+
+ auto argv_vec = gflags::GetArgvs();
+ std::unique_ptr<char*[]> argv(new char*[argv_vec.size() + 2]);
+ for (size_t i = 0; i < argv_vec.size(); i++) {
+ argv[i] = argv_vec[i].data();
+ }
+ // Will take precedence over any earlier arguments.
+ std::string reboot_notification =
+ "-reboot_notification_fd=" + std::to_string(notification_fd);
+ argv[argv_vec.size()] = reboot_notification.data();
+ argv[argv_vec.size() + 1] = nullptr;
+
+ execv("/proc/self/exe", argv.get());
+ // execve should not return, so something went wrong.
+ PLOG(ERROR) << "execv returned: ";
+}
+
+} // namespace run_cvd_impl
+} // namespace cuttlefish
diff --git a/host/commands/run_cvd/server_loop_impl.h b/host/commands/run_cvd/server_loop_impl.h
new file mode 100644
index 0000000..80770fc
--- /dev/null
+++ b/host/commands/run_cvd/server_loop_impl.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 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
+
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include <fruit/fruit.h>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/result.h"
+#include "host/commands/run_cvd/process_monitor.h"
+#include "host/commands/run_cvd/runner_defs.h"
+#include "host/commands/run_cvd/server_loop.h"
+#include "host/libs/command_util/util.h"
+#include "host/libs/config/command_source.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/feature.h"
+#include "host/libs/config/inject.h"
+
+namespace cuttlefish {
+namespace run_cvd_impl {
+
+class ServerLoopImpl : public ServerLoop,
+ public SetupFeature,
+ public LateInjected {
+ public:
+ INJECT(ServerLoopImpl(const CuttlefishConfig& config,
+ const CuttlefishConfig::InstanceSpecific& instance));
+
+ Result<void> LateInject(fruit::Injector<>& injector) override;
+
+ // ServerLoop
+ Result<void> Run() override;
+
+ // SetupFeature
+ std::string Name() const override { return "ServerLoop"; }
+
+ private:
+ bool Enabled() const override { return true; }
+ std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
+ Result<void> ResultSetup() override;
+ Result<void> HandleExtended(const LauncherActionInfo& action_info,
+ const SharedFD& client);
+ Result<void> HandleSuspend(const std::string& serialized_data,
+ const SharedFD& client);
+ Result<void> HandleResume(const std::string& serialized_data,
+ const SharedFD& client);
+
+ void HandleActionWithNoData(const LauncherAction action,
+ const SharedFD& client,
+ ProcessMonitor& process_monitor);
+
+ void DeleteFifos();
+ bool PowerwashFiles();
+ void RestartRunCvd(int notification_fd);
+ static bool CreateQcowOverlay(const std::string& crosvm_path,
+ const std::string& backing_file,
+ const std::string& output_overlay_path);
+
+ const CuttlefishConfig& config_;
+ const CuttlefishConfig::InstanceSpecific& instance_;
+ std::vector<CommandSource*> command_sources_;
+ SharedFD server_;
+};
+
+} // namespace run_cvd_impl
+} // namespace cuttlefish
diff --git a/host/commands/run_cvd/server_loop_impl_snapshot.cpp b/host/commands/run_cvd/server_loop_impl_snapshot.cpp
new file mode 100644
index 0000000..ddd31d9
--- /dev/null
+++ b/host/commands/run_cvd/server_loop_impl_snapshot.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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/run_cvd/server_loop_impl.h"
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/result.h"
+#include "host/commands/run_cvd/runner_defs.h"
+#include "host/libs/command_util/util.h"
+#include "run_cvd.pb.h"
+
+namespace cuttlefish {
+namespace run_cvd_impl {
+
+Result<void> ServerLoopImpl::HandleExtended(
+ const LauncherActionInfo& action_info, const SharedFD& client) {
+ CF_EXPECT(action_info.action == LauncherAction::kExtended);
+ switch (action_info.type) {
+ case ExtendedActionType::kSuspend: {
+ CF_EXPECT(HandleSuspend(action_info.serialized_data, client));
+ return {};
+ }
+ case ExtendedActionType::kResume: {
+ CF_EXPECT(HandleResume(action_info.serialized_data, client));
+ return {};
+ }
+ default:
+ return CF_ERR("Unsupported ExtendedActionType");
+ }
+}
+
+Result<void> ServerLoopImpl::HandleSuspend(const std::string& serialized_data,
+ const SharedFD& client) {
+ run_cvd::ExtendedLauncherAction extended_action;
+ CF_EXPECT(extended_action.ParseFromString(serialized_data),
+ "Failed to load ExtendedLauncherAction proto.");
+ CF_EXPECT_EQ(extended_action.actions_case(),
+ run_cvd::ExtendedLauncherAction::ActionsCase::kSuspend);
+ LOG(INFO) << "Suspend is requested but not yet implemented.";
+ auto response = LauncherResponse::kSuccess;
+ CF_EXPECT_EQ(client->Write(&response, sizeof(response)), sizeof(response),
+ "Failed to wrote the suspend response.");
+ return {};
+}
+
+Result<void> ServerLoopImpl::HandleResume(const std::string& serialized_data,
+ const SharedFD& client) {
+ run_cvd::ExtendedLauncherAction extended_action;
+ CF_EXPECT(extended_action.ParseFromString(serialized_data),
+ "Failed to load ExtendedLauncherAction proto.");
+ CF_EXPECT_EQ(extended_action.actions_case(),
+ run_cvd::ExtendedLauncherAction::ActionsCase::kResume);
+ LOG(INFO) << "Resume is requested but not yet implemented.";
+ auto response = LauncherResponse::kSuccess;
+ CF_EXPECT_EQ(client->Write(&response, sizeof(response)), sizeof(response),
+ "Failed to wrote the suspend response.");
+ return {};
+}
+
+} // namespace run_cvd_impl
+} // namespace cuttlefish