Fix debuggerd issues.

- Fix a problem where a tid exits before the attach completes, and it
  causes debuggerd to self terminate.
- Fix a problem where sibling tid dumps do not properly wait for the tid
  to get signalled.

Bug: 17800180
Bug: 12567315

(cherry picked from commit 84ddb34a3af77dbe490aaa07b738bbfd7109d5ba)

Change-Id: I45e33865614d4c96f4a89cf117398666b556d500
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index 9a30fe3..2baf9de 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -28,8 +28,8 @@
 #include <backtrace/Backtrace.h>
 #include <log/log.h>
 
-const int sleep_time_usec = 50000;         // 0.05 seconds
-const int max_total_sleep_usec = 10000000; // 10 seconds
+const int SLEEP_TIME_USEC = 50000;         // 0.05 seconds
+const int MAX_TOTAL_SLEEP_USEC = 10000000; // 10 seconds
 
 static int write_to_am(int fd, const char* buf, int len) {
   int to_write = len;
@@ -91,48 +91,44 @@
   }
 }
 
-int wait_for_signal(pid_t tid, int* total_sleep_time_usec) {
+int wait_for_sigstop(pid_t tid, int* total_sleep_time_usec, bool* detach_failed) {
+  bool allow_dead_tid = false;
   for (;;) {
     int status;
-    pid_t n = waitpid(tid, &status, __WALL | WNOHANG);
-    if (n < 0) {
-      if (errno == EAGAIN)
-        continue;
-      ALOGE("waitpid failed: %s\n", strerror(errno));
-      return -1;
-    } else if (n > 0) {
-      ALOGV("waitpid: n=%d status=%08x\n", n, status);
+    pid_t n = TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL | WNOHANG));
+    if (n == -1) {
+      ALOGE("waitpid failed: tid %d, %s", tid, strerror(errno));
+      break;
+    } else if (n == tid) {
       if (WIFSTOPPED(status)) {
         return WSTOPSIG(status);
       } else {
         ALOGE("unexpected waitpid response: n=%d, status=%08x\n", n, status);
-        return -1;
+        // This is the only circumstance under which we can allow a detach
+        // to fail with ESRCH, which indicates the tid has exited.
+        allow_dead_tid = true;
+        break;
       }
     }
 
-    if (*total_sleep_time_usec > max_total_sleep_usec) {
-      ALOGE("timed out waiting for tid=%d to die\n", tid);
-      return -1;
-    }
-
-    // not ready yet
-    ALOGV("not ready yet\n");
-    usleep(sleep_time_usec);
-    *total_sleep_time_usec += sleep_time_usec;
-  }
-}
-
-void wait_for_stop(pid_t tid, int* total_sleep_time_usec) {
-  siginfo_t si;
-  while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) < 0 && errno == ESRCH) {
-    if (*total_sleep_time_usec > max_total_sleep_usec) {
-      ALOGE("timed out waiting for tid=%d to stop\n", tid);
+    if (*total_sleep_time_usec > MAX_TOTAL_SLEEP_USEC) {
+      ALOGE("timed out waiting for stop signal: tid=%d", tid);
       break;
     }
 
-    usleep(sleep_time_usec);
-    *total_sleep_time_usec += sleep_time_usec;
+    usleep(SLEEP_TIME_USEC);
+    *total_sleep_time_usec += SLEEP_TIME_USEC;
   }
+
+  if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
+    if (allow_dead_tid && errno == ESRCH) {
+      ALOGE("tid exited before attach completed: tid %d", tid);
+    } else {
+      *detach_failed = true;
+      ALOGE("detach failed: tid %d, %s", tid, strerror(errno));
+    }
+  }
+  return -1;
 }
 
 #if defined (__mips__)