Make qemu the client in the qemu monitor connection

The launcher creates a unix socket and waits for qemu to connect to it
with a timeout. This allows the launcher to ensure qemu started
successfully before launching more processes. Only the launcher can
stop qemu through the monitor, stop_cvd will kill it with the fuser
command if it can't talk to the launcher.

Bug: 111453282
Test: local & gce
Change-Id: I589b14bb07741fbd9c0810c2b73fdb026f2517f9
diff --git a/host/libs/vm_manager/cf_qemu.sh b/host/libs/vm_manager/cf_qemu.sh
index 4bca7c2..7316643 100755
--- a/host/libs/vm_manager/cf_qemu.sh
+++ b/host/libs/vm_manager/cf_qemu.sh
@@ -46,7 +46,7 @@
     -display none
     -no-user-config
     -nodefaults
-    -chardev "socket,id=charmonitor,path=${monitor_path:-${default_dir}/qemu_monitor.sock},server,nowait"
+    -chardev "socket,id=charmonitor,path=${monitor_path:-${default_dir}/qemu_monitor.sock},nowait"
     -mon "chardev=charmonitor,id=monitor,mode=control"
     -rtc "base=utc"
     -no-shutdown
diff --git a/host/libs/vm_manager/libvirt_manager.cpp b/host/libs/vm_manager/libvirt_manager.cpp
index 96415e0..90e221d 100644
--- a/host/libs/vm_manager/libvirt_manager.cpp
+++ b/host/libs/vm_manager/libvirt_manager.cpp
@@ -347,7 +347,7 @@
 LibvirtManager::LibvirtManager(vsoc::CuttlefishConfig* config)
   : VmManager(config) {}
 
-bool LibvirtManager::Start() const {
+bool LibvirtManager::Start() {
   std::string start_command = GetLibvirtCommand();
   start_command += " create /dev/fd/0";
 
@@ -374,7 +374,7 @@
   return true;
 }
 
-bool LibvirtManager::Stop() const {
+bool LibvirtManager::Stop() {
   auto stop_command = GetLibvirtCommand();
   stop_command += " destroy " + config_->instance_name();
   return std::system(stop_command.c_str()) == 0;
diff --git a/host/libs/vm_manager/libvirt_manager.h b/host/libs/vm_manager/libvirt_manager.h
index d0d157e..d582827 100644
--- a/host/libs/vm_manager/libvirt_manager.h
+++ b/host/libs/vm_manager/libvirt_manager.h
@@ -27,8 +27,8 @@
   LibvirtManager(vsoc::CuttlefishConfig* config);
   virtual ~LibvirtManager() = default;
 
-  bool Start() const override;
-  bool Stop() const override;
+  bool Start() override;
+  bool Stop() override;
 
   bool EnsureInstanceDirExists() const override;
   bool CleanPriorFiles() const override;
diff --git a/host/libs/vm_manager/qemu_manager.cpp b/host/libs/vm_manager/qemu_manager.cpp
index 8eeb5a6..257e013 100644
--- a/host/libs/vm_manager/qemu_manager.cpp
+++ b/host/libs/vm_manager/qemu_manager.cpp
@@ -33,6 +33,7 @@
 #include <gflags/gflags.h>
 #include <glog/logging.h>
 
+#include "common/libs/fs/shared_select.h"
 #include "common/libs/utils/files.h"
 #include "common/libs/utils/subprocess.h"
 #include "common/libs/utils/users.h"
@@ -55,15 +56,14 @@
   LOG(INFO) << key << "=" << value;
 }
 
-int BuildAndRunQemuCmd(vsoc::CuttlefishConfig* config) {
+pid_t BuildAndRunQemuCmd(vsoc::CuttlefishConfig* config) {
   // Set the config values in the environment
   LogAndSetEnv("qemu_binary", FLAGS_qemu_binary);
   LogAndSetEnv("instance_name", config->instance_name());
   LogAndSetEnv("memory_mb", std::to_string(config->memory_mb()));
   LogAndSetEnv("cpus", std::to_string(config->cpus()));
   LogAndSetEnv("uuid", config->uuid());
-  LogAndSetEnv("monitor_path",
-                      config->PerInstancePath("qemu_monitor.sock"));
+  LogAndSetEnv("monitor_path", GetMonitorPath(config));
   LogAndSetEnv("kernel_image_path", config->kernel_image_path());
   LogAndSetEnv("gdb_flag", config->gdb_flag());
   LogAndSetEnv("ramdisk_image_path", config->ramdisk_image_path());
@@ -84,7 +84,7 @@
   LogAndSetEnv("ivshmem_vector_count",
                       std::to_string(config->ivshmem_vector_count()));
   LogAndSetEnv("usb_v1_socket_name", config->usb_v1_socket_name());
-  return cvd::execute({vsoc::DefaultHostArtifactsPath("bin/cf_qemu.sh")});
+  return cvd::subprocess({vsoc::DefaultHostArtifactsPath("bin/cf_qemu.sh")});
 }
 
 }  // namespace
@@ -94,55 +94,51 @@
 QemuManager::QemuManager(vsoc::CuttlefishConfig* config)
   : VmManager(config) {}
 
-bool QemuManager::Start() const {
-  // Create a thread that will make the launcher abort if the qemu process
-  // crashes, this avoids having the launcher waiting forever for
-  // VIRTUAL_DEVICE_BOOT_COMPLETED in this cases.
-  auto config = this->config_;
-  std::thread waiting_thread([config]() {
-    int status = BuildAndRunQemuCmd(config);
-    if (status != 0) {
-      LOG(FATAL) << "Qemu process exited prematurely";
-    } else {
-      LOG(INFO) << "Qemu process exited normally";
-    }
-  });
-  waiting_thread.detach();
-  return true;
+bool QemuManager::Start() {
+  if (monitor_conn_->IsOpen()) {
+    LOG(ERROR) << "Already started, should call Stop() first";
+    return false;
+  }
+  auto monitor_path = GetMonitorPath(config_);
+  auto monitor_sock = cvd::SharedFD::SocketLocalServer(
+      monitor_path.c_str(), false, SOCK_STREAM, 0666);
+
+  BuildAndRunQemuCmd(config_);
+
+  cvd::SharedFDSet fdset;
+  fdset.Set(monitor_sock);
+  struct timeval timeout {5, 0}; // Wait at most 5 seconds for qemu to connect
+  int select_result = cvd::Select(&fdset, 0, 0, &timeout);
+  if (select_result < 0) {
+    LOG(ERROR) << "Error when calling seletct: " << strerror(errno);
+    return false;
+  }
+  if (select_result == 0) {
+    LOG(ERROR) << "Timed out waiting for qemu to connect to monitor";
+    return false;
+  }
+  monitor_conn_ = cvd::SharedFD::Accept(*monitor_sock);
+  monitor_conn_->Fcntl(F_SETFD, FD_CLOEXEC);
+  return monitor_conn_->IsOpen();
 }
-bool QemuManager::Stop() const {
-  int errno_;
-  int fd = socket(AF_UNIX, SOCK_STREAM, 0);
-  if (fd == -1) {
-    errno_ = errno;
-    LOG(ERROR) << "Error creating socket: " << strerror(errno_);
+bool QemuManager::Stop() {
+  if (!monitor_conn_->IsOpen()) {
+    LOG(ERROR) << "The connection to qemu is closed, is it still running?";
     return false;
   }
-
-  struct sockaddr_un addr;
-  memset(&addr, 0, sizeof(addr));
-  addr.sun_family = AF_UNIX;
-  std::string monitor_path = GetMonitorPath(config_);
-  strncpy(addr.sun_path, monitor_path.c_str(), sizeof(addr.sun_path) - 1);
-
-  if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
-    errno_ = errno;
-    LOG(ERROR) << "Error connecting to qemu monitor: " << strerror(errno_);
-    return false;
-  }
-
   char msg[] = "{\"execute\":\"qmp_capabilities\"}{\"execute\":\"quit\"}";
   ssize_t len = sizeof(msg) - 1;
   while (len > 0) {
-    int tmp = TEMP_FAILURE_RETRY(write(fd, msg, len));
+    int tmp = monitor_conn_->Write(msg, len);
     if (tmp < 0) {
-      LOG(ERROR) << "Error writing to socket";
+      LOG(ERROR) << "Error writing to socket: " << monitor_conn_->StrError();
+      return false;
     }
     len -= tmp;
   }
   // Log the reply
   char buff[1000];
-  while ((len = TEMP_FAILURE_RETRY(read(fd, buff, sizeof(buff) - 1))) > 0) {
+  while ((len = monitor_conn_->Read(buff, sizeof(buff) - 1)) > 0) {
     buff[len] = '\0';
     LOG(INFO) << "From qemu monitor: " << buff;
   }
diff --git a/host/libs/vm_manager/qemu_manager.h b/host/libs/vm_manager/qemu_manager.h
index 20fe26a..7c053e7 100644
--- a/host/libs/vm_manager/qemu_manager.h
+++ b/host/libs/vm_manager/qemu_manager.h
@@ -17,6 +17,8 @@
 
 #include "host/libs/vm_manager/vm_manager.h"
 
+#include "common/libs/fs/shared_fd.h"
+
 namespace vm_manager {
 
 // Starts a guest VM using the qemu command directly. It requires the host
@@ -27,14 +29,16 @@
   QemuManager(vsoc::CuttlefishConfig* config);
   virtual ~QemuManager() = default;
 
-  bool Start() const override;
-  bool Stop() const override;
+  bool Start() override;
+  bool Stop() override;
 
   bool EnsureInstanceDirExists() const override;
   bool CleanPriorFiles() const override;
 
   bool ValidateHostConfiguration(
       std::vector<std::string>* config_commands) const override;
+ private:
+  cvd::SharedFD monitor_conn_;
 };
 
 }  // namespace vm_manager
diff --git a/host/libs/vm_manager/vm_manager.h b/host/libs/vm_manager/vm_manager.h
index 7b3490a..d4f7036 100644
--- a/host/libs/vm_manager/vm_manager.h
+++ b/host/libs/vm_manager/vm_manager.h
@@ -39,8 +39,8 @@
 
   virtual ~VmManager() = default;
 
-  virtual bool Start() const = 0;
-  virtual bool Stop() const = 0;
+  virtual bool Start() = 0;
+  virtual bool Stop() = 0;
 
   virtual bool EnsureInstanceDirExists() const = 0;
   virtual bool CleanPriorFiles() const = 0;