Adds the process monitor to the launcher

The process monitor is a server the launcher runs after it has
launched the device. It listens on a unix socket for actions to
perform. So far the only action implemented is to stop the device

Bug: 111321286
Bug: 111453282
Bug: 111553274
Test: local
Change-Id: I59cccf703742541cde59fc4e094b6d02ba6278f8
diff --git a/host/commands/launch/launcher_defs.h b/host/commands/launch/launcher_defs.h
index 1787a6c..a6d3372 100644
--- a/host/commands/launch/launcher_defs.h
+++ b/host/commands/launch/launcher_defs.h
@@ -31,6 +31,19 @@
   kPipeIOError = 10,
   kVirtualDeviceBootFailed = 11,
   kProcessGroupError = 12,
+  kMonitorCreationFailed = 13,
+  kServerError = 14,
 };
 
-}
+// Actions supported by the launcher server
+enum class LauncherAction : char {
+  kStop = 'X',
+};
+
+// Responses from the launcher server
+enum class LauncherResponse : char {
+  kSuccess = 'S',
+  kError = 'E',
+  kUnknownAction = 'U',
+};
+}  // namespace cvd
diff --git a/host/commands/launch/main.cc b/host/commands/launch/main.cc
index f91d62e..ca3888e 100644
--- a/host/commands/launch/main.cc
+++ b/host/commands/launch/main.cc
@@ -567,6 +567,8 @@
   config->set_console_path(config->PerInstancePath("console"));
   config->set_logcat_path(config->PerInstancePath("logcat"));
   config->set_launcher_log_path(config->PerInstancePath("launcher.log"));
+  config->set_launcher_monitor_socket_path(
+      config->PerInstancePath("launcher_monitor.sock"));
 
   config->set_mobile_bridge_name(FLAGS_mobile_interface);
   config->set_mobile_tap_name(FLAGS_mobile_tap_name);
@@ -697,6 +699,64 @@
     return write_end;
   }
 }
+
+// Stops the device. If this function is successful it returns on a child of the
+// launcher (after it killed the laucher) and it should exit immediately
+bool StopCvd() {
+  auto vm_manager = vm_manager::VmManager::Get();
+  vm_manager->Stop();
+  auto pgid = getpgid(0);
+  auto child_pid = fork();
+  if (child_pid > 0) {
+    // The parent just waits for the child to kill it.
+    int wstatus;
+    waitpid(child_pid, &wstatus, 0);
+    LOG(ERROR) << "The forked child exited before delivering signal with "
+                  "status: "
+               << wstatus;
+    // If waitpid returns it means the child exited before the signal was
+    // delivered, notify the client of the error and continue serving
+    return false;
+  } else if (child_pid == 0) {
+    // The child makes sure it is in a different process group before
+    // killing everyone on its parent's
+    // This call never fails (see SETPGID(2))
+    setpgid(0, 0);
+    killpg(pgid, SIGKILL);
+    return true;
+  } else {
+    // The fork failed, the system is in pretty bad shape
+    LOG(FATAL) << "Unable to fork before on Stop: " << strerror(errno);
+    return false;
+  }
+}
+
+void ServerLoop(cvd::SharedFD server) {
+  while (true) {
+    // TODO: use select to handle simultaneous connections.
+    auto client = cvd::SharedFD::Accept(*server);
+    cvd::LauncherAction action;
+    while (client->IsOpen() && client->Read(&action, sizeof(char)) > 0) {
+      switch (action) {
+        case cvd::LauncherAction::kStop:
+          if (StopCvd()) {
+            auto response = cvd::LauncherResponse::kSuccess;
+            client->Write(&response, sizeof(response));
+            std::exit(0);
+          } else {
+            auto response = cvd::LauncherResponse::kError;
+            client->Write(&response, sizeof(response));
+          }
+          break;
+        default:
+          LOG(ERROR) << "Unrecognized launcher action: "
+                     << static_cast<char>(action);
+          auto response = cvd::LauncherResponse::kError;
+          client->Write(&response, sizeof(response));
+      }
+    }
+  }
+}
 }  // namespace
 
 int main(int argc, char** argv) {
@@ -773,6 +833,13 @@
                         config->PerInstancePath("kernel.log"),
                         FLAGS_deprecated_boot_completed);
 
+  auto launcher_monitor_path = config->launcher_monitor_socket_path();
+  auto launcher_monitor_socket = cvd::SharedFD::SocketLocalServer(
+      launcher_monitor_path.c_str(), false, SOCK_STREAM, 0666);
+  if (!launcher_monitor_socket->IsOpen()) {
+    LOG(ERROR) << "Error when opening launcher server: " << launcher_monitor_socket->StrError();
+    return cvd::LauncherExitCodes::kMonitorCreationFailed;
+  }
   if (FLAGS_daemon) {
     // This code will move to its own process eventually so the signal handling
     // is done here to keep everything that needs to move close together.
@@ -832,5 +899,7 @@
   LaunchVNCServerIfEnabled();
   LaunchAdbConnectorIfEnabled();
 
-  pause();
+  ServerLoop(launcher_monitor_socket); // Should not return
+  LOG(ERROR) << "The server loop returned, it should never happen!!";
+  return cvd::LauncherExitCodes::kServerError;
 }
diff --git a/host/libs/config/cuttlefish_config.cpp b/host/libs/config/cuttlefish_config.cpp
index 96c3228..2f2fffa 100644
--- a/host/libs/config/cuttlefish_config.cpp
+++ b/host/libs/config/cuttlefish_config.cpp
@@ -92,6 +92,7 @@
 const char* kConsolePath = "console_path";
 const char* kLogcatPath = "logcat_path";
 const char* kLauncherLogPath = "launcher_log_path";
+const char* kLauncherMonitorPath = "launcher_monitor_socket";
 const char* kDtbPath = "dtb_path";
 
 const char* kMempath = "mempath";
@@ -310,6 +311,14 @@
   SetPath(kLogcatPath, logcat_path);
 }
 
+std::string CuttlefishConfig::launcher_monitor_socket_path() const {
+  return (*dictionary_)[kLauncherMonitorPath].asString();
+}
+void CuttlefishConfig::set_launcher_monitor_socket_path(
+    const std::string& launhcer_monitor_path) {
+  (*dictionary_)[kLauncherMonitorPath] = launhcer_monitor_path;
+}
+
 std::string CuttlefishConfig::launcher_log_path() const {
   return (*dictionary_)[kLauncherLogPath].asString();
 }
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index f965d10..456e2ae 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -134,6 +134,10 @@
   std::string launcher_log_path() const;
   void set_launcher_log_path(const std::string& launcher_log_path);
 
+  std::string launcher_monitor_socket_path() const;
+  void set_launcher_monitor_socket_path(
+      const std::string& launhcer_monitor_path);
+
   std::string mobile_bridge_name() const;
   void set_mobile_bridge_name(const std::string& mobile_bridge_name);