|
16 | 16 |
|
17 | 17 | #include "cuttlefish/host/commands/cvd/cli/commands/start.h" |
18 | 18 |
|
| 19 | +#include <fcntl.h> |
19 | 20 | #include <signal.h> // IWYU pragma: keep |
20 | 21 | #include <stddef.h> |
21 | 22 | #include <stdlib.h> |
|
40 | 41 | #include "absl/strings/str_join.h" |
41 | 42 | #include "absl/strings/str_split.h" |
42 | 43 |
|
| 44 | +#include "cuttlefish/common/libs/fs/shared_fd.h" |
43 | 45 | #include "cuttlefish/common/libs/utils/contains.h" |
44 | 46 | #include "cuttlefish/common/libs/utils/files.h" |
45 | 47 | #include "cuttlefish/flag_parser/flag.h" |
@@ -337,6 +339,21 @@ Result<void> CvdStartCommandHandler::Handle(const CommandRequest& request) { |
337 | 339 | return CF_ERR(NoGroupMessage(request)); |
338 | 340 | } |
339 | 341 |
|
| 342 | + if (request.Selectors().instance_names && |
| 343 | + request.Selectors().instance_names->size() == 1) { |
| 344 | + auto [instance, group] = |
| 345 | + CF_EXPECT(selector::SelectInstance(instance_manager_, request)); |
| 346 | + |
| 347 | + if (instance.State() == cvd::INSTANCE_STATE_STOPPED && |
| 348 | + group.StartTime() != TimeStamp{}) { |
| 349 | + CF_EXPECT(LaunchSingleInstance(instance, group, request)); |
| 350 | + return {}; |
| 351 | + } else { |
| 352 | + VLOG(1) << "Instance is not in stopped state. Proceeding with " |
| 353 | + "normal group start."; |
| 354 | + } |
| 355 | + } |
| 356 | + |
340 | 357 | CF_EXPECT(ConsumeDaemonModeFlag(subcmd_args)); |
341 | 358 | subcmd_args.push_back("--daemon=true"); |
342 | 359 |
|
@@ -472,6 +489,72 @@ Result<void> CvdStartCommandHandler::LaunchDeviceInterruptible( |
472 | 489 | return {}; |
473 | 490 | } |
474 | 491 |
|
| 492 | +Result<void> CvdStartCommandHandler::LaunchSingleInstance( |
| 493 | + LocalInstance& instance, LocalInstanceGroup& group, |
| 494 | + const CommandRequest& request) { |
| 495 | + auto bin_path = group.HostArtifactsPath() + "/bin/run_cvd"; |
| 496 | + cvd_common::Envs run_cvd_envs = request.Env(); |
| 497 | + run_cvd_envs[kCuttlefishInstanceEnvVarName] = std::to_string(instance.Id()); |
| 498 | + run_cvd_envs["HOME"] = group.HomeDir(); |
| 499 | + run_cvd_envs[kAndroidHostOut] = group.HostArtifactsPath(); |
| 500 | + run_cvd_envs[kAndroidProductOut] = group.ProductOutPath(); |
| 501 | + run_cvd_envs[kAndroidSoongHostOut] = group.HostArtifactsPath(); |
| 502 | + run_cvd_envs[kCvdMarkEnv] = "true"; |
| 503 | + |
| 504 | + ConstructCommandParam construct_cmd_param{.bin_path = bin_path, |
| 505 | + .home = group.HomeDir(), |
| 506 | + .args = cvd_common::Args{}, |
| 507 | + .envs = run_cvd_envs, |
| 508 | + .working_dir = CurrentDirectory(), |
| 509 | + .command_name = "run_cvd"}; |
| 510 | + |
| 511 | + Command command = CF_EXPECT(ConstructCommand(construct_cmd_param)); |
| 512 | + command.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, |
| 513 | + Subprocess::StdIOChannel::kStdErr); |
| 514 | + SharedFD dev_null = SharedFD::Open("/dev/null", O_RDONLY); |
| 515 | + if (dev_null->IsOpen()) { |
| 516 | + command.RedirectStdIO(Subprocess::StdIOChannel::kStdIn, dev_null); |
| 517 | + } else { |
| 518 | + LOG(ERROR) << "Failed to open /dev/null: " << dev_null->StrError(); |
| 519 | + } |
| 520 | + |
| 521 | + auto symlink_config_res = SymlinkPreviousConfig(group.HomeDir()); |
| 522 | + if (!symlink_config_res.ok()) { |
| 523 | + LOG(ERROR) << "Failed to symlink the config file at system wide home: " |
| 524 | + << symlink_config_res.error(); |
| 525 | + } |
| 526 | + |
| 527 | + auto set_instance_state = [&group, &instance](cvd::InstanceState state) { |
| 528 | + for (auto& inst : group.Instances()) { |
| 529 | + if (inst.Id() == instance.Id()) { |
| 530 | + inst.SetState(state); |
| 531 | + break; |
| 532 | + } |
| 533 | + } |
| 534 | + }; |
| 535 | + |
| 536 | + set_instance_state(cvd::INSTANCE_STATE_STARTING); |
| 537 | + group.SetStartTime(CvdServerClock::now()); |
| 538 | + CF_EXPECT(instance_manager_.UpdateInstanceGroup(group)); |
| 539 | + |
| 540 | + Result<void> start_res = |
| 541 | + LaunchDevice(std::move(command), group, run_cvd_envs, request); |
| 542 | + |
| 543 | + if (!start_res.ok()) { |
| 544 | + set_instance_state(cvd::INSTANCE_STATE_BOOT_FAILED); |
| 545 | + CF_EXPECT(instance_manager_.UpdateInstanceGroup(group)); |
| 546 | + return start_res; |
| 547 | + } |
| 548 | + |
| 549 | + set_instance_state(cvd::INSTANCE_STATE_RUNNING); |
| 550 | + CF_EXPECT(instance_manager_.UpdateInstanceGroup(group)); |
| 551 | + |
| 552 | + auto group_json = CF_EXPECT(group.FetchStatus()); |
| 553 | + std::cout << group_json.toStyledString(); |
| 554 | + |
| 555 | + return {}; |
| 556 | +} |
| 557 | + |
475 | 558 | std::vector<HelpParagraph> CvdStartCommandHandler::Description() const { |
476 | 559 | std::vector<HelpParagraph> description; |
477 | 560 | description.emplace_back( |
|
0 commit comments