debuggerd: fork the signal sender once.

Bug: http://b/27427439
Change-Id: I6294ff68a150bc9950a300264c31d2141307ac66
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index eabbb9a..b6c2f8a 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -15,21 +15,20 @@
  */
 
 #include <dirent.h>
+#include <elf.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <pthread.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
-#include <sys/types.h>
-#include <time.h>
-
-#include <elf.h>
 #include <sys/poll.h>
 #include <sys/prctl.h>
 #include <sys/ptrace.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 #include <sys/wait.h>
+#include <time.h>
 
 #include <set>
 
@@ -48,6 +47,7 @@
 
 #include "backtrace.h"
 #include "getevent.h"
+#include "signal_sender.h"
 #include "tombstone.h"
 #include "utility.h"
 
@@ -422,7 +422,7 @@
         // this we get a lot of "ptrace detach failed:
         // No such process".
         *crash_signal = signal;
-        kill(request.pid, SIGSTOP);
+        send_signal(request.pid, 0, SIGSTOP);
         engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings, signal,
                           request.original_si_code, request.abort_msg_address);
         break;
@@ -451,60 +451,6 @@
   return true;
 }
 
-// Fork a process that listens for signals to send, or 0, to exit.
-static bool fork_signal_sender(int* out_fd, pid_t* sender_pid, pid_t target_pid) {
-  int sfd[2];
-  if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sfd) != 0) {
-    ALOGE("debuggerd: failed to create socketpair for signal sender: %s", strerror(errno));
-    return false;
-  }
-
-  pid_t fork_pid = fork();
-  if (fork_pid == -1) {
-    ALOGE("debuggerd: failed to initialize signal sender: fork failed: %s", strerror(errno));
-    return false;
-  } else if (fork_pid == 0) {
-    close(sfd[1]);
-
-    while (true) {
-      int signal;
-      int rc = TEMP_FAILURE_RETRY(read(sfd[0], &signal, sizeof(signal)));
-      if (rc < 0) {
-        ALOGE("debuggerd: signal sender failed to read from socket");
-        kill(target_pid, SIGKILL);
-        exit(1);
-      } else if (rc != sizeof(signal)) {
-        ALOGE("debuggerd: signal sender read unexpected number of bytes: %d", rc);
-        kill(target_pid, SIGKILL);
-        exit(1);
-      }
-
-      // Report success after sending a signal, or before exiting.
-      int err = 0;
-      if (signal != 0) {
-        if (kill(target_pid, signal) != 0) {
-          err = errno;
-        }
-      }
-
-      if (TEMP_FAILURE_RETRY(write(sfd[0], &err, sizeof(err))) < 0) {
-        ALOGE("debuggerd: signal sender failed to write: %s", strerror(errno));
-        kill(target_pid, SIGKILL);
-        exit(1);
-      }
-
-      if (signal == 0) {
-        exit(0);
-      }
-    }
-  } else {
-    close(sfd[0]);
-    *out_fd = sfd[1];
-    *sender_pid = fork_pid;
-    return true;
-  }
-}
-
 static void handle_request(int fd) {
   ALOGV("handle_request(%d)\n", fd);
 
@@ -585,15 +531,6 @@
   // Don't attach to the sibling threads if we want to attach gdb.
   // Supposedly, it makes the process less reliable.
   bool attach_gdb = should_attach_gdb(&request);
-  int signal_fd = -1;
-  pid_t signal_pid = 0;
-
-  // Fork a process that stays root, and listens on a pipe to pause and resume the target.
-  if (!fork_signal_sender(&signal_fd, &signal_pid, request.pid)) {
-    ALOGE("debuggerd: failed to fork signal sender");
-    exit(1);
-  }
-
   if (attach_gdb) {
     // Open all of the input devices we need to listen for VOLUMEDOWN before dropping privileges.
     if (init_getevent() != 0) {
@@ -603,21 +540,6 @@
 
   }
 
-  auto send_signal = [=](int signal) {
-    int error;
-    if (TEMP_FAILURE_RETRY(write(signal_fd, &signal, sizeof(signal))) < 0) {
-      ALOGE("debuggerd: failed to notify signal process: %s", strerror(errno));
-      return false;
-    } else if (TEMP_FAILURE_RETRY(read(signal_fd, &error, sizeof(error))) < 0) {
-      ALOGE("debuggerd: failed to read response from signal process: %s", strerror(errno));
-      return false;
-    } else if (error != 0) {
-      errno = error;
-      return false;
-    }
-    return true;
-  };
-
   std::set<pid_t> siblings;
   if (!attach_gdb) {
     ptrace_siblings(request.pid, request.tid, siblings);
@@ -646,7 +568,7 @@
 
   if (attach_gdb) {
     // Tell the signal process to send SIGSTOP to the target.
-    if (!send_signal(SIGSTOP)) {
+    if (!send_signal(request.pid, 0, SIGSTOP)) {
       ALOGE("debuggerd: failed to stop process for gdb attach: %s", strerror(errno));
       attach_gdb = false;
     }
@@ -662,7 +584,7 @@
 
   // Send the signal back to the process if it crashed and we're not waiting for gdb.
   if (!attach_gdb && request.action == DEBUGGER_ACTION_CRASH) {
-    if (!send_signal(crash_signal)) {
+    if (!send_signal(request.pid, request.tid, crash_signal)) {
       ALOGE("debuggerd: failed to kill process %d: %s", request.pid, strerror(errno));
     }
   }
@@ -672,18 +594,13 @@
     wait_for_user_action(request);
 
     // Tell the signal process to send SIGCONT to the target.
-    if (!send_signal(SIGCONT)) {
+    if (!send_signal(request.pid, 0, SIGCONT)) {
       ALOGE("debuggerd: failed to resume process %d: %s", request.pid, strerror(errno));
     }
 
     uninit_getevent();
   }
 
-  if (!send_signal(0)) {
-    ALOGE("debuggerd: failed to notify signal sender to finish");
-    kill(signal_pid, SIGKILL);
-  }
-  waitpid(signal_pid, nullptr, 0);
   exit(!succeeded);
 }
 
@@ -714,6 +631,12 @@
                               SOCK_STREAM | SOCK_CLOEXEC);
   if (s == -1) return 1;
 
+  // Fork a process that stays root, and listens on a pipe to pause and resume the target.
+  if (!start_signal_sender()) {
+    ALOGE("debuggerd: failed to fork signal sender");
+    return 1;
+  }
+
   ALOGI("debuggerd: starting\n");
 
   for (;;) {