Make subprocesses die when their parents do

This could also be a configurable option in cvd::Subprocess, but it
seems to work when always enabled.

The PR_SET_PDEATHSIG setting is unset on the forked child, which happens
to do the right thing already with run_cvd daemonizing. Because that does
not use cvd::Subprocess, the setting doesn't apply to it (though it is
given to run_cvd originally by launch_cvd).

Bug: 145956571
Test: ctrl-c on launch_cvd
Change-Id: I387db1acabe90e1f41abb159b1c07e891ea46a87
diff --git a/common/libs/utils/subprocess.cpp b/common/libs/utils/subprocess.cpp
index e83b487..9c383d3 100644
--- a/common/libs/utils/subprocess.cpp
+++ b/common/libs/utils/subprocess.cpp
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <stdlib.h>
+#include <sys/prctl.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
@@ -69,7 +70,8 @@
     const char* const* command, const char* const* envp,
     const std::map<cvd::Subprocess::StdIOChannel, int>& redirects,
     const std::map<cvd::SharedFD, int>& inherited_fds, bool with_control_socket,
-    cvd::SubprocessStopper stopper, bool in_group = false, bool verbose = false) {
+    cvd::SubprocessStopper stopper, bool in_group = false, bool verbose = false,
+    bool exit_with_parent = true) {
   // The parent socket will get closed on the child on the call to exec, the
   // child socket will be closed on the parent when this function returns and no
   // references to the fd are left
@@ -91,6 +93,10 @@
 
   pid_t pid = fork();
   if (!pid) {
+    if (exit_with_parent) {
+      prctl(PR_SET_PDEATHSIG, SIGHUP); // Die when parent dies
+    }
+
     do_redirects(redirects);
     if (in_group) {
       // This call should never fail (see SETPGID(2))
@@ -293,17 +299,21 @@
   verbose_ = verbose;
 }
 
+void Command::SetExitWithParent(bool exit_with_parent) {
+  exit_with_parent_ = exit_with_parent;
+}
+
 Subprocess Command::StartHelper(bool with_control_socket, bool in_group) const {
   auto cmd = ToCharPointers(command_);
   if (use_parent_env_) {
     return subprocess_impl(cmd.data(), nullptr, redirects_, inherited_fds_,
                            with_control_socket, subprocess_stopper_, in_group,
-                           verbose_);
+                           verbose_, exit_with_parent_);
   } else {
     auto envp = ToCharPointers(env_);
     return subprocess_impl(cmd.data(), envp.data(), redirects_, inherited_fds_,
                            with_control_socket, subprocess_stopper_, in_group,
-                           verbose_);
+                           verbose_, exit_with_parent_);
   }
 }
 
diff --git a/common/libs/utils/subprocess.h b/common/libs/utils/subprocess.h
index 44976f9..df3d9f6 100644
--- a/common/libs/utils/subprocess.h
+++ b/common/libs/utils/subprocess.h
@@ -118,8 +118,10 @@
   // optional subprocess stopper. When not provided, stopper defaults to sending
   // SIGKILL to the subprocess.
   Command(const std::string& executable,
-          SubprocessStopper stopper = KillSubprocess)
-      : subprocess_stopper_(stopper), verbose_(true) {
+          SubprocessStopper stopper = KillSubprocess,
+          bool exit_with_parent = true)
+      : subprocess_stopper_(stopper), verbose_(true),
+        exit_with_parent_(exit_with_parent) {
     command_.push_back(executable);
   }
   Command(Command&&) = default;
@@ -159,6 +161,7 @@
                      Subprocess::StdIOChannel parent_channel);
 
   void SetVerbose(bool verbose);
+  void SetExitWithParent(bool exit_with_parent);
 
   // Starts execution of the command. This method can be called multiple times,
   // effectively staring multiple (possibly concurrent) instances. If
@@ -185,6 +188,7 @@
   std::vector<std::string> env_{};
   SubprocessStopper subprocess_stopper_;
   bool verbose_;
+  bool exit_with_parent_;
 };
 
 /*