2121#include < stdlib.h>
2222#include < string.h>
2323#include < unistd.h>
24+ #include < fcntl.h>
2425
2526#include < algorithm>
2627#include < cstdlib>
4041#include " absl/strings/str_join.h"
4142#include " absl/strings/str_split.h"
4243
44+ #include " cuttlefish/common/libs/fs/shared_fd.h"
4345#include " cuttlefish/common/libs/utils/contains.h"
4446#include " cuttlefish/common/libs/utils/files.h"
4547#include " cuttlefish/flag_parser/flag.h"
@@ -313,7 +315,8 @@ Result<std::vector<Flag>> GetCvdInternalStartFlags(
313315
314316CvdStartCommandHandler::CvdStartCommandHandler (
315317 InstanceManager& instance_manager)
316- : instance_manager_(instance_manager) {}
318+ : instance_manager_(instance_manager) {
319+ }
317320
318321static Result<void > ConsumeDaemonModeFlag (cvd_common::Args& args) {
319322 bool daemon = true ;
@@ -337,6 +340,19 @@ Result<void> CvdStartCommandHandler::Handle(const CommandRequest& request) {
337340 return CF_ERR (NoGroupMessage (request));
338341 }
339342
343+ if (request.Selectors ().instance_names ) {
344+ auto [instance, group] =
345+ CF_EXPECT (selector::SelectInstance (instance_manager_, request));
346+
347+ auto config_path =
348+ group.AssemblyDir () + " /cuttlefish_config.json" ;
349+ if (FileExists (config_path)) {
350+ return LaunchSingleInstance (instance, group, request);
351+ } else {
352+ LOG (INFO ) << " Group configuration does not exist on disk. Proceeding with normal group start." ;
353+ }
354+ }
355+
340356 CF_EXPECT (ConsumeDaemonModeFlag (subcmd_args));
341357 subcmd_args.push_back (" --daemon=true" );
342358
@@ -477,6 +493,74 @@ Result<void> CvdStartCommandHandler::LaunchDeviceInterruptible(
477493 return {};
478494}
479495
496+ Result<void > CvdStartCommandHandler::LaunchSingleInstance (
497+ LocalInstance& instance, LocalInstanceGroup& group,
498+ const CommandRequest& request) {
499+ auto bin_path = group.HostArtifactsPath () + " /bin/run_cvd" ;
500+ cvd_common::Envs run_cvd_envs = request.Env ();
501+ run_cvd_envs[kCuttlefishInstanceEnvVarName ] = std::to_string (instance.id ());
502+ run_cvd_envs[" HOME" ] = group.HomeDir ();
503+ run_cvd_envs[kAndroidHostOut ] = group.HostArtifactsPath ();
504+ run_cvd_envs[kAndroidProductOut ] = group.ProductOutPath ();
505+ run_cvd_envs[kAndroidSoongHostOut ] = group.HostArtifactsPath ();
506+ run_cvd_envs[kCvdMarkEnv ] = " true" ;
507+
508+ ConstructCommandParam construct_cmd_param{.bin_path = bin_path,
509+ .home = group.HomeDir (),
510+ .args = cvd_common::Args{},
511+ .envs = run_cvd_envs,
512+ .working_dir = CurrentDirectory (),
513+ .command_name = " run_cvd" };
514+
515+ Command command = CF_EXPECT (ConstructCommand (construct_cmd_param));
516+ command.RedirectStdIO (Subprocess::StdIOChannel::kStdOut ,
517+ Subprocess::StdIOChannel::kStdErr );
518+ SharedFD dev_null = SharedFD::Open (" /dev/null" , O_RDONLY );
519+ if (dev_null->IsOpen ()) {
520+ command.RedirectStdIO (Subprocess::StdIOChannel::kStdIn , dev_null);
521+ } else {
522+ LOG (ERROR ) << " Failed to open /dev/null: " << dev_null->StrError ();
523+ }
524+
525+ auto symlink_config_res = SymlinkPreviousConfig (group.HomeDir ());
526+ if (!symlink_config_res.ok ()) {
527+ LOG (ERROR ) << " Failed to symlink the config file at system wide home: "
528+ << symlink_config_res.error ();
529+ }
530+
531+ auto set_instance_state = [&group, &instance](cvd::InstanceState state) {
532+ for (auto & inst : group.Instances ()) {
533+ if (inst.id () == instance.id ()) {
534+ inst.set_state (state);
535+ break ;
536+ }
537+ }
538+ };
539+
540+ set_instance_state (cvd::INSTANCE_STATE_STARTING );
541+ group.SetStartTime (CvdServerClock::now ());
542+ CF_EXPECT (instance_manager_.UpdateInstanceGroup (group));
543+
544+ Result<void > start_res =
545+ LaunchDevice (std::move (command), group, run_cvd_envs, request);
546+
547+ if (!start_res.ok ()) {
548+ set_instance_state (cvd::INSTANCE_STATE_BOOT_FAILED );
549+ CF_EXPECT (instance_manager_.UpdateInstanceGroup (group));
550+ return start_res;
551+ }
552+
553+ set_instance_state (cvd::INSTANCE_STATE_RUNNING );
554+ CF_EXPECT (instance_manager_.UpdateInstanceGroup (group));
555+
556+ auto group_json = CF_EXPECT (group.FetchStatus ());
557+ std::cout << group_json.toStyledString ();
558+
559+ return {};
560+ }
561+
562+
563+
480564std::vector<HelpParagraph> CvdStartCommandHandler::Description () const {
481565 std::vector<HelpParagraph> description;
482566 description.emplace_back (
0 commit comments