From 070f386a384994dbfe1046fb61e1fef21f844068 Mon Sep 17 00:00:00 2001 From: My Name Date: Fri, 12 Jun 2026 10:01:14 +0000 Subject: [PATCH] Update cvd start to handle single instances --- .../commands/cvd/cli/commands/BUILD.bazel | 1 + .../host/commands/cvd/cli/commands/start.cpp | 99 +++++++++++++++++++ .../host/commands/cvd/cli/commands/start.h | 4 + 3 files changed, 104 insertions(+) diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/BUILD.bazel b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/BUILD.bazel index 22da76db6bc..d21df5bf69d 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/BUILD.bazel @@ -390,6 +390,7 @@ cf_cc_library( hdrs = ["start.h"], clang_format_enabled = False, deps = [ + "//cuttlefish/common/libs/fs", "//cuttlefish/common/libs/utils:contains", "//cuttlefish/common/libs/utils:files", "//cuttlefish/common/libs/utils:json", diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp index 69ec23356d3..585397abf3c 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp @@ -16,6 +16,7 @@ #include "cuttlefish/host/commands/cvd/cli/commands/start.h" +#include #include // IWYU pragma: keep #include #include @@ -40,6 +41,7 @@ #include "absl/strings/str_join.h" #include "absl/strings/str_split.h" +#include "cuttlefish/common/libs/fs/shared_fd.h" #include "cuttlefish/common/libs/utils/contains.h" #include "cuttlefish/common/libs/utils/files.h" #include "cuttlefish/flag_parser/flag.h" @@ -327,6 +329,21 @@ static Result ConsumeDaemonModeFlag(cvd_common::Args& args) { return {}; } +static bool HasUnsafeFlagsForBypass(const std::vector& args) { + std::vector args_copy = args; + bool daemon = true; + std::string report_anonymous = ""; + std::vector safe_flags = { + GflagsCompatFlag("daemon", daemon), + GflagsCompatFlag("report_anonymous_usage_stats", report_anonymous), + }; + auto res = ConsumeFlags(safe_flags, args_copy); + if (!res.ok()) { + return true; + } + return !args_copy.empty(); +} + Result CvdStartCommandHandler::Handle(const CommandRequest& request) { std::vector subcmd_args = request.SubcommandArguments(); CF_EXPECT(!GetConfigPath(subcmd_args).has_value(), @@ -337,6 +354,22 @@ Result CvdStartCommandHandler::Handle(const CommandRequest& request) { return CF_ERR(NoGroupMessage(request)); } + if (request.Selectors().instance_names && + request.Selectors().instance_names->size() == 1) { + auto [instance, group] = + CF_EXPECT(selector::SelectInstance(instance_manager_, request)); + + if (instance.State() == cvd::INSTANCE_STATE_STOPPED && + group.StartTime() != TimeStamp{} && + !HasUnsafeFlagsForBypass(subcmd_args)) { + CF_EXPECT(LaunchSingleInstance(instance, group, request)); + return {}; + } else { + VLOG(1) << "Instance is not in stopped state. Proceeding with " + "normal group start."; + } + } + CF_EXPECT(ConsumeDaemonModeFlag(subcmd_args)); subcmd_args.push_back("--daemon=true"); @@ -477,6 +510,72 @@ Result CvdStartCommandHandler::LaunchDeviceInterruptible( return {}; } +Result CvdStartCommandHandler::LaunchSingleInstance( + LocalInstance& instance, LocalInstanceGroup& group, + const CommandRequest& request) { + auto bin_path = group.HostArtifactsPath() + "/bin/run_cvd"; + cvd_common::Envs run_cvd_envs = request.Env(); + run_cvd_envs[kCuttlefishInstanceEnvVarName] = std::to_string(instance.Id()); + run_cvd_envs["HOME"] = group.HomeDir(); + run_cvd_envs[kAndroidHostOut] = group.HostArtifactsPath(); + run_cvd_envs[kAndroidProductOut] = group.ProductOutPath(); + run_cvd_envs[kAndroidSoongHostOut] = group.HostArtifactsPath(); + run_cvd_envs[kCvdMarkEnv] = "true"; + + ConstructCommandParam construct_cmd_param{.bin_path = bin_path, + .home = group.HomeDir(), + .args = cvd_common::Args{}, + .envs = run_cvd_envs, + .working_dir = CurrentDirectory(), + .command_name = "run_cvd"}; + + Command command = CF_EXPECT(ConstructCommand(construct_cmd_param)); + command.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, + Subprocess::StdIOChannel::kStdErr); + SharedFD dev_null = SharedFD::Open("/dev/null", O_RDONLY); + if (dev_null->IsOpen()) { + command.RedirectStdIO(Subprocess::StdIOChannel::kStdIn, dev_null); + } else { + LOG(ERROR) << "Failed to open /dev/null: " << dev_null->StrError(); + } + + auto symlink_config_res = SymlinkPreviousConfig(group.HomeDir()); + if (!symlink_config_res.ok()) { + LOG(ERROR) << "Failed to symlink the config file at system wide home: " + << symlink_config_res.error(); + } + + auto set_instance_state = [&group, &instance](cvd::InstanceState state) { + for (auto& inst : group.Instances()) { + if (inst.Id() == instance.Id()) { + inst.SetState(state); + break; + } + } + }; + + set_instance_state(cvd::INSTANCE_STATE_STARTING); + group.SetStartTime(CvdServerClock::now()); + CF_EXPECT(instance_manager_.UpdateInstanceGroup(group)); + + Result start_res = + LaunchDevice(std::move(command), group, run_cvd_envs, request); + + if (!start_res.ok()) { + set_instance_state(cvd::INSTANCE_STATE_BOOT_FAILED); + CF_EXPECT(instance_manager_.UpdateInstanceGroup(group)); + return start_res; + } + + set_instance_state(cvd::INSTANCE_STATE_RUNNING); + CF_EXPECT(instance_manager_.UpdateInstanceGroup(group)); + + auto group_json = CF_EXPECT(group.FetchStatus()); + std::cout << group_json.toStyledString(); + + return {}; +} + std::vector CvdStartCommandHandler::Description() const { std::vector description; description.emplace_back( diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.h b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.h index 6b836cb0078..6479ce40088 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.h +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.h @@ -43,6 +43,10 @@ class CvdStartCommandHandler : public CvdCommandHandler { bool RequiresDeviceExists() const override { return true; } private: + Result LaunchSingleInstance(LocalInstance& instance, + LocalInstanceGroup& group, + const CommandRequest& request); + Result LaunchDevice(Command command, LocalInstanceGroup& group, const cvd_common::Envs& envs, const CommandRequest& request);