Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
99 changes: 99 additions & 0 deletions base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "cuttlefish/host/commands/cvd/cli/commands/start.h"

#include <fcntl.h>
#include <signal.h> // IWYU pragma: keep
#include <stddef.h>
#include <stdlib.h>
Expand All @@ -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"
Expand Down Expand Up @@ -327,6 +329,21 @@ static Result<void> ConsumeDaemonModeFlag(cvd_common::Args& args) {
return {};
}

static bool HasUnsafeFlagsForBypass(const std::vector<std::string>& args) {
std::vector<std::string> args_copy = args;
bool daemon = true;
std::string report_anonymous = "";
std::vector<Flag> 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<void> CvdStartCommandHandler::Handle(const CommandRequest& request) {
std::vector<std::string> subcmd_args = request.SubcommandArguments();
CF_EXPECT(!GetConfigPath(subcmd_args).has_value(),
Expand All @@ -337,6 +354,22 @@ Result<void> 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");

Expand Down Expand Up @@ -477,6 +510,72 @@ Result<void> CvdStartCommandHandler::LaunchDeviceInterruptible(
return {};
}

Result<void> 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<void> 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<HelpParagraph> CvdStartCommandHandler::Description() const {
std::vector<HelpParagraph> description;
description.emplace_back(
Expand Down
4 changes: 4 additions & 0 deletions base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ class CvdStartCommandHandler : public CvdCommandHandler {
bool RequiresDeviceExists() const override { return true; }

private:
Result<void> LaunchSingleInstance(LocalInstance& instance,
LocalInstanceGroup& group,
const CommandRequest& request);

Result<void> LaunchDevice(Command command, LocalInstanceGroup& group,
const cvd_common::Envs& envs,
const CommandRequest& request);
Expand Down
Loading