Merge "move tinyutils into its own namespace" into jb-mr2-dev
diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.c
index efc49eb..763b448 100644
--- a/adb/adb_auth_client.c
+++ b/adb/adb_auth_client.c
@@ -161,7 +161,7 @@
 
 static void usb_disconnected(void* unused, atransport* t)
 {
-    D("USB disconnect");
+    D("USB disconnect\n");
     remove_transport_disconnect(usb_transport, &usb_disconnect);
     usb_transport = NULL;
     needs_retry = false;
@@ -175,7 +175,7 @@
     if (events & FDE_READ) {
         ret = unix_read(fd, response, sizeof(response));
         if (ret < 0) {
-            D("Framework disconnect");
+            D("Framework disconnect\n");
             if (usb_transport)
                 fdevent_remove(&usb_transport->auth_fde);
             framework_fd = -1;
@@ -192,8 +192,10 @@
     char msg[MAX_PAYLOAD];
     int ret;
 
-    usb_transport = t;
-    add_transport_disconnect(t, &usb_disconnect);
+    if (!usb_transport) {
+        usb_transport = t;
+        add_transport_disconnect(t, &usb_disconnect);
+    }
 
     if (framework_fd < 0) {
         D("Client not connected\n");
diff --git a/debuggerd/backtrace.c b/debuggerd/backtrace.c
index ba76e7d..08f8836 100644
--- a/debuggerd/backtrace.c
+++ b/debuggerd/backtrace.c
@@ -112,10 +112,11 @@
     }
 }
 
-void dump_backtrace(int fd, pid_t pid, pid_t tid, bool* detach_failed,
+void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
         int* total_sleep_time_usec) {
     log_t log;
     log.tfd = fd;
+    log.amfd = amfd;
     log.quiet = true;
 
     ptrace_context_t* context = load_ptrace_context(tid);
diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h
index ec7d20f..c5c786a 100644
--- a/debuggerd/backtrace.h
+++ b/debuggerd/backtrace.h
@@ -25,7 +25,7 @@
 
 /* Dumps a backtrace using a format similar to what Dalvik uses so that the result
  * can be intermixed in a bug report. */
-void dump_backtrace(int fd, pid_t pid, pid_t tid, bool* detach_failed,
+void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
         int* total_sleep_time_usec);
 
 #endif // _DEBUGGERD_BACKTRACE_H
diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c
index 65ff0f6..2736f30 100644
--- a/debuggerd/debuggerd.c
+++ b/debuggerd/debuggerd.c
@@ -314,7 +314,8 @@
                                     &total_sleep_time_usec);
                         } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
                             XLOG("stopped -- dumping to fd\n");
-                            dump_backtrace(fd, request.pid, request.tid, &detach_failed,
+                            dump_backtrace(fd, -1,
+                                    request.pid, request.tid, &detach_failed,
                                     &total_sleep_time_usec);
                         } else {
                             XLOG("stopped -- continuing\n");
diff --git a/debuggerd/tombstone.c b/debuggerd/tombstone.c
index e8b3e24..7c9cb6c 100644
--- a/debuggerd/tombstone.c
+++ b/debuggerd/tombstone.c
@@ -35,6 +35,9 @@
 #include <corkscrew/demangle.h>
 #include <corkscrew/backtrace.h>
 
+#include <sys/socket.h>
+#include <linux/un.h>
+
 #include <selinux/android.h>
 
 #include "machine.h"
@@ -47,6 +50,9 @@
 #define MAX_TOMBSTONES  10
 #define TOMBSTONE_DIR   "/data/tombstones"
 
+/* Must match the path defined in NativeCrashListener.java */
+#define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
+
 #define typecheck(x,y) {    \
     typeof(x) __dummy1;     \
     typeof(y) __dummy2;     \
@@ -627,6 +633,18 @@
     property_get("ro.debuggable", value, "0");
     bool want_logs = (value[0] == '1');
 
+    if (log->amfd >= 0) {
+        /*
+         * Activity Manager protocol: binary 32-bit network-byte-order ints for the
+         * pid and signal number, followed by the raw text of the dump, culminating
+         * in a zero byte that marks end-of-data.
+         */
+        uint32_t datum = htonl(pid);
+        TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
+        datum = htonl(signal);
+        TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
+    }
+
     _LOG(log, false,
             "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
     dump_build_info(log);
@@ -653,6 +671,16 @@
     if (want_logs) {
         dump_logs(log, pid, false);
     }
+
+    /* send EOD to the Activity Manager, then wait for its ack to avoid racing ahead
+     * and killing the target out from under it */
+    if (log->amfd >= 0) {
+        uint8_t eodMarker = 0;
+        TEMP_FAILURE_RETRY( write(log->amfd, &eodMarker, 1) );
+        /* 3 sec timeout reading the ack; we're fine if that happens */
+        TEMP_FAILURE_RETRY( read(log->amfd, &eodMarker, 1) );
+    }
+
     return detach_failed;
 }
 
@@ -712,6 +740,35 @@
     return strdup(path);
 }
 
+static int activity_manager_connect() {
+    int amfd = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (amfd >= 0) {
+        struct sockaddr_un address;
+        int err;
+
+        memset(&address, 0, sizeof(address));
+        address.sun_family = AF_UNIX;
+        strncpy(address.sun_path, NCRASH_SOCKET_PATH, sizeof(address.sun_path));
+        err = TEMP_FAILURE_RETRY( connect(amfd, (struct sockaddr*) &address, sizeof(address)) );
+        if (!err) {
+            struct timeval tv;
+            memset(&tv, 0, sizeof(tv));
+            tv.tv_sec = 1;  // tight leash
+            err = setsockopt(amfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+            if (!err) {
+                tv.tv_sec = 3;  // 3 seconds on handshake read
+                err = setsockopt(amfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+            }
+        }
+        if (err) {
+            close(amfd);
+            amfd = -1;
+        }
+    }
+
+    return amfd;
+}
+
 char* engrave_tombstone(pid_t pid, pid_t tid, int signal,
         bool dump_sibling_threads, bool quiet, bool* detach_failed,
         int* total_sleep_time_usec) {
@@ -732,10 +789,12 @@
 
     log_t log;
     log.tfd = fd;
+    log.amfd = activity_manager_connect();
     log.quiet = quiet;
     *detach_failed = dump_crash(&log, pid, tid, signal, dump_sibling_threads,
             total_sleep_time_usec);
 
+    close(log.amfd);
     close(fd);
     return path;
 }
diff --git a/debuggerd/utility.c b/debuggerd/utility.c
index aabaf74..de9200a 100644
--- a/debuggerd/utility.c
+++ b/debuggerd/utility.c
@@ -25,27 +25,63 @@
 #include <cutils/logd.h>
 #include <sys/ptrace.h>
 #include <sys/wait.h>
+#include <arpa/inet.h>
+#include <assert.h>
 
 #include "utility.h"
 
 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;
+    while (to_write > 0) {
+        int written = TEMP_FAILURE_RETRY( write(fd, buf + len - to_write, to_write) );
+        if (written < 0) {
+            /* hard failure */
+            return -1;
+        }
+        to_write -= written;
+    }
+    return len;
+}
+
 void _LOG(log_t* log, bool in_tombstone_only, const char *fmt, ...) {
     char buf[512];
+    bool want_tfd_write;
+    bool want_log_write;
+    bool want_amfd_write;
+    int len;
 
     va_list ap;
     va_start(ap, fmt);
 
-    if (log && log->tfd >= 0) {
-        int len;
+    // where is the information going to go?
+    want_tfd_write = log && log->tfd >= 0;      // write to the tombstone fd?
+    want_log_write = !in_tombstone_only && (!log || !log->quiet);
+    want_amfd_write = log && log->amfd >= 0;    // only used when want_log_write is true
+
+    // if we're going to need the literal string, generate it once here
+    if (want_tfd_write || want_amfd_write) {
         vsnprintf(buf, sizeof(buf), fmt, ap);
         len = strlen(buf);
+    }
+
+    if (want_tfd_write) {
         write(log->tfd, buf, len);
     }
 
-    if (!in_tombstone_only && (!log || !log->quiet)) {
+    if (want_log_write) {
+        // whatever goes to logcat also goes to the Activity Manager
         __android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap);
+        if (want_amfd_write && len > 0) {
+            int written = write_to_am(log->amfd, buf, len);
+            if (written <= 0) {
+                // timeout or other failure on write; stop informing the activity manager
+                LOG("AM write failure, giving up\n");
+                log->amfd = -1;
+            }
+        }
     }
     va_end(ap);
 }
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 136f46d..8d31e5e 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -24,7 +24,9 @@
 typedef struct {
     /* tombstone file descriptor */
     int tfd;
-    /* if true, does not log anything to the Android logcat */
+    /* Activity Manager socket file descriptor */
+    int amfd;
+    /* if true, does not log anything to the Android logcat or Activity Manager */
     bool quiet;
 } log_t;